]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #2921 from keszybz/do-not-report-masked-units-as-changed
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 3 May 2016 18:08:39 +0000 (14:08 -0400)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 3 May 2016 18:08:39 +0000 (14:08 -0400)
361 files changed:
.gitignore
.vimrc
CODING_STYLE
Makefile-man.am
Makefile.am
NEWS
README
TODO
catalog/systemd.be.catalog
catalog/systemd.be@latin.catalog
catalog/systemd.catalog
catalog/systemd.da.catalog
catalog/systemd.fr.catalog
catalog/systemd.hr.catalog [new file with mode: 0644]
catalog/systemd.hu.catalog
catalog/systemd.it.catalog
catalog/systemd.ko.catalog
catalog/systemd.pl.catalog
catalog/systemd.pt_BR.catalog
catalog/systemd.ru.catalog
catalog/systemd.sr.catalog
catalog/systemd.zh_CN.catalog
catalog/systemd.zh_TW.catalog
coccinelle/strjoina.cocci [new file with mode: 0644]
configure.ac
hwdb/60-evdev.hwdb
hwdb/60-keyboard.hwdb
hwdb/70-mouse.hwdb
man/coredump.conf.xml
man/daemon.xml
man/journalctl.xml
man/journald.conf.xml
man/kernel-command-line.xml
man/loginctl.xml
man/logind.conf.xml
man/machinectl.xml
man/networkd.conf.xml [new file with mode: 0644]
man/nss-myhostname.xml
man/sd_event_source_set_priority.xml
man/sd_journal_add_match.xml
man/sd_journal_get_data.xml
man/sd_journal_open.xml
man/sd_uid_get_state.xml
man/sd_watchdog_enabled.xml
man/systemctl.xml
man/systemd-ask-password.xml
man/systemd-coredump.xml
man/systemd-journal-gatewayd.service.xml
man/systemd-nspawn.xml
man/systemd-resolved.service.xml
man/systemd-run.xml
man/systemd-sysctl.service.xml
man/systemd-system.conf.xml
man/systemd-tmpfiles.xml
man/systemd.automount.xml
man/systemd.exec.xml
man/systemd.mount.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.nspawn.xml
man/systemd.offline-updates.xml [new file with mode: 0644]
man/systemd.path.xml
man/systemd.resource-control.xml
man/systemd.service.xml
man/systemd.slice.xml
man/systemd.socket.xml
man/systemd.special.xml
man/systemd.swap.xml
man/systemd.target.xml
man/systemd.timer.xml
man/systemd.unit.xml
man/tmpfiles.d.xml
po/LINGUAS
po/fr.po
po/hr.po [new file with mode: 0644]
po/pl.po
rules/60-persistent-storage.rules
rules/99-systemd.rules.in
shell-completion/zsh/_coredumpctl
shell-completion/zsh/_networkctl [new file with mode: 0644]
src/activate/activate.c
src/analyze/analyze-verify.c
src/analyze/analyze-verify.h
src/analyze/analyze.c
src/basic/architecture.c
src/basic/architecture.h
src/basic/c-rbtree.c [deleted file]
src/basic/c-rbtree.h [deleted file]
src/basic/copy.c
src/basic/copy.h
src/basic/def.h
src/basic/dirent-util.c
src/basic/dirent-util.h
src/basic/fd-util.c
src/basic/fd-util.h
src/basic/fdset.c
src/basic/fileio.c
src/basic/fileio.h
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/hashmap.c
src/basic/hostname-util.c
src/basic/locale-util.c
src/basic/missing.h
src/basic/mount-util.c
src/basic/nss-util.h
src/basic/parse-util.h
src/basic/path-util.c
src/basic/path-util.h
src/basic/process-util.c
src/basic/process-util.h
src/basic/rlimit-util.c
src/basic/rm-rf.h
src/basic/signal-util.c
src/basic/signal-util.h
src/basic/string-table.h
src/basic/strv.c
src/basic/strv.h
src/basic/terminal-util.c
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/cgls/cgls.c
src/cgtop/cgtop.c
src/core/automount.c
src/core/busname.c
src/core/cgroup.c
src/core/dbus-execute.c
src/core/dbus-kill.c
src/core/dbus-manager.c
src/core/dbus-socket.c
src/core/dbus-timer.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/device.c
src/core/failure-action.c
src/core/ima-setup.c
src/core/ima-setup.h
src/core/job.c
src/core/load-dropin.c
src/core/load-dropin.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/machine-id-setup.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/mount-setup.c
src/core/mount.c
src/core/org.freedesktop.systemd1.conf
src/core/path.c
src/core/scope.c
src/core/selinux-access.c
src/core/service.c
src/core/service.h
src/core/shutdown.c
src/core/slice.c
src/core/socket.c
src/core/socket.h
src/core/swap.c
src/core/system.conf
src/core/timer.c
src/core/transaction.c
src/core/triggers.systemd.in
src/core/unit-printf.c
src/core/unit.c
src/core/unit.h
src/core/user.conf
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/cryptsetup/cryptsetup.c
src/import/curl-util.c
src/import/import-common.c
src/import/pull-common.c
src/import/pull-job.h
src/journal-remote/journal-gatewayd.c
src/journal-remote/journal-remote-parse.c
src/journal-remote/journal-upload-journal.c
src/journal-remote/journal-upload.c
src/journal-remote/journal-upload.h
src/journal/compress.c
src/journal/fsprg.c
src/journal/journal-file.c
src/journal/journal-file.h
src/journal/journal-internal.h
src/journal/journal-send.c
src/journal/journal-verify.c
src/journal/journalctl.c
src/journal/journald-gperf.gperf
src/journal/journald-native.c
src/journal/journald-server.c
src/journal/journald.conf
src/journal/sd-journal.c
src/journal/test-compress-benchmark.c
src/journal/test-journal-flush.c
src/journal/test-journal-interleaving.c
src/journal/test-journal-stream.c
src/journal/test-journal-verify.c
src/journal/test-journal.c
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/dhcp-identifier.h
src/libsystemd-network/dhcp6-protocol.h
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd/libsystemd.sym
src/libsystemd/sd-bus/bus-common-errors.c
src/libsystemd/sd-bus/bus-common-errors.h
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-netlink/local-addresses.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/rtnl-message.c
src/libsystemd/sd-resolve/sd-resolve.c
src/libsystemd/sd-resolve/test-resolve.c
src/locale/language-fallback-map
src/locale/localed.c
src/login/.gitignore
src/login/loginctl.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-user-dbus.c
src/login/logind.c
src/login/logind.conf.in [moved from src/login/logind.conf with 95% similarity]
src/login/org.freedesktop.login1.policy.in
src/login/systemd-user.m4
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machine-dbus.h
src/machine/machine.c
src/machine/machine.h
src/machine/machinectl.c
src/machine/machined-dbus.c
src/machine/machined.c
src/machine/machined.h
src/machine/operation.c [new file with mode: 0644]
src/machine/operation.h [new file with mode: 0644]
src/network/.gitignore
src/network/networkd-address-pool.c
src/network/networkd-address.c
src/network/networkd-conf.c [new file with mode: 0644]
src/network/networkd-conf.h [new file with mode: 0644]
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-gperf.gperf [new file with mode: 0644]
src/network/networkd-link.c
src/network/networkd-lldp-tx.c
src/network/networkd-manager.c
src/network/networkd-netdev-bridge.c
src/network/networkd-netdev-bridge.h
src/network/networkd-netdev-gperf.gperf
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-route.c
src/network/networkd.c
src/network/networkd.h
src/network/test-network-tables.c
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-network.c
src/nspawn/nspawn-network.h
src/nspawn/nspawn-patch-uid.c [new file with mode: 0644]
src/nspawn/nspawn-patch-uid.h [new file with mode: 0644]
src/nspawn/nspawn-register.c
src/nspawn/nspawn-settings.c
src/nspawn/nspawn-settings.h
src/nspawn/nspawn.c
src/nspawn/test-patch-uid.c [new file with mode: 0644]
src/nss-myhostname/nss-myhostname.c
src/nss-resolve/nss-resolve.c
src/resolve/RFCs
src/resolve/resolved-bus.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-link.c
src/run/run.c
src/shared/bus-unit-util.c [new file with mode: 0644]
src/shared/bus-unit-util.h [new file with mode: 0644]
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/cgroup-show.c
src/shared/cgroup-show.h
src/shared/conf-parser.c
src/shared/dropin.c
src/shared/firewall-util.c
src/shared/install.c
src/shared/install.h
src/shared/logs-show.c
src/shared/logs-show.h
src/shared/machine-image.c
src/shared/machine-image.h
src/shared/output-mode.c [new file with mode: 0644]
src/shared/output-mode.h
src/shared/path-lookup.c
src/shared/path-lookup.h
src/shared/sleep-config.c
src/shared/spawn-polkit-agent.c
src/shared/tests.c [new file with mode: 0644]
src/shared/tests.h [new file with mode: 0644]
src/systemctl/systemctl.c
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp6-client.h
src/systemd/sd-journal.h
src/systemd/sd-lldp.h
src/sysv-generator/sysv-generator.c
src/test/test-cgroup-mask.c
src/test/test-copy.c
src/test/test-engine.c
src/test/test-execute.c
src/test/test-install-root.c
src/test/test-install.c
src/test/test-namespace.c
src/test/test-nss.c [new file with mode: 0644]
src/test/test-path-lookup.c
src/test/test-path-util.c
src/test/test-path.c
src/test/test-rbtree.c [deleted file]
src/test/test-rlimit-util.c
src/test/test-sched-prio.c
src/test/test-strv.c
src/test/test-tmpfiles.c
src/test/test-udev.c
src/test/test-unit-file.c
src/test/test-unit-name.c
src/tmpfiles/tmpfiles.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/udev-builtin-net_id.c
src/udev/udevadm-monitor.c
src/udev/udevd.c
test/TEST-06-SELINUX/Makefile [changed from file to symlink]
test/TEST-07-ISSUE-1981/test.sh
test/TEST-08-ISSUE-2730/Makefile [changed from file to symlink]
test/TEST-09-ISSUE-2691/Makefile [new symlink]
test/TEST-09-ISSUE-2691/test.sh [new file with mode: 0755]
test/TEST-10-ISSUE-2467/Makefile [new symlink]
test/TEST-10-ISSUE-2467/test.sh [new file with mode: 0755]
test/TEST-11-ISSUE-3166/Makefile [new symlink]
test/TEST-11-ISSUE-3166/test.sh [new file with mode: 0755]
test/networkd-test.py
test/sys.tar.xz
test/sysv-generator-test.py [changed mode: 0644->0755]
test/test-functions
test/udev-test.pl
tmpfiles.d/systemd.conf.m4
units/emergency.service.in
units/rc-local.service.in
units/systemd-machined.service.in
units/systemd-nspawn@.service.in
units/systemd-user-sessions.service.in
units/tmp.mount.m4

index 0e1d428ab05ad3d31e3d229dad05d5447f21b330..c7eb14452dba803739aa50332247a84d40761adf 100644 (file)
 /test-network
 /test-network-tables
 /test-ns
+/test-nss
 /test-parse-util
+/test-patch-uid
 /test-path
 /test-path-lookup
 /test-path-util
 /test-pty
 /test-qcow2
 /test-ratelimit
-/test-rbtree
 /test-replace-var
 /test-resolve
 /test-resolve-tables
diff --git a/.vimrc b/.vimrc
index 7b436bd3776950d12af3163a24be516c4e2a8047..284bf88494c574f0aefb4f76650b5a1320af4489 100644 (file)
--- a/.vimrc
+++ b/.vimrc
@@ -16,5 +16,5 @@ set shiftwidth=8
 set expandtab
 set makeprg=GCC_COLORS=\ make
 set tw=79
-au FileType xml set tw=119
+au BufRead,BufNewFile *.xml set tw=119 shiftwidth=2 smarttab
 au FileType c set tw=119
index e5ba396368d8f49f3a77e62d82246fa89f26cde1..b689355c9a6611fdadfe09ab88f15ff3e61930a5 100644 (file)
   b) socket() and socketpair() must get SOCK_CLOEXEC passed
   c) recvmsg() must get MSG_CMSG_CLOEXEC set
   d) F_DUPFD_CLOEXEC should be used instead of F_DUPFD, and so on
+  f) invocations of fopen() should take "e"
 
 - We never use the POSIX version of basename() (which glibc defines it in
   libgen.h), only the GNU version (which glibc defines in string.h).
 
       unlink("/foo/bar/baz");
 
+  Don't cast function calls to (void) that return no error
+  conditions. Specifically, the various xyz_unref() calls that return a NULL
+  object shouldn't be cast to (void), since not using the return value does not
+  hide any errors.
+
 - Don't invoke exit(), ever. It is not replacement for proper error
   handling. Please escalate errors up your call chain, and use normal
   "return" to exit from the main function of a process. If you
index 3f03afc2efef39a1a9499a338930a7127242091d..d5b328d267145557192e9dd43b9da4c45896393c 100644 (file)
@@ -144,6 +144,7 @@ MANPAGES += \
        man/systemd.link.5 \
        man/systemd.mount.5 \
        man/systemd.nspawn.5 \
+       man/systemd.offline-updates.7 \
        man/systemd.path.5 \
        man/systemd.preset.5 \
        man/systemd.resource-control.5 \
@@ -241,6 +242,7 @@ MANPAGES_ALIAS += \
        man/SD_JOURNAL_INVALIDATE.3 \
        man/SD_JOURNAL_LOCAL_ONLY.3 \
        man/SD_JOURNAL_NOP.3 \
+       man/SD_JOURNAL_OS_ROOT.3 \
        man/SD_JOURNAL_RUNTIME_ONLY.3 \
        man/SD_JOURNAL_SUPPRESS_LOCATION.3 \
        man/SD_JOURNAL_SYSTEM.3 \
@@ -387,9 +389,10 @@ MANPAGES_ALIAS += \
        man/sd_journal_get_timeout.3 \
        man/sd_journal_has_persistent_files.3 \
        man/sd_journal_next_skip.3 \
-       man/sd_journal_open_container.3 \
        man/sd_journal_open_directory.3 \
+       man/sd_journal_open_directory_fd.3 \
        man/sd_journal_open_files.3 \
+       man/sd_journal_open_files_fd.3 \
        man/sd_journal_perror.3 \
        man/sd_journal_previous.3 \
        man/sd_journal_previous_skip.3 \
@@ -570,6 +573,7 @@ man/SD_JOURNAL_FOREACH_UNIQUE.3: man/sd_journal_query_unique.3
 man/SD_JOURNAL_INVALIDATE.3: man/sd_journal_get_fd.3
 man/SD_JOURNAL_LOCAL_ONLY.3: man/sd_journal_open.3
 man/SD_JOURNAL_NOP.3: man/sd_journal_get_fd.3
+man/SD_JOURNAL_OS_ROOT.3: man/sd_journal_open.3
 man/SD_JOURNAL_RUNTIME_ONLY.3: man/sd_journal_open.3
 man/SD_JOURNAL_SUPPRESS_LOCATION.3: man/sd_journal_print.3
 man/SD_JOURNAL_SYSTEM.3: man/sd_journal_open.3
@@ -716,9 +720,10 @@ man/sd_journal_get_monotonic_usec.3: man/sd_journal_get_realtime_usec.3
 man/sd_journal_get_timeout.3: man/sd_journal_get_fd.3
 man/sd_journal_has_persistent_files.3: man/sd_journal_has_runtime_files.3
 man/sd_journal_next_skip.3: man/sd_journal_next.3
-man/sd_journal_open_container.3: man/sd_journal_open.3
 man/sd_journal_open_directory.3: man/sd_journal_open.3
+man/sd_journal_open_directory_fd.3: man/sd_journal_open.3
 man/sd_journal_open_files.3: man/sd_journal_open.3
+man/sd_journal_open_files_fd.3: man/sd_journal_open.3
 man/sd_journal_perror.3: man/sd_journal_print.3
 man/sd_journal_previous.3: man/sd_journal_next.3
 man/sd_journal_previous_skip.3: man/sd_journal_next.3
@@ -1033,6 +1038,9 @@ man/SD_JOURNAL_LOCAL_ONLY.html: man/sd_journal_open.html
 man/SD_JOURNAL_NOP.html: man/sd_journal_get_fd.html
        $(html-alias)
 
+man/SD_JOURNAL_OS_ROOT.html: man/sd_journal_open.html
+       $(html-alias)
+
 man/SD_JOURNAL_RUNTIME_ONLY.html: man/sd_journal_open.html
        $(html-alias)
 
@@ -1471,15 +1479,18 @@ man/sd_journal_has_persistent_files.html: man/sd_journal_has_runtime_files.html
 man/sd_journal_next_skip.html: man/sd_journal_next.html
        $(html-alias)
 
-man/sd_journal_open_container.html: man/sd_journal_open.html
+man/sd_journal_open_directory.html: man/sd_journal_open.html
        $(html-alias)
 
-man/sd_journal_open_directory.html: man/sd_journal_open.html
+man/sd_journal_open_directory_fd.html: man/sd_journal_open.html
        $(html-alias)
 
 man/sd_journal_open_files.html: man/sd_journal_open.html
        $(html-alias)
 
+man/sd_journal_open_files_fd.html: man/sd_journal_open.html
+       $(html-alias)
+
 man/sd_journal_perror.html: man/sd_journal_print.html
        $(html-alias)
 
@@ -1849,11 +1860,21 @@ MANPAGES += \
        man/coredumpctl.1 \
        man/systemd-coredump.8
 MANPAGES_ALIAS += \
-       man/coredump.conf.d.5
+       man/coredump.conf.d.5 \
+       man/systemd-coredump.socket.8 \
+       man/systemd-coredump@.service.8
 man/coredump.conf.d.5: man/coredump.conf.5
+man/systemd-coredump.socket.8: man/systemd-coredump.8
+man/systemd-coredump@.service.8: man/systemd-coredump.8
 man/coredump.conf.d.html: man/coredump.conf.html
        $(html-alias)
 
+man/systemd-coredump.socket.html: man/systemd-coredump.html
+       $(html-alias)
+
+man/systemd-coredump@.service.html: man/systemd-coredump.html
+       $(html-alias)
+
 endif
 
 if ENABLE_EFI
@@ -1960,15 +1981,21 @@ endif
 if ENABLE_NETWORKD
 MANPAGES += \
        man/networkctl.1 \
+       man/networkd.conf.5 \
        man/systemd-networkd-wait-online.service.8 \
        man/systemd-networkd.service.8 \
        man/systemd.netdev.5 \
        man/systemd.network.5
 MANPAGES_ALIAS += \
+       man/networkd.conf.d.5 \
        man/systemd-networkd-wait-online.8 \
        man/systemd-networkd.8
+man/networkd.conf.d.5: man/networkd.conf.5
 man/systemd-networkd-wait-online.8: man/systemd-networkd-wait-online.service.8
 man/systemd-networkd.8: man/systemd-networkd.service.8
+man/networkd.conf.d.html: man/networkd.conf.html
+       $(html-alias)
+
 man/systemd-networkd-wait-online.html: man/systemd-networkd-wait-online.service.html
        $(html-alias)
 
@@ -2479,6 +2506,7 @@ EXTRA_DIST += \
        man/machinectl.xml \
        man/modules-load.d.xml \
        man/networkctl.xml \
+       man/networkd.conf.xml \
        man/nss-myhostname.xml \
        man/nss-mymachines.xml \
        man/nss-resolve.xml \
@@ -2644,6 +2672,7 @@ EXTRA_DIST += \
        man/systemd.netdev.xml \
        man/systemd.network.xml \
        man/systemd.nspawn.xml \
+       man/systemd.offline-updates.xml \
        man/systemd.path.xml \
        man/systemd.preset.xml \
        man/systemd.resource-control.xml \
index 9ed2217d012e65e6cfabac2292fb80d58eb2860f..a05c7ce4db5a86cee6412d087df590f465534c5b 100644 (file)
@@ -747,8 +747,6 @@ libbasic_la_SOURCES = \
        src/basic/missing_syscall.h \
        src/basic/capability-util.c \
        src/basic/capability-util.h \
-       src/basic/c-rbtree.c \
-       src/basic/c-rbtree.h \
        src/basic/conf-files.c \
        src/basic/conf-files.h \
        src/basic/stdio-util.h \
@@ -964,6 +962,7 @@ noinst_LTLIBRARIES += \
 
 libshared_la_SOURCES = \
        src/shared/output-mode.h \
+       src/shared/output-mode.c \
        src/shared/gpt.h \
        src/shared/udev-util.h \
        src/shared/linux/auto_dev-ioctl.h \
@@ -1038,7 +1037,11 @@ libshared_la_SOURCES = \
        src/shared/machine-pool.c \
        src/shared/machine-pool.h \
        src/shared/resolve-util.c \
-       src/shared/resolve-util.h
+       src/shared/resolve-util.h \
+       src/shared/bus-unit-util.c \
+       src/shared/bus-unit-util.h \
+       src/shared/tests.h \
+       src/shared/tests.c
 
 if HAVE_UTMP
 libshared_la_SOURCES += \
@@ -1383,6 +1386,9 @@ pkgconfigdata_DATA += \
 nodist_rpmmacros_DATA = \
        src/core/macros.systemd
 
+BUILT_SOURCES += \
+       src/core/triggers.systemd
+
 EXTRA_DIST += \
        src/core/systemd.pc.in \
        src/core/macros.systemd.in \
@@ -1491,7 +1497,6 @@ tests += \
        test-copy \
        test-cap-list \
        test-sigbus \
-       test-rbtree \
        test-verbs \
        test-af-list \
        test-arphrd-list \
@@ -1745,12 +1750,6 @@ test_sigbus_SOURCES = \
 test_sigbus_LDADD = \
        libshared.la
 
-test_rbtree_SOURCES = \
-       src/test/test-rbtree.c
-
-test_rbtree_LDADD = \
-       libshared.la
-
 test_condition_SOURCES = \
        src/test/test-condition.c
 
@@ -3022,10 +3021,14 @@ systemd_nspawn_SOURCES = \
        src/nspawn/nspawn-setuid.h \
        src/nspawn/nspawn-stub-pid1.c \
        src/nspawn/nspawn-stub-pid1.h \
+       src/nspawn/nspawn-patch-uid.c \
+       src/nspawn/nspawn-patch-uid.h \
        src/core/mount-setup.c \
        src/core/mount-setup.h \
        src/core/loopback-setup.c \
-       src/core/loopback-setup.h
+       src/core/loopback-setup.h \
+       src/core/machine-id-setup.c \
+       src/core/machine-id-setup.h
 
 nodist_systemd_nspawn_SOURCES = \
        src/nspawn/nspawn-gperf.c
@@ -3047,6 +3050,17 @@ systemd_nspawn_LDADD += \
        libfirewall.la
 endif
 
+test_patch_uid_SOURCES = \
+       src/nspawn/nspawn-patch-uid.c \
+       src/nspawn/nspawn-patch-uid.h \
+       src/nspawn/test-patch-uid.c
+
+test_patch_uid_LDADD = \
+       libshared.la
+
+manual_tests += \
+       test-patch-uid
+
 # ------------------------------------------------------------------------------
 systemd_run_SOURCES = \
        src/run/run.c
@@ -3826,9 +3840,11 @@ check_DATA += \
 endif
 
 # packed sysfs test tree
-test/sys:
+test/sys: test/sys.tar.xz
+       -rm -rf test/sys
        $(AM_V_at)$(MKDIR_P) $(dir $@)
        $(AM_V_GEN)tar -C test/ -xJf $(top_srcdir)/test/sys.tar.xz
+       -touch test/sys
 
 test-sys-distclean:
        -rm -rf test/sys
@@ -4723,7 +4739,7 @@ systemd_localed_SOURCES = \
 
 systemd_localed_LDADD = \
        libshared.la \
-       $(XKBCOMMON_LIBS)
+       -ldl
 
 systemd_localed_CFLAGS = \
        $(AM_CFLAGS) \
@@ -4874,6 +4890,17 @@ EXTRA_DIST += \
        units/systemd-timesyncd.service.in \
        src/timesync/timesyncd.conf.in
 
+# ------------------------------------------------------------------------------
+test_nss_SOURCES = \
+       src/test/test-nss.c
+
+test_nss_LDADD = \
+       libsystemd-internal.la \
+       -ldl
+
+manual_tests += \
+       test-nss
+
 # ------------------------------------------------------------------------------
 if HAVE_MYHOSTNAME
 libnss_myhostname_la_SOURCES = \
@@ -4915,7 +4942,9 @@ libmachine_core_la_SOURCES = \
        src/machine/machine-dbus.c \
        src/machine/machine-dbus.h \
        src/machine/image-dbus.c \
-       src/machine/image-dbus.h
+       src/machine/image-dbus.h \
+       src/machine/operation.c \
+       src/machine/operation.h
 
 libmachine_core_la_LIBADD = \
        libshared.la
@@ -5397,6 +5426,8 @@ libnetworkd_core_la_CFLAGS = \
 libnetworkd_core_la_SOURCES = \
        src/libsystemd-network/network-internal.h \
        src/network/networkd.h \
+       src/network/networkd-conf.h \
+       src/network/networkd-conf.c \
        src/network/networkd-link.h \
        src/network/networkd-link.c \
        src/network/networkd-netdev.h \
@@ -5445,6 +5476,7 @@ libnetworkd_core_la_SOURCES = \
        src/network/networkd-lldp-tx.c
 
 nodist_libnetworkd_core_la_SOURCES = \
+       src/network/networkd-gperf.c \
        src/network/networkd-network-gperf.c \
        src/network/networkd-netdev-gperf.c
 
@@ -5541,6 +5573,7 @@ BUSNAMES_TARGET_WANTS += \
 endif
 
 gperf_gperf_sources += \
+       src/network/networkd-gperf.gperf \
        src/network/networkd-network-gperf.gperf \
        src/network/networkd-netdev-gperf.gperf
 
@@ -5705,7 +5738,7 @@ dist_dbussystemservice_DATA += \
 dist_dbuspolicy_DATA += \
        src/login/org.freedesktop.login1.conf
 
-dist_pkgsysconf_DATA += \
+nodist_pkgsysconf_DATA += \
        src/login/logind.conf
 
 polkitpolicy_files += \
@@ -5742,7 +5775,8 @@ gperf_gperf_sources += \
 EXTRA_DIST += \
        src/login/71-seat.rules.in \
        src/login/73-seat-late.rules.in \
-       units/systemd-logind.service.in
+       units/systemd-logind.service.in \
+       src/login/logind.conf.in
 
 # ------------------------------------------------------------------------------
 if HAVE_PAM
@@ -5795,6 +5829,14 @@ EXTRA_DIST += \
        test/TEST-07-ISSUE-1981/Makefile \
        test/TEST-07-ISSUE-1981/test-segfault.sh \
        test/TEST-07-ISSUE-1981/test.sh \
+       test/TEST-08-ISSUE-2730/Makefile \
+       test/TEST-08-ISSUE-2730/test.sh \
+       test/TEST-09-ISSUE-2691/Makefile \
+       test/TEST-09-ISSUE-2691/test.sh \
+       test/TEST-10-ISSUE-2467/Makefile \
+       test/TEST-10-ISSUE-2467/test.sh \
+       test/TEST-11-ISSUE-3166/Makefile \
+       test/TEST-11-ISSUE-3166/test.sh \
        test/test-functions
 
 EXTRA_DIST += \
@@ -5859,6 +5901,7 @@ substitutions = \
        '|NTP_SERVERS=$(NTP_SERVERS)|' \
        '|DNS_SERVERS=$(DNS_SERVERS)|' \
        '|DEFAULT_DNSSEC_MODE=$(DEFAULT_DNSSEC_MODE)|' \
+       '|KILL_USER_PROCESSES=$(KILL_USER_PROCESSES)|' \
        '|systemuidmax=$(SYSTEM_UID_MAX)|' \
        '|systemgidmax=$(SYSTEM_GID_MAX)|' \
        '|TTY_GID=$(TTY_GID)|' \
diff --git a/NEWS b/NEWS
index 6f43b8ce3a33207a51efc1c01f03a94304e46ff2..16ea7b7290d7a8b47cde9e7a7d25c7dc55f69dea 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,10 +19,83 @@ CHANGES WITH 230 in spe:
           again don't consider turning this on in your stable, LTS or
           production release just yet.
 
+        * systemd-resolve conveniently resolves DANE records with the --tlsa
+          option and OPENPGPKEY records with the --openpgp option.
+
+        * systemd-logind will now by default terminate user processes that are
+          part of the user session scope unit (session-XX.scope) when the user
+          logs out. This behaviour is controlled by the
+          KillUserProcesses=yes|no setting in logind.conf, and previous default
+          of "no" is now changed to "yes". This means that user sessions will
+          be properly cleaned up after, but additional steps are necessary to
+          allow intentionally long-running processes to survive logout.
+
+          While the user is logged in at least once, user@.service is running,
+          and any service that should survive the end of any individual login
+          session can be started at a user service or scope using systemd-run.
+          systemd-run(1) man page has been extended with an example which
+          shows how to run screen in a scope unit underneath user@.service.
+          The same command works for tmux.
+
+          After the user logs out of all sessions, user@.service will be
+          terminated too, by default, unless the user has "lingering" enabled.
+          To effectively allow users to run long-term tasks even if they are
+          logged out, lingering must be enabled for them. See loginctl(1) for
+          details. The default polkit policy was modified to allow users to
+          set lingering for themselves without authentication.
+
+          Previous defaults can be restored at compile time by the
+          --without-kill-user-processes option.
+
+        * The unified cgroup hierarchy added in Linux 4.5 is now supported.
+          Use systemd.unified_cgroup_hierarchy=1 on the kernel command line
+          to enable.
+          WARNING: it is not possible to use previous systemd versions with
+          systemd.unified_cgroup_hierarchy=1 and the new kernel. Therefore it
+          is necessary to also update systemd in the initramfs if using the
+          unified hierarchy. Updated selinux policy is also required.
+
+        * LLDP support has been extended, and both passive (receive-only)
+          and active (sender) modes are supported. Passive mode
+          ("routers-only") is enabled by default in systemd-networkd.
+          Active LLDP mode is enabled by default for containers on the
+          internal network.
+          "networkctl lldp" can be used to list information gathered.
+
+        * Headers for LLDP support (sd-lldp.h) are now public.
+
+        * The Unique Identifier sent in DHCP requests can be configured.
+
         * Testing tool /usr/lib/systemd/systemd-activate is renamed to
           systemd-socket-activate and installed into /usr/bin. It is now fully
           supported.
 
+        * systemd-journald now uses separate threads to flush changes to
+          disk when closing journal files.
+
+        * systemd-ask-password skips printing of the password to stdout
+          with --no-output which can be useful in scripts.
+
+        * Framebuffer devices (/dev/fb*) and 3D printers and scanners
+          (devices tagged with ID_MAKER_TOOL) are now tagged with
+          "uaccess" and are available to logged in users.
+
+        * systemd-bootchart has been split out to a separate repository:
+          https://github.com/systemd/systemd-bootchart
+
+        * Compatibility libraries libsystemd-daemon.so, libsystemd-journal.so,
+          libsystemd-id128.so, and libsystemd-login.so which have been
+          deprecated since systemd-209 have been removed along along with the
+          corresponding pkg-config files. All symbols provided by the those
+          libraries are provided by libsystemd.so.
+
+        * Capabilities= setting has been removed (it is ignored for backwards
+          compatibility). AmbientCapabilities= and CapabilityBoundingSet=
+          should be used instead.
+
+        * systemd-bus-proxyd has been removed, as kdbus will not be merged
+          in current form.
+
 CHANGES WITH 229:
 
         * The systemd-resolved DNS resolver service has gained a substantial
@@ -238,7 +311,7 @@ CHANGES WITH 229:
         Andersen, Tom Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Vito
         Caputo, WaLyong Cho, Yu Watanabe, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2016-02-11
+         Berlin, 2016-02-11
 
 CHANGES WITH 228:
 
@@ -369,6 +442,9 @@ CHANGES WITH 228:
 
           https://sourceware.org/bugzilla/show_bug.cgi?id=19108
 
+          Note that only util-linux versions built with
+          --enable-libmount-force-mountinfo are supported.
+
         * Support for the ".snapshot" unit type has been removed. This
           feature turned out to be little useful and little used, and
           has now been removed from the core and from systemctl.
@@ -436,7 +512,7 @@ CHANGES WITH 228:
         Tom Gundersen, Torstein Husebø, Vito Caputo, Zbigniew
         Jędrzejewski-Szmek
 
-        -- Berlin, 2015-11-18
+         Berlin, 2015-11-18
 
 CHANGES WITH 227:
 
@@ -640,7 +716,7 @@ CHANGES WITH 227:
         Andersen, Tom Gundersen, Tom Lyon, Viktar Vauchkevich,
         Zbigniew Jędrzejewski-Szmek, Марко М. Костић
 
-        -- Berlin, 2015-10-07
+         Berlin, 2015-10-07
 
 CHANGES WITH 226:
 
@@ -760,7 +836,7 @@ CHANGES WITH 226:
         Hack, Susant Sahani, Sylvain Pasche, Thomas Hindoe Paaboel
         Andersen, Tom Gundersen, Torstein Husebø
 
-        -- Berlin, 2015-09-08
+         Berlin, 2015-09-08
 
 CHANGES WITH 225:
 
@@ -833,7 +909,7 @@ CHANGES WITH 225:
         Paaboel Andersen, Thomas Meyer, Tom Gundersen, Vincent Batts,
         WaLyong Cho, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-08-27
+         Berlin, 2015-08-27
 
 CHANGES WITH 224:
 
@@ -848,7 +924,7 @@ CHANGES WITH 224:
         Herrmann, Herman Fries, Johannes Nixdorf, Kay Sievers, Lennart
         Poettering, Peter Hutterer, Susant Sahani, Tom Gundersen
 
-        -- Berlin, 2015-07-31
+         Berlin, 2015-07-31
 
 CHANGES WITH 223:
 
@@ -913,7 +989,7 @@ CHANGES WITH 223:
         Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Vito Caputo,
         Vivenzio Pagliari, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-07-29
+         Berlin, 2015-07-29
 
 CHANGES WITH 222:
 
@@ -953,7 +1029,7 @@ CHANGES WITH 222:
         Susant Sahani, Thomas Hindoe Paaboel Andersen, Tom Gundersen, Torstein
         Husebø, Vedran Miletić, WaLyong Cho, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-07-07
+         Berlin, 2015-07-07
 
 CHANGES WITH 221:
 
@@ -1031,7 +1107,7 @@ CHANGES WITH 221:
         Husebø, Umut Tezduyar Lindskog, Viktar Vauchkevich, Werner
         Fink, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-06-19
+         Berlin, 2015-06-19
 
 CHANGES WITH 220:
 
@@ -1260,7 +1336,7 @@ CHANGES WITH 220:
         Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Will
         Woods, Zachary Cook, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-05-22
+         Berlin, 2015-05-22
 
 CHANGES WITH 219:
 
@@ -1584,7 +1660,7 @@ CHANGES WITH 219:
         Lindskog, Veres Lajos, Vincent Batts, WaLyong Cho, Wieland
         Hoffmann, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2015-02-16
+         Berlin, 2015-02-16
 
 CHANGES WITH 218:
 
@@ -1786,7 +1862,7 @@ CHANGES WITH 218:
         Torstein Husebø, Umut Tezduyar Lindskog, Vicente Olivert
         Riera, WaLyong Cho, Wesley Dawson, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-12-10
+         Berlin, 2014-12-10
 
 CHANGES WITH 217:
 
@@ -1998,7 +2074,7 @@ CHANGES WITH 217:
         Husebø, Umut Tezduyar Lindskog, WaLyong Cho, Zbigniew
         Jędrzejewski-Szmek
 
-        -- Berlin, 2014-10-28
+         Berlin, 2014-10-28
 
 CHANGES WITH 216:
 
@@ -2200,7 +2276,7 @@ CHANGES WITH 216:
         Tobias Geerinckx-Rice, Tomasz Torcz, Tom Gundersen, Umut
         Tezduyar Lindskog, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-08-19
+         Berlin, 2014-08-19
 
 CHANGES WITH 215:
 
@@ -2434,7 +2510,7 @@ CHANGES WITH 215:
         Paaboel Andersen, Tom Gundersen, Tom Hirst, Umut Tezduyar
         Lindskog, Uoti Urpala, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-07-03
+         Berlin, 2014-07-03
 
 CHANGES WITH 214:
 
@@ -2628,7 +2704,7 @@ CHANGES WITH 214:
         Andersen, Tom Gundersen, Umut Tezduyar Lindskog, Zbigniew
         Jędrzejewski-Szmek
 
-        -- Berlin, 2014-06-11
+         Berlin, 2014-06-11
 
 CHANGES WITH 213:
 
@@ -2760,7 +2836,7 @@ CHANGES WITH 213:
         Lindskog, WaLyong Cho, Will Woods, Zbigniew
         Jędrzejewski-Szmek
 
-        -- Beijing, 2014-05-28
+         Beijing, 2014-05-28
 
 CHANGES WITH 212:
 
@@ -2909,7 +2985,7 @@ CHANGES WITH 212:
         Umut Tezduyar Lindskog, Wieland Hoffmann, Zbigniew
         Jędrzejewski-Szmek
 
-        -- Berlin, 2014-03-25
+         Berlin, 2014-03-25
 
 CHANGES WITH 211:
 
@@ -3033,7 +3109,7 @@ CHANGES WITH 211:
         Gundersen, Umut Tezduyar Lindskog, Uoti Urpala, Zachary Cook,
         Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-03-12
+         Berlin, 2014-03-12
 
 CHANGES WITH 210:
 
@@ -3138,7 +3214,7 @@ CHANGES WITH 210:
         Paaboel Andersen, Tom Gundersen, Umut Tezduyar Lindskog,
         Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-02-24
+         Berlin, 2014-02-24
 
 CHANGES WITH 209:
 
@@ -3594,7 +3670,7 @@ CHANGES WITH 209:
         Pavlín, Vincent Batts, WaLyong Cho, William Giokas, Yang
         Zhiyong, Yin Kangkai, Yuxuan Shui, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2014-02-20
+         Berlin, 2014-02-20
 
 CHANGES WITH 208:
 
@@ -3681,7 +3757,7 @@ CHANGES WITH 208:
         Michael Scherer, Michał Górny, Mike Gilbert, Patrick McCarty,
         Sebastian Ott, Tom Gundersen, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2013-10-02
+         Berlin, 2013-10-02
 
 CHANGES WITH 207:
 
@@ -3781,7 +3857,7 @@ CHANGES WITH 207:
         Paaboel Andersen, Tom Gundersen, Umut Tezduyar, WANG Chao,
         William Giokas, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2013-09-13
+         Berlin, 2013-09-13
 
 CHANGES WITH 206:
 
@@ -3880,14 +3956,14 @@ CHANGES WITH 206:
         Thomas H.P. Andersen, Tom Gundersen, Tomasz Torcz, William
         Giokas, Zbigniew Jędrzejewski-Szmek
 
-        -- Berlin, 2013-07-23
+         Berlin, 2013-07-23
 
 CHANGES WITH 205:
 
         * Two new unit types have been introduced:
 
           Scope units are very similar to service units, however, are
-          created out of pre-existing processes -- instead of PID 1
+          created out of pre-existing processes  instead of PID 1
           forking off the processes. By using scope units it is
           possible for system services and applications to group their
           own child processes (worker processes) in a powerful way
diff --git a/README b/README
index 0118c102f6eed592795906f3ea57ce1f5ac2931e..ca8993cb1282e22fcb1c0fcecaa4f1cc6adc3f63 100644 (file)
--- a/README
+++ b/README
@@ -118,6 +118,7 @@ REQUIREMENTS:
         glibc >= 2.16
         libcap
         libmount >= 2.27.1 (from util-linux)
+                (util-linux *must* be built with --enable-libmount-force-mountinfo)
         libseccomp >= 1.0.0 (optional)
         libblkid >= 2.24 (from util-linux) (optional)
         libkmod >= 15 (optional)
diff --git a/TODO b/TODO
index b2840ba4ab395959d09992add6906b348050ea00..a930583f85e05bc066ce1a9f0a9dfe5f41951e6f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -33,16 +33,34 @@ Janitorial Clean-ups:
 
 Features:
 
-* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
+* journalctl: make sure -f ends when the container indicated by -M terminates
+
+* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
+  kernel doesn't support linkat() that replaces existing files, currently)
+
+* check if DeviceAllow= should split first, resolve specifiers later
+
+* transient units: don't bother with actually setting unit properties, we
+  reload the unit file anyway
 
-* machinectl remove --hidden + machinectl remove --all
+* make sure resolved can be restarted without losing pushed-in dns config
+
+* fix https://github.com/systemd/systemd/pull/2890, this shouldn't be exported
+  like this.
+
+* journald: sigbus API via a signal-handler safe function that people may call
+  from the SIGBUS handler
+
+* resolved: cefmz.x.incapdns.net fails to authenticate
+
+* 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
 
 * resolved: maybe, after all, implement local listening for DNS packets on port
-  53.
+  127.0.0.53:53.
 
 * delay activation of logind until somebody logs in, or when /dev/tty0 pulls it
   in or lingering is on (so that containers don't bother with it until PAM is used). also exit-on-idle
@@ -56,11 +74,9 @@ Features:
 * PID1: find a way how we can reload unit file configuration for
   specific units only, without reloading the whole of systemd
 
-* add an explicit parser for LimitNICE= and LimitRTPRIO= that verifies
+* add an explicit parser for LimitRTPRIO= that verifies
   the specified range and generates sane error messages for incorrect
-  specifications. Also, for LimitNICE= maybe introduce a syntax such
-  as "+5" or "-7" in order to make the limits more readable as they
-  are otherwise shifted by 20.
+  specifications.
 
 * do something about "/control" subcgroups in the unified cgroup hierarchy
 
@@ -68,12 +84,6 @@ Features:
 
 * push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy)
 
-* add a new command "systemctl revert" or so, that removes all dropin
-  snippets in /run and /etc, and all unit files with counterparts in
-  /usr, and thus undoes what "systemctl set-property" and "systemctl
-  edit" create. Maybe even add "systemctl revert -a" to do this for
-  all units.
-
 * 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.
@@ -87,9 +97,6 @@ Features:
 
 * install: include generator dirs in unit file search paths
 
-* rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring
-  to unicode chars, to make things more expressive.
-
 * fstab-generator: default to tmpfs-as-root if only usr= is specified on the kernel cmdline
 
 * docs: bring http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date
@@ -139,8 +146,6 @@ Features:
 * as soon as we have kdbus, and sender timestamps, revisit coalescing multiple parallel daemon reloads:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/025862.html
 
-* the install state probably shouldn't get confused by generated units, think dbus1/kdbus compat!
-
 * in systemctl list-unit-files: show the install value the presets would suggest for a service in a third column
 
 * figure out when we can use the coarse timers
@@ -152,8 +157,6 @@ Features:
 
 * firstboot: make it useful to be run immediately after yum --installroot to set up a machine. (most specifically, make --copy-root-password work even if /etc/passwd already exists
 
-* add infrastructure to allocate dynamic/transient users and UID ranges, for use in user-namespaced containers, per-seat gdm login screens and gdm guest sessions
-
 * maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment=
 
 * introduce systemd-timesync-wait.service or so to sync on an NTP fix?
@@ -240,7 +243,7 @@ Features:
   CAP_NET_ADMIN is set, more than the loopback device is defined, even
   when it is otherwise off
 
-* MessageQueueMessageSize= and RLimitFSIZE= (and suchlike) should use parse_iec_size().
+* MessageQueueMessageSize= (and suchlike) should use parse_iec_size().
 
 * "busctl status" works only as root on dbus1, since we cannot read
   /proc/$PID/exe
@@ -255,7 +258,7 @@ 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 and wallclock runtime for a service
+* 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
@@ -377,7 +380,7 @@ Features:
 
 * systemd-inhibit: make taking delay locks useful: support sending SIGINT or SIGTERM on PrepareForSleep()
 
-* remove any syslog support from log.c -- we probably cannot do this before split-off udev is gone for good
+* remove any syslog support from log.c  we probably cannot do this before split-off udev is gone for good
 
 * shutdown logging: store to EFI var, and store to USB stick?
 
@@ -497,8 +500,6 @@ Features:
     written to as FAIL, but instead show that their are being written to.
   - add journalctl -H that talks via ssh to a remote peer and passes through
     binary logs data
-  - change journalctl -M to acquire fd to journal directory via machined, and
-    then operate on that via openat() instead of absolute paths
   - add a version of --merge which also merges /var/log/journal/remote
   - log accumulated resource usage after each service invocation
   - journalctl: -m should access container journals directly by enumerating
@@ -537,7 +538,6 @@ Features:
 * unit install:
   - "systemctl mask" should find all names by which a unit is accessible
     (i.e. by scanning for symlinks to it) and link them all to /dev/null
-  - systemctl list-unit-files should list generated files (and probably with a new state "generated" for them, or so)
 
 * timer units:
   - timer units should get the ability to trigger when:
@@ -564,8 +564,6 @@ Features:
   - 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
-  - refuses to boot containers without /etc/machine-id (OK?), and with empty
-    /etc/machine-id (not OK).
   - 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
@@ -586,8 +584,6 @@ Features:
   - should send out sd_notify("WATCHDOG=1") messages
   - optionally automatically add FORWARD rules to iptables whenever nspawn is
     running, remove them when shut down.
-  - add a logic for cleaning up read-only, hidden container images in
-    /var/lib/machines that are not ancestors of any non-hidden containers
   - Improve error message when --bind= is used on a non-existing source
     directory
   - maybe make copying of /etc/resolv.conf optional, and skip it if --read-only
@@ -631,8 +627,6 @@ Features:
 
 * initialize the hostname from the fs label of /, if /etc/hostname does not exist?
 
-* rename "userspace" to "core-os"
-
 * udev:
   - move to LGPL
   - kill scsi_id
@@ -747,11 +741,6 @@ Features:
   - Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely
   - consider adding RuntimeDirectoryUser= + RuntimeDirectoryGroup=
 
-* systemd-python:
-   - figure out a simple way to wait for journal events in a way that
-     works with ^C
-   - add documentation to systemd.daemon
-
 * udev-link-config:
    - Make sure ID_PATH is always exported and complete for
      network devices where possible, so we can safely rely
index be081d6efc097915b1b70d49a2f439e6e1db2263..051f49492ff1a87d224363eeac589660e6eee52b 100644 (file)
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
 Паведамленні іншых сэрвісаў засталіся.
 
 Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з
-дапамогай RateLimitInterval= і RateLimitBurst= у файле
+дапамогай RateLimitIntervalSec= і RateLimitBurst= у файле
 /etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 382fdb8b0452a83a0ed70f1aa532d081768a1af8..6ab361aafb12ae04d18dc38099b8e061938ca449 100644 (file)
@@ -53,7 +53,7 @@ Majcie na ŭvazie, što byli adkinuty paviedamliennia toĺki hetaha servisu.
 Paviedamlienni inšych servisaŭ zastalisia.
 
 Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z
-dapamohaj RateLimitInterval= i RateLimitBurst= u fajlie
+dapamohaj RateLimitIntervalSec= i RateLimitBurst= u fajlie
 /etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia detaliej.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 077f182a5a7ad78ed9d7d334d188b06501192d54..90929bca6dd3832e1a5c13f04f8f5a9924f6cdb8 100644 (file)
@@ -66,7 +66,7 @@ Note that only messages from the service in question have been
 dropped, other services' messages are unaffected.
 
 The limits controlling when messages are dropped may be configured
-with RateLimitInterval= and RateLimitBurst= in
+with RateLimitIntervalSec= and RateLimitBurst= in
 /etc/systemd/journald.conf. See journald.conf(5) for details.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index bd4d742d8a14716e10f95a39b4496abb755b63a9..093e8139da665b5bfbdcd2d39205d5a81b435f54 100644 (file)
@@ -52,7 +52,7 @@ Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre
 services er ikke påvirket.
 
 Grænsen for hvornår beskeder bliver smidt væk kan konfigureres
-med RateLimitInterval= og RateLimitBurst= i
+med RateLimitIntervalSec= og RateLimitBurst= i
 /etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 03a457786fddb76ac8940fd543f09379377d8db3..d71c2902d72503d3afa1d13d84068d155836a40a 100644 (file)
@@ -51,7 +51,7 @@ Notez que seuls des messages de ce service ont été évincés, les messages des
 autres services ne sont pas affectés.
 
 Les limites définissant ce comportement peuvent être configurées avec les
-paramètres RateLimitInterval= et RateLimitBurst= dans le fichier
+paramètres RateLimitIntervalSec= et RateLimitBurst= dans le fichier
 /etc/systemd/journald.conf. Voir journald.conf(5) pour plus de détails.
 
 -- e9bf28e6e834481bb6f48f548ad13606
diff --git a/catalog/systemd.hr.catalog b/catalog/systemd.hr.catalog
new file mode 100644 (file)
index 0000000..350988d
--- /dev/null
@@ -0,0 +1,314 @@
+#  This file is part of systemd.
+#
+#  Copyright 2012 Lennart Poettering
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+#
+#  systemd is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public License
+#  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# Message catalog for systemd's own messages
+# Croatian translation
+
+# Format kataloga je dokumentiran na
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# Za pojašnjenje zašto ovo radimo, posjetite https://xkcd.com/1024/
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: journal je pokrenut
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Journal proces sustava se pokrenuo, otvorio je journal
+ datoteke za upis i spreman je za obradu zahtjeva.
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: journal je zaustavljen
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Journal proces sustava je isključio i zatvorio sve trenutno
+aktivne journal datoteke.
+
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Diskovni prostor koji koristi journal
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) trenutno koristi @CURRENT_USE_PRETTY@.
+Najveća dopuštena upotreba je postavljena na @MAX_USE_PRETTY@.
+Ostavljam najmanje @DISK_KEEP_FREE_PRETTY@ slobodno (trenutno dostupno @DISK_AVAILABLE_PRETTY@ diskovnog prostora).
+Prisilno ograničenje upotrebe je @LIMIT_PRETTY@, od kojeg je @AVAILABLE_PRETTY@ još dostupno.
+
+Ograničenja kontroliraju koliko diskovnog prostora koristi journal mogu
+se podesiti sa SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=,
+RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= settings u
+/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: Poruka iz usluge je potisnuta
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+Usluga je prijavila previše poruka u određenom vremenskom razdoblju. Poruke
+iz usluge su odbačene.
+
+Zapamtite da samo poruke iz usluge u upitu su
+odbačene, ostale poruke usluga nisu zahvaćene.
+
+Ograničenja koja kontroliraju kada je poruka odbačena mogu se podesiti
+sa RateLimitIntervalSec= i RateLimitBurst= u
+/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: Journal poruka je propuštena
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Kernel poruka je izgubljena zato jer ih journal sustav nije mogao
+dovoljno brzo obraditi.
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: Proces @COREDUMP_PID@ (@COREDUMP_COMM@) je izbacio jezgru
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+Proces @COREDUMP_PID@ (@COREDUMP_COMM@) se srušio i izbacio jezgru.
+
+Rušenje programa je uobičajeno uzrokovano greškom u programiranju i
+trebalo bi se prijaviti razvijatelju kao greška.
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: Nova sesija @SESSION_ID@ je stvorena za korisnika @USER_ID@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Nova sesija sa ID @SESSION_ID@ je stvorena za korisnika @USER_ID@.
+
+Glavni proces sesije je @LEADER@.
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: Sesija @SESSION_ID@ je prekinuta
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Sesija sa ID @SESSION_ID@ je prekinuta.
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: Novo sjedište @SEAT_ID@ je sada dostupno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Novo sjedište @SEAT_ID@ je podešeno i sada je dostupno.
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: Sjedište @SEAT_ID@ je sada uklonjeno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Sjedište @SEAT_ID@ je uklonjeno i više nije dostupno.
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: Vrijeme promjene
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sat sustava je promijenjen na @REALTIME@ microsekundi nakon 1. Siječnja, 1970 godine.
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: Vremenska zona je promijenjena u @TIMEZONE@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Vremenska zona je promijenjena u @TIMEZONE@.
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: Pokretanje sustava je sada završeno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sve usluge sustava koje su zadane za pokretanje pri pokretanju sustava
+su uspješno pokrenute. Zapamtite da ovo ne znači da sada računalo
+miruje zato jer se neke usluge još uvijek mogu pokretati.
+
+Pokretanje kernela zahtijeva @KERNEL_USEC@ mikrosekundi.
+
+Pokretanje početnog RAM diska zahtijeva @INITRD_USEC@ mikrosekundi.
+
+Pokretanje prostora korisnika zahtijeva @USERSPACE_USEC@ mikrosekundi.
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: Pokrenuto je stanje spavanja @SLEEP@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sustav je sada pokrenuo stanje spavanja @SLEEP@
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: Završeno je stanje spavanja @SLEEP@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sustav je sada završio stanje spavanja @SLEEP@
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: Pokrenuto je isključivanje sustava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Pokrenuto je isključivanje sustava. Isključivanje je sada pokrenuto,
+sve usluge sustava su prekinute i svi datotečni sustavi su odmontirani.
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: Jedinica @UNIT@ je započela pokretanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela pokretanje.
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: Jedinica @UNIT@ je završila pokretanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila pokretanje.
+
+Rezultat pokretanja je @RESULT@.
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: Jedinica @UNIT@ je započela isključivanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela isključivanje.
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: Jedinica @UNIT@ je završila isključivanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila isključivanje.
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: Jedinica @UNIT@ nije uspjela
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ nije uspjela.
+
+Rezultat je @RESULT@.
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: Jedinica @UNIT@ je započela ponovno učitavati podešavanja
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela ponovno učitavati podešavanja
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: Jedinica @UNIT@ je završila ponovno učitavati podešavanja
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila ponovno učitavati podešavanja
+
+Rezultat je @RESULT@.
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: Proces @EXECUTABLE@ se ne može pokrenuti
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Proces @EXECUTABLE@ se ne može pokrenuti i nije uspio.
+
+Broj greške vraćen ovim procesom je @ERRNO@.
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: Jedna ili više poruka se ne mogu proslijediti u dnevnik sustava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedna ili više poruka se ne mogu proslijediti u dnevnik sustava, usluge
+su pokrenute istovremeno s journalom. Ovo uobičajeno označava da
+implementacija dnevnika sustava ne može slijediti brzinu
+zahtjeva poruka.
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: Točka montiranja nije prazna
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Direktorij @WHERE@ je određen za točku montiranja (drugi redak u
+/etc/fstab ili Where= redak u datoteci systemd jedinice) i nije prazan.
+To ne utječe na montiranje, ali postojeće datoteke u ovom direktoriju
+postaju nedostupne. Kako bi vidjeli datoteke preko kojih je montirano,
+ručno montirajte osnovni datotečni sustav na drugu lokaciju.
+
+-- 24d8d4452573402496068381a6312df2
+Subject: Virtualni stroj ili spremnik su pokrenuti
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Virtualni stroj @NAME@ sa vodećim @LEADER@ PID-om je
+pokrenut i spreman je za korištenje.
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: Virtualni stroj ili spremnik su isključeni
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Virtualni stroj @NAME@ sa vodećim PID-om @LEADER@ je
+isključen.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: DNSSEC način je isključen, jer ga poslužitelj ne podržava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Usluga razrješavanja (systemd-resolved.service) je otkrila da
+podešeni DNS poslužitelj ne podržava DNSSEC, i DNSSEC, kao rezultat
+provjera je isključena.
+
+Ovaj događaj će zauzeti mjesto ako je DNSSEC=allow-downgrade podešen u
+resolved.conf i podešeni DNS poslužitelj je nekompatibilan s DNSSEC. Zapamtite
+da korištenje ovog načina dopušta povećanje DNSSEC napada, napadač bi mogao
+isključiti DNSSEC provjeru na sustavu umetanjem DNS odgovora u
+komunikacijski kanal što rezultira povećanjem napada poput ovog.
+
+Ovaj događaj bi mogao označavati da je DNS poslužitelj uistinu nekompatibilan s
+DNSSEC ili da je napadač uspješno izvršio takav napad.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: DNSSEC provjera neuspješna
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+DNS zahtjev ili snimak resursa nije prošao DNSSEC provjeru. To uobičajeno
+označava da je komunikacijski kanal mijenjan.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: DNSSEC pouzdano sidro je opozvano
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+A DNSSEC trust anchor has been revoked. A new trust anchor has to be
+configured, or the operating system needs to be updated, to provide an updated
+DNSSEC trust anchor.
index 30d76916ccf9ffbff5e50f7971fa48aa38ad8134..68e8c2572e5cef2d163c2875fb5aba0030bd8826 100644 (file)
@@ -51,7 +51,7 @@ Ne feledje, hogy csak a kérdéses szolgáltatás üzenetei kerültek eldobásra
  más szolgáltatások üzeneteit ez nem befolyásolja. 
 
 Az üzenetek eldobását vezérlő korlátok az /etc/systemd/journald.conf
-RateLimitInterval= és RateLimitBurst= beállításaival adhatók meg.
+RateLimitIntervalSec= és RateLimitBurst= beállításaival adhatók meg.
 Részletekért lásd a journald.conf(5) man oldalt.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 861b92b74abe79b9626fc163349b4b46011439bc..b6fca48221c8339ce0f0f6aacf71c13b28774b2a 100644 (file)
@@ -46,7 +46,7 @@ Solo i messaggi del servizio indicato sono stati
 eliminati, i messaggi degli altri servizi rimangono invariati.
 
 I limiti oltre i quali i messaggi si eliminano si configurano
-con RateLimitInterval= e RateLimitBurst= in
+con RateLimitIntervalSec= e RateLimitBurst= in
 /etc/systemd/journald.conf. Vedi journald.conf(5) per maggiori informazioni.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 3c3535a94c19f44c81a8992a0130b27633d62827..2fc6b60b1b02e29fba5a566024136a88616eb0ce 100644 (file)
@@ -55,7 +55,7 @@ Documentation: man:journald.conf(5)
 다른 서비스의 메시지에는 영향을 주지 않습니다.
 
 메시지 거절 제어 제한 값은 /etc/systemd/journald.conf 의
-RateLimitInterval= 변수와 RateLimitBurst= 변수로 설정합니다.
+RateLimitIntervalSec= 변수와 RateLimitBurst= 변수로 설정합니다.
 자세한 내용은 ournald.conf(5)를 살펴보십시오.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 6b8a31d8c4927183371a5b4eae3e62012eef81c0..d8059e93cded4687f940c4095436d46631eb3031 100644 (file)
@@ -1,7 +1,7 @@
 #  This file is part of systemd.
 #
 #  Copyright 2012 Lennart Poettering
-#  Copyright 2014, 2015 Piotr Drąg
+#  Copyright 2014, 2015, 2016 Piotr Drąg
 #
 #  systemd is free software; you can redistribute it and/or modify it
 #  under the terms of the GNU Lesser General Public License as published by
@@ -40,6 +40,22 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
 Systemowy proces dziennika został wyłączony i zamknął wszystkie obecnie
 aktywne pliki dziennika.
 
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Miejsce na dysku używane przez dziennik
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) obecnie używa @CURRENT_USE_PRETTY@.
+Maksymalnie może używać @MAX_USE_PRETTY@.
+Zostawianie co najmniej @DISK_KEEP_FREE_PRETTY@ wolnego (z obecnie dostępnego @DISK_AVAILABLE_PRETTY@ miejsca na dysku).
+Wymuszone ograniczenie użycia wynosi więc @LIMIT_PRETTY@, z czego @AVAILABLE_PRETTY@ jest nadal dostępne.
+
+Ograniczenia kontrolujące ilość miejsca na dysku używanego przez dziennik
+można konfigurować za pomocą ustawień SystemMaxUse=, SystemKeepFree=,
+SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize=
+w pliku /etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej
+informacji.
+
 -- a596d6fe7bfa4994828e72309e95d61e
 Subject: Ograniczono komunikaty z usługi
 Defined-By: systemd
@@ -53,7 +69,7 @@ Proszę zauważyć, że tylko komunikaty z danej usługi zostały pominięte. Ni
 to wpływu na komunikaty innych usług.
 
 Ograniczenia kontrolujące pomijanie komunikatów mogą być konfigurowane
-za pomocą opcji RateLimitInterval= i RateLimitBurst= w pliku
+za pomocą opcji RateLimitIntervalSec= i RateLimitBurst= w pliku
 /etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej informacji.
 
 -- e9bf28e6e834481bb6f48f548ad13606
@@ -72,7 +88,8 @@ Documentation: man:core(5)
 
 Proces @COREDUMP_PID@ (@COREDUMP_COMM@) uległ awarii i zrzucił plik core.
 
-Zwykle wskazuje to na błąd programistyczny w danym programie i powinno zostać zgłoszone jego producentowi jako błąd.
+Zwykle wskazuje to na błąd programistyczny w danym programie i powinno zostać
+zgłoszone jego producentowi jako błąd.
 
 -- 8d45620c1a4348dbb17410da57c60c66
 Subject: Utworzono nową sesję @SESSION_ID@ dla użytkownika @USER_ID@
@@ -259,3 +276,40 @@ Defined-By: systemd
 Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
 
 Maszyna wirtualna @NAME@ (PID prowadzący @LEADER@) została wyłączona.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Wyłączono tryb DNSSEC, ponieważ serwer go nie obsługuje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Usługa resolver (systemd-resolved.service) wykryła, że skonfigurowany serwer
+DNS nie obsługuje DNSSEC, w wyniku czego walidacja DNSSEC została wyłączona.
+
+To zdarzenie będzie miało miejsce, jeśli skonfigurowano DNSSEC=allow-downgrade
+w pliku resolved.conf, a skonfigurowany serwer DNS jest niezgodny z DNSSEC.
+Proszę zauważyć, że używanie tego trybu umożliwia ataki wyłączające DNSSEC,
+ponieważ atakujący będzie mógł wyłączyć walidację DNSSEC na komputerze przez
+umieszczenie odpowiednich odpowiedzi DNS w kanale komunikacji.
+
+To zdarzenie może wskazywać, że serwer DNS jest faktycznie niezgodny z DNSSEC,
+albo że atakującemu udało się upozorować atak tego typu.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: Walidacja DNSSEC się nie powiodła
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Zapytanie DNS lub ustawiony wpis zasobu nie przeszedł walidacji DNSSEC.
+Zwykle wskazuje to, że ktoś manipulował używanym kanałem komunikacji.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Unieważniono kotwicę zaufania DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Kotwica zaufania DNSSEC została unieważniona. Należy skonfigurować nową, albo
+system operacyjny musi zostać zaktualizowany, aby dostarczyć zaktualizowaną
+kotwicę zaufania DNSSEC.
index d9716e30f75be9806245f445c5e503d818502617..8b856e83557f14fb30e8f36133a92a1b5cf35368 100644 (file)
@@ -53,7 +53,7 @@ Note que apenas mensagens de um serviço em questão foram descartadas; outras
 mensagens dos serviços não foram afetadas.
 
 Os controles de limites de quando as mensagens são descartadas pode ser
-configurado com RateLimitInterval= e RateLimitBurst= no
+configurado com RateLimitIntervalSec= e RateLimitBurst= no
 /etc/systemd/journald.conf. Veja journald.conf(5) para detalhes.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index eedbb8aa9c44bcb7d8ced2d896610fe65a518d3e..e56dbe3acccad2f07cfbc231a8efe9646623757c 100644 (file)
@@ -76,7 +76,7 @@ Documentation: man:journald.conf(5)
 сообщения других служб не затронуты.
 
 Предел, после которого служба журнала начинает игнорировать сообщения,
-настраивается параметрами RateLimitInterval= и RateLimitBurst= в файле
+настраивается параметрами RateLimitIntervalSec= и RateLimitBurst= в файле
 /etc/systemd/journald.conf. Подробности смотрите на странице руководства
 journald.conf(5).
 
index cf700c477b2206a60c591a27ab2a5b6851b7ca80..cc689b795620aa13515c93413a077bc9b1857fd7 100644 (file)
@@ -52,7 +52,7 @@ Documentation: man:journald.conf(5)
 услуге нису захваћене овим.
 
 Ограничења која подешавају начин на који се поруке одбацују се могу подесити
-помоћу „RateLimitInterval=“ и „RateLimitBurst=“ параметара унутар датотеке
+помоћу „RateLimitIntervalSec=“ и „RateLimitBurst=“ параметара унутар датотеке
 /etc/systemd/journald.conf. Погледајте journald.conf(5) за појединости.
 
 -- e9bf28e6e834481bb6f48f548ad13606
index 38639109e47a63376ba3129986a5734e0021ea60..ed59fc92507e9fd69a44e229bb61b14001b45a77 100644 (file)
@@ -50,7 +50,7 @@ Documentation: man:journald.conf(5)
 请注意只有由有问题的服务传来的消息被丢弃,
 其它服务的消息不受影响。
 
-可以在 /etc/systemd/journald.conf 中设定 RateLimitInterval=
+可以在 /etc/systemd/journald.conf 中设定 RateLimitIntervalSec=
 以及 RateLimitBurst = 的值以控制丢弃信息的限制。
 请参见 journald.conf(5) 以了解详情。
 
index 027ffe44e5aea776c7baf43da037712d8121476a..aa5004db085c2ee3f9b603fa63b1f5ee1390b849 100644 (file)
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
 其他服務的訊息則不受影響。
 
 可以在 /etc/systemd/journald.conf 中設定
-RateLimitInterval= 以及 RateLimitBurst=
+RateLimitIntervalSec= 以及 RateLimitBurst=
 來控制當訊息要開始被丟棄時的限制。參見 journald.conf(5) 以獲得更多資訊。
 
 -- e9bf28e6e834481bb6f48f548ad13606
diff --git a/coccinelle/strjoina.cocci b/coccinelle/strjoina.cocci
new file mode 100644 (file)
index 0000000..a6236eb
--- /dev/null
@@ -0,0 +1,6 @@
+@@
+expression n, m;
+expression list s;
+@@
+- n = strjoina(m, s, NULL);
++ n = strjoina(m, s);
index cb14abda05cc9d3f7316f79d6a995f579b95967c..d6320d20227f6f6b6befd5f5b86aa3ccf02c2c3d 100644 (file)
@@ -336,7 +336,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE,
                 IFLA_BRIDGE_VLAN_INFO,
                 IFLA_BRPORT_PROXYARP,
                 IFLA_BRPORT_LEARNING_SYNC,
-                IFLA_BR_PRIORITY,
+                IFLA_BR_VLAN_DEFAULT_PVID,
                 NDA_IFINDEX,
                 IFA_FLAGS],
 [], [], [[
@@ -507,6 +507,14 @@ if test "x$enable_apparmor" != "xno"; then
 fi
 AM_CONDITIONAL(HAVE_APPARMOR, [test "$have_apparmor" = "yes"])
 
+have_adm_group=no
+AC_ARG_ENABLE(adm-group, AS_HELP_STRING([--disable-adm-group], [disable adm group]))
+AS_IF([test "x$enable_adm_group" != "xno"], [
+        AC_DEFINE(ENABLE_ADM_GROUP, 1, [Define if the ACL for adm group should be enabled])
+        have_adm_group=yes
+        M4_DEFINES="$M4_DEFINES -DENABLE_ADM_GROUP"
+])
+
 have_wheel_group=no
 AC_ARG_ENABLE(wheel-group, AS_HELP_STRING([--disable-wheel-group], [disable wheel group]))
 AS_IF([test "x$enable_wheel_group" != "xno"], [
@@ -889,7 +897,7 @@ AM_CONDITIONAL(HAVE_MICROHTTPD, [test "$have_microhttpd" = "yes"])
 have_libcurl=no
 AC_ARG_ENABLE(libcurl, AS_HELP_STRING([--disable-libcurl], [disable libcurl support]))
 if test "x$enable_libcurl" != "xno"; then
-        PKG_CHECK_MODULES(LIBCURL, [libcurl],
+        PKG_CHECK_MODULES(LIBCURL, [libcurl >= 7.32.0],
                 [AC_DEFINE(HAVE_LIBCURL, 1, [Define if libcurl is available])
                  have_libcurl=yes
                  M4_DEFINES="$M4_DEFINES -DHAVE_LIBCURL"],
@@ -1014,14 +1022,24 @@ fi
 AM_CONDITIONAL(ENABLE_LOGIND, [test "$have_logind" = "yes"])
 AS_IF([test "$have_logind" = "yes"], [ AC_DEFINE(HAVE_LOGIND, [1], [Logind support available]) ])
 
+AC_ARG_WITH([kill-user-processes],
+        [AS_HELP_STRING([--without-kill-user-processes], [Set logind's KillUserProcesses=no by default])])
+AS_IF([test "$with_kill_user_processes" != "no"],
+       [kill_user_processes=true
+        KILL_USER_PROCESSES=yes],
+       [kill_user_processes=false
+        KILL_USER_PROCESSES=no])
+AC_DEFINE_UNQUOTED(KILL_USER_PROCESSES, [$kill_user_processes], [Default KillUserProcesses setting])
+AC_SUBST(KILL_USER_PROCESSES)
+
 # ------------------------------------------------------------------------------
 have_machined=no
 AC_ARG_ENABLE(machined, AS_HELP_STRING([--disable-machined], [disable machine daemon]))
 if test "x$enable_machined" != "xno"; then
         have_machined=yes
+        AC_DEFINE(HAVE_MACHINED, [1], [systemd-machined is enabled])
 fi
 AM_CONDITIONAL(ENABLE_MACHINED, [test "$have_machined" = "yes"])
-AS_IF([test "$have_machined" = "yes"], [ AC_DEFINE(HAVE_MACHINED, [1], [Machined support available]) ])
 
 # ------------------------------------------------------------------------------
 have_importd=no
@@ -1131,6 +1149,7 @@ AS_IF([test "x$enable_resolved" != "xno"], [
 
         have_resolved=yes
         M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED"
+        AC_DEFINE(HAVE_RESOLVED, [1], [systemd-resolved is enabled])
 ])
 AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"])
 
@@ -1332,6 +1351,7 @@ if test "x$enable_myhostname" != "xno"; then
         AC_CHECK_FUNCS([gethostbyaddr gethostbyname gettimeofday inet_ntoa memset select socket strcspn strdup strerror strncasecmp strcasecmp strspn])
 
         have_myhostname=yes
+        AC_DEFINE(HAVE_MYHOSTNAME, [1], [nss-myhostname is enabled])
 fi
 AM_CONDITIONAL(HAVE_MYHOSTNAME, [test "$have_myhostname" = "yes"])
 
@@ -1552,106 +1572,108 @@ AC_OUTPUT
 AC_MSG_RESULT([
         $PACKAGE_NAME $VERSION
 
-        libcryptsetup:           ${have_libcryptsetup}
-        PAM:                     ${have_pam}
-        AUDIT:                   ${have_audit}
-        IMA:                     ${have_ima}
-        AppArmor:                ${have_apparmor}
-        SELinux:                 ${have_selinux}
-        SECCOMP:                 ${have_seccomp}
-        SMACK:                   ${have_smack}
-        ZLIB:                    ${have_zlib}
-        XZ:                      ${have_xz}
-        LZ4:                     ${have_lz4}
-        BZIP2:                   ${have_bzip2}
-        ACL:                     ${have_acl}
-        GCRYPT:                  ${have_gcrypt}
-        QRENCODE:                ${have_qrencode}
-        MICROHTTPD:              ${have_microhttpd}
-        GNUTLS:                  ${have_gnutls}
-        libcurl:                 ${have_libcurl}
-        libidn:                  ${have_libidn}
-        libiptc:                 ${have_libiptc}
-        ELFUTILS:                ${have_elfutils}
-        binfmt:                  ${have_binfmt}
-        vconsole:                ${have_vconsole}
-        quotacheck:              ${have_quotacheck}
-        tmpfiles:                ${have_tmpfiles}
-        sysusers:                ${have_sysusers}
-        firstboot:               ${have_firstboot}
-        randomseed:              ${have_randomseed}
-        backlight:               ${have_backlight}
-        rfkill:                  ${have_rfkill}
-        logind:                  ${have_logind}
-        machined:                ${have_machined}
-        importd:                 ${have_importd}
-        hostnamed:               ${have_hostnamed}
-        timedated:               ${have_timedated}
-        timesyncd:               ${have_timesyncd}
-        Default NTP servers:     ${NTP_SERVERS}
-        time epoch:              ${TIME_EPOCH}
-        localed:                 ${have_localed}
-        networkd:                ${have_networkd}
-        resolved:                ${have_resolved}
-        Default DNS servers:     ${DNS_SERVERS}
-        Default DNSSEC mode:     ${DEFAULT_DNSSEC_MODE}
-        coredump:                ${have_coredump}
-        polkit:                  ${have_polkit}
-        efi:                     ${have_efi}
-        gnuefi:                  ${have_gnuefi}
-        efi arch:                ${EFI_ARCH}
-        EFI machine type:        ${EFI_MACHINE_TYPE_NAME}
-        EFI CC                   ${EFI_CC}
-        EFI libdir:              ${EFI_LIB_DIR}
-        EFI ldsdir:              ${EFI_LDS_DIR}
-        EFI includedir:          ${EFI_INC_DIR}
-        kmod:                    ${have_kmod}
-        xkbcommon:               ${have_xkbcommon}
-        blkid:                   ${have_blkid}
-        libmount:                ${have_libmount}
-        dbus:                    ${have_dbus}
-        nss-myhostname:          ${have_myhostname}
-        hwdb:                    ${enable_hwdb}
-        tpm:                     ${have_tpm}
-        kdbus:                   ${have_kdbus}
-        Python:                  ${have_python}
-        man pages:               ${have_manpages}
-        test coverage:           ${have_coverage}
-        Split /usr:              ${enable_split_usr}
-        SysV compatibility:      ${SYSTEM_SYSV_COMPAT}
-        utmp/wtmp support:       ${have_utmp}
-        ldconfig support:        ${enable_ldconfig}
-        hibernate support:       ${enable_hibernate}
-        extra debugging:         ${enable_debug}
-        tests:                   ${enable_tests}
-
-        prefix:                  ${prefix}
-        rootprefix:              ${with_rootprefix}
-        sysconf dir:             ${sysconfdir}
-        datarootdir:             ${datarootdir}
-        includedir:              ${includedir}
-        lib dir:                 ${libdir}
-        rootlib dir:             ${with_rootlibdir}
-        SysV init scripts:       ${SYSTEM_SYSVINIT_PATH}
-        SysV rc?.d directories:  ${SYSTEM_SYSVRCND_PATH}
-        Build Python:            ${PYTHON}
-        PAM modules dir:         ${with_pamlibdir}
-        PAM configuration dir:   ${with_pamconfdir}
-        D-Bus policy dir:        ${with_dbuspolicydir}
-        D-Bus session dir:       ${with_dbussessionservicedir}
-        D-Bus system dir:        ${with_dbussystemservicedir}
-        Bash completions dir:    ${with_bashcompletiondir}
-        Zsh completions dir:     ${with_zshcompletiondir}
-        Extra start script:      ${RC_LOCAL_SCRIPT_PATH_START}
-        Extra stop script:       ${RC_LOCAL_SCRIPT_PATH_STOP}
-        Wheel group:             ${have_wheel_group}
-        Debug shell:             ${SUSHELL} @ ${DEBUGTTY}
-        TTY GID:                 ${TTY_GID}
-        Maximum System UID:      ${SYSTEM_UID_MAX}
-        Maximum System GID:      ${SYSTEM_GID_MAX}
-        Certificate root:        ${CERTIFICATEROOT}
-
-        CFLAGS:                  ${OUR_CFLAGS} ${CFLAGS}
-        CPPFLAGS:                ${OUR_CPPFLAGS} ${CPPFLAGS}
-        LDFLAGS:                 ${OUR_LDFLAGS} ${LDFLAGS}
+        libcryptsetup:                     ${have_libcryptsetup}
+        PAM:                               ${have_pam}
+        AUDIT:                             ${have_audit}
+        IMA:                               ${have_ima}
+        AppArmor:                          ${have_apparmor}
+        SELinux:                           ${have_selinux}
+        SECCOMP:                           ${have_seccomp}
+        SMACK:                             ${have_smack}
+        ZLIB:                              ${have_zlib}
+        XZ:                                ${have_xz}
+        LZ4:                               ${have_lz4}
+        BZIP2:                             ${have_bzip2}
+        ACL:                               ${have_acl}
+        GCRYPT:                            ${have_gcrypt}
+        QRENCODE:                          ${have_qrencode}
+        MICROHTTPD:                        ${have_microhttpd}
+        GNUTLS:                            ${have_gnutls}
+        libcurl:                           ${have_libcurl}
+        libidn:                            ${have_libidn}
+        libiptc:                           ${have_libiptc}
+        ELFUTILS:                          ${have_elfutils}
+        binfmt:                            ${have_binfmt}
+        vconsole:                          ${have_vconsole}
+        quotacheck:                        ${have_quotacheck}
+        tmpfiles:                          ${have_tmpfiles}
+        sysusers:                          ${have_sysusers}
+        firstboot:                         ${have_firstboot}
+        randomseed:                        ${have_randomseed}
+        backlight:                         ${have_backlight}
+        rfkill:                            ${have_rfkill}
+        logind:                            ${have_logind}
+        Default KillUserProcesses setting: ${KILL_USER_PROCESSES}
+        machined:                          ${have_machined}
+        importd:                           ${have_importd}
+        hostnamed:                         ${have_hostnamed}
+        timedated:                         ${have_timedated}
+        timesyncd:                         ${have_timesyncd}
+        Default NTP servers:               ${NTP_SERVERS}
+        time epoch:                        ${TIME_EPOCH}
+        localed:                           ${have_localed}
+        networkd:                          ${have_networkd}
+        resolved:                          ${have_resolved}
+        Default DNS servers:               ${DNS_SERVERS}
+        Default DNSSEC mode:               ${DEFAULT_DNSSEC_MODE}
+        coredump:                          ${have_coredump}
+        polkit:                            ${have_polkit}
+        efi:                               ${have_efi}
+        gnuefi:                            ${have_gnuefi}
+        efi arch:                          ${EFI_ARCH}
+        EFI machine type:                  ${EFI_MACHINE_TYPE_NAME}
+        EFI CC                             ${EFI_CC}
+        EFI libdir:                        ${EFI_LIB_DIR}
+        EFI ldsdir:                        ${EFI_LDS_DIR}
+        EFI includedir:                    ${EFI_INC_DIR}
+        kmod:                              ${have_kmod}
+        xkbcommon:                         ${have_xkbcommon}
+        blkid:                             ${have_blkid}
+        libmount:                          ${have_libmount}
+        dbus:                              ${have_dbus}
+        nss-myhostname:                    ${have_myhostname}
+        hwdb:                              ${enable_hwdb}
+        tpm:                               ${have_tpm}
+        kdbus:                             ${have_kdbus}
+        Python:                            ${have_python}
+        man pages:                         ${have_manpages}
+        test coverage:                     ${have_coverage}
+        Split /usr:                        ${enable_split_usr}
+        SysV compatibility:                ${SYSTEM_SYSV_COMPAT}
+        utmp/wtmp support:                 ${have_utmp}
+        ldconfig support:                  ${enable_ldconfig}
+        hibernate support:                 ${enable_hibernate}
+        extra debugging:                   ${enable_debug}
+        tests:                             ${enable_tests}
+
+        prefix:                            ${prefix}
+        rootprefix:                        ${with_rootprefix}
+        sysconf dir:                       ${sysconfdir}
+        datarootdir:                       ${datarootdir}
+        includedir:                        ${includedir}
+        lib dir:                           ${libdir}
+        rootlib dir:                       ${with_rootlibdir}
+        SysV init scripts:                 ${SYSTEM_SYSVINIT_PATH}
+        SysV rc?.d directories:            ${SYSTEM_SYSVRCND_PATH}
+        Build Python:                      ${PYTHON}
+        PAM modules dir:                   ${with_pamlibdir}
+        PAM configuration dir:             ${with_pamconfdir}
+        D-Bus policy dir:                  ${with_dbuspolicydir}
+        D-Bus session dir:                 ${with_dbussessionservicedir}
+        D-Bus system dir:                  ${with_dbussystemservicedir}
+        Bash completions dir:              ${with_bashcompletiondir}
+        Zsh completions dir:               ${with_zshcompletiondir}
+        Extra start script:                ${RC_LOCAL_SCRIPT_PATH_START}
+        Extra stop script:                 ${RC_LOCAL_SCRIPT_PATH_STOP}
+        Adm group:                         ${have_adm_group}
+        Wheel group:                       ${have_wheel_group}
+        Debug shell:                       ${SUSHELL} @ ${DEBUGTTY}
+        TTY GID:                           ${TTY_GID}
+        Maximum System UID:                ${SYSTEM_UID_MAX}
+        Maximum System GID:                ${SYSTEM_GID_MAX}
+        Certificate root:                  ${CERTIFICATEROOT}
+
+        CFLAGS:   ${OUR_CFLAGS} ${CFLAGS}
+        CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
+        LDFLAGS:  ${OUR_LDFLAGS} ${LDFLAGS}
 ])
index 4f04539e12fc7bc156e2315fe76a5b8f8c7d8b7e..547db3a2ca280f928353f0cd5242ea51984d800c 100644 (file)
@@ -127,6 +127,13 @@ evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLati
  EVDEV_ABS_35=76:1815:22
  EVDEV_ABS_36=131:1330:30
 
+# Dell XPS15 9550
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnXPS159550*
+ EVDEV_ABS_00=::41
+ EVDEV_ABS_01=::43
+ EVDEV_ABS_35=::41
+ EVDEV_ABS_36=::43
+
 #########################################
 # Google
 #########################################
index 46013d344934abc813239fa21f7247d86e8c76b3..fd49b034933e56d71296ba025d78c843521053d0 100644 (file)
@@ -496,12 +496,20 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHP*ProBook*4*:pvr*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPZBook*:pvr*
  KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
 
+# HP Folio 1040g2
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:pvr*
+ KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
+ KEYBOARD_KEY_d8=!f23                                   # touchpad off
+ KEYBOARD_KEY_d9=!f22                                   # touchpad on
+
 # HP ProBook 6555b
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:*
  KEYBOARD_KEY_b2=www                                    # Earth
 
 # HP ProBook 440 G3
 evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*440*G3*
+# HP ProBook 640 G2
+evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*640*G2*
  KEYBOARD_KEY_85=unknown                                # lid close; also reported via special evdev
  KEYBOARD_KEY_f8=unknown                                # rf kill; also reported via special evdev
 
index 54ace7cbc159d59c537de1614a9aa9fe6dc7c3f6..a5b39dc41e787c51bcfba43bd6bbf03ff1f968b2 100644 (file)
@@ -131,6 +131,14 @@ mouse:usb:v413cp3012:name:Dell Dell USB Optical Mouse:
 mouse:usb:v046dpc063:name:DELL DELL USB Laser Mouse:
  MOUSE_DPI=1000@125
 
+##########################################
+# Dynex
+#########################################
+
+# Dynex Wired Optical Mouse (DX-WMSE2)
+mouse:usb:v0461p4d46:name:USB Optical Mouse:
+ MOUSE_DPI=1000@125
+
 ##########################################
 # Fujitsu Siemens
 ##########################################
@@ -419,6 +427,14 @@ mouse:usb:v22d4p1308:name:Laview Technology Mionix Avior 7000:
  MOUSE_DPI=400@1000 *1600@1000 7000@1000
  MOUSE_WHEEL_CLICK_ANGLE=15
 
+##########################################
+# MODECOM
+##########################################
+
+# MODECOM MC-WM4 Wireless Optical Mouse
+mouse:usb:v0e8fp00a7:name:DaKai 2.4G RX:
+ MOUSE_DPI=*800@126 1600@126
+
 ##########################################
 # Oklick
 ##########################################
@@ -443,3 +459,27 @@ mouse:usb:v1532p0042:name:Razer Razer Abyssus:
 mouse:usb:v1e7dp2c2e:name:ROCCAT ROCCAT Lua:
  MOUSE_DPI=250@125 500@125 1000@125 1250@125 1500@125 1750@125 2000@125 250@250 500@250 1000@250 1250@250 1500@250 1750@250 2000@250 250@500 500@500 1000@500 1250@500 1500@500 1750@500 2000@500 250@1000 500@1000 *1000@1000 1250@1000 1500@1000 1750@1000 2000@1000
  MOUSE_WHEEL_CLICK_ANGLE=15
+
+##########################################
+# Sharkoon
+##########################################
+
+# Sharkoon Shark Force Gaming Mouse
+mouse:usb:v093ap2521:name:USB OPTICAL MOUSE:
+ MOUSE_DPI=*1000@125 1600@125 600@125
+
+##########################################
+# SteelSeries
+##########################################
+
+# SteelSeries Sensei Raw
+mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:
+ MOUSE_DPI=1000@1022
+
+##########################################
+# Trust
+##########################################
+
+# Trust illuminated mouse gxt 152
+mouse:usb:v145fp01ac:name:HID-compliant Mouse Trust Gaming Mouse:
+ MOUSE_DPI=*800@528 1200@537 1600@536 2400@521
index a0a497b46760b081bd1f41f8abd71a8969890b3e..2064a96523e0b5dfeeb6b5519977fd8230f30fbd 100644 (file)
 
     <para>These files configure the behavior of
     <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-    a handler for core dumps invoked by the kernel.</para>
+    a handler for core dumps invoked by the kernel. Whether <command>systemd-coredump</command> is used
+    is determined by the kernel's
+    <varname>kernel.core_pattern</varname> <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    setting. See
+    <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    and
+    <citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    pages for the details.</para>
   </refsect1>
 
   <xi:include href="standard-conf.xml" xpointer="main-conf" />
index b6125cb5c7f6fa2a5318bb39e8e033d3e231cd95..485c66225eb9ba1ce77e273d0c8650235a3e8186 100644 (file)
       functionality of the init system, it is recommended not to
       execute them when run as new-style service.</para>
 
-      <para>Note that new-style init systems guarantee execution of
-      daemon processes in a clean process context: it is guaranteed
-      that the environment block is sanitized, that the signal
-      handlers and mask is reset and that no left-over file
-      descriptors are passed. Daemons will be executed in their own
-      session, with standard input/output/error connected to
-      <filename>/dev/null</filename> unless otherwise configured. The
-      umask is reset.
+      <para>Note that new-style init systems guarantee execution of daemon processes in a clean process context: it is
+      guaranteed that the environment block is sanitized, that the signal handlers and mask is reset and that no
+      left-over file descriptors are passed. Daemons will be executed in their own session, with standard input
+      connected to <filename>/dev/null</filename> and standard output/error connected to the
+      <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      logging service, unless otherwise configured. The umask is reset.
       </para>
 
       <para>It is recommended for new-style daemons to implement the
         bus-activatable by supplying a D-Bus service activation
         configuration file. This has multiple advantages: your daemon
         may be started lazily on-demand; it may be started in parallel
-        to other daemons requiring it -- which maximizes
+        to other daemons requiring it  which maximizes
         parallelization and boot-up speed; your daemon can be
         restarted on failure without losing any bus requests, as the
         bus queues requests for activatable services. See below for
index b281f26b45eb68bb270addc823b9bff52f8d077d..3efe6ef62aacf0e34c0db7a619be5016c655a15f 100644 (file)
               </listitem>
             </varlistentry>
 
+            <varlistentry>
+              <term>
+                <option>short-unix</option>
+              </term>
+              <listitem>
+                <para>is very similar, but shows seconds passed since January 1st 1970 UTC instead of wallclock
+                timestamps ("UNIX time"). The time is shown with microsecond accuracy.</para>
+              </listitem>
+            </varlistentry>
+
             <varlistentry>
               <term>
                 <option>verbose</option>
         (UTC).</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--no-hostname</option></term>
+
+        <listitem><para>Don't show the hostname field of log messages originating from the local host. This switch only
+        has an effect on the <option>short</option> family of output modes (see above).</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>-x</option></term>
         <term><option>--catalog</option></term>
         space they use falls below the specified size (specified with
         the usual <literal>K</literal>, <literal>M</literal>,
         <literal>G</literal> and <literal>T</literal> suffixes), or all
-        journal files contain no data older than the specified
+        archived journal files contain no data older than the specified
         timespan (specified with the usual <literal>s</literal>,
-        <literal>min</literal>, <literal>h</literal>,
+        <literal>m</literal>, <literal>h</literal>,
         <literal>days</literal>, <literal>months</literal>,
         <literal>weeks</literal> and <literal>years</literal> suffixes),
         or no more than the specified number of separate journal files
index a9690e8138022d5722ed38bd73a1de829527dbd2..3964cd6bc52cce77866efba4ed106cc1c6c7bbb4 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><varname>RateLimitInterval=</varname></term>
+        <term><varname>RateLimitIntervalSec=</varname></term>
         <term><varname>RateLimitBurst=</varname></term>
 
         <listitem><para>Configures the rate limiting that is applied
         to all messages generated on the system. If, in the time
-        interval defined by <varname>RateLimitInterval=</varname>,
+        interval defined by <varname>RateLimitIntervalSec=</varname>,
         more messages than specified in
         <varname>RateLimitBurst=</varname> are logged by a service,
         all further messages within the interval are dropped until the
         per-service, so that two services which log do not interfere
         with each other's limits. Defaults to 1000 messages in 30s.
         The time specification for
-        <varname>RateLimitInterval=</varname> may be specified in the
+        <varname>RateLimitIntervalSec=</varname> may be specified in the
         following units: <literal>s</literal>, <literal>min</literal>,
         <literal>h</literal>, <literal>ms</literal>,
         <literal>us</literal>. To turn off any kind of rate limiting,
index 42d5e006bb77736a91572ff6625cb88621b4a205..9c04849f66b97bc09a887e6bac99e709ad7fb94f 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>systemd.default_timeout_start_sec=</varname></term>
+
+        <listitem>
+          <para>Overwrites the default start job timeout <varname>DefaultTimeoutStartSec=</varname> at boot. For details,
+          see <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>modules-load=</varname></term>
         <term><varname>rd.modules-load=</varname></term>
index f41acc6a1b8bc9340632f8fd5aee539d48871cbc..fb51740503f87dbfe0a19262226a482dac999378 100644 (file)
         shown.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--value</option></term>
+
+        <listitem>
+          <para>When printing properties with <command>show</command>,
+          only print the value, and skip the property name and
+          <literal>=</literal>.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>-a</option></term>
         <term><option>--all</option></term>
         This allows users who are not logged in to run long-running
         services. Takes one or more user names or numeric UIDs as
         argument. If no argument is specified, enables/disables
-        lingering for the user of the session of the caller.
+        lingering for the user of the session of the caller.</para>
+
+        <para>See also <varname>KillUserProcesses=</varname> setting in
+        <citerefentry><refentrytitle>logind.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
         </para></listitem>
       </varlistentry>
 
     otherwise.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Querying user status</title>
+
+      <programlisting>$ loginctl user-status
+fatima (1005)
+           Since: Sat 2016-04-09 14:23:31 EDT; 54min ago
+           State: active
+        Sessions: 5 *3
+            Unit: user-1005.slice
+                  ├─user@1005.service
+                    ...
+                  ├─session-3.scope
+                    ...
+                  └─session-5.scope
+                    ├─3473 login -- fatima
+                    └─3515 -zsh
+
+Apr 09 14:40:30 laptop login[2325]: pam_unix(login:session):
+                       session opened for user fatima by LOGIN(uid=0)
+Apr 09 14:40:30 laptop login[2325]: LOGIN ON tty3 BY fatima
+</programlisting>
+
+      <para>There are two sessions, 3 and 5. Session 3 is a graphical session,
+      marked with a star. The tree of processing including the two corresponding
+      scope units and the user manager unit are shown.</para>
+    </example>
+  </refsect1>
+
   <xi:include href="less-variables.xml" />
 
   <refsect1>
index 597759e33a9dd4822c7f0bdb9597bf264f27c0f5..6ba35414befa8f2a8ac2b6fab5dccd2a0988deb6 100644 (file)
       <varlistentry>
         <term><varname>KillUserProcesses=</varname></term>
 
-        <listitem><para>Takes a boolean argument. Configures whether
-        the processes of a user should be killed when the user
-        completely logs out (i.e. after the user's last session
-        ended). Defaults to <literal>no</literal>.</para>
-
-        <para>Note that setting <varname>KillUserProcesses=1</varname>
+        <listitem><para>Takes a boolean argument. Configures whether the processes of a
+        user should be killed when the user logs out. If true, the scope unit
+        corresponding to the session and all processes inside that scope will be
+        terminated. If false, the scope is "abandoned", see
+        <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+        and processes are not killed. Defaults to <literal>yes</literal>,
+        but see the options <varname>KillOnlyUsers=</varname> and
+        <varname>KillExcludeUsers=</varname> below.</para>
+
+        <para>In addition to session processes, user process may run under the user
+        manager unit <filename>user@.service</filename>. Depending on the linger
+        settings, this may allow users to run processes independent of their login
+        sessions. See the description of <command>enable-linger</command> in
+        <citerefentry><refentrytitle>loginctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+        </para>
+
+        <para>Note that setting <varname>KillUserProcesses=yes</varname>
         will break tools like
-        <citerefentry project='die-net'><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
+        <citerefentry project='die-net'><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        and
+        <citerefentry project='die-net'><refentrytitle>tmux</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+        unless they are moved out of the session scope. See example in
+        <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>KillOnlyUsers=</varname></term>
         <term><varname>KillExcludeUsers=</varname></term>
 
-        <listitem><para>These settings take space-separated lists of
-        usernames that influence the effect of
-        <varname>KillUserProcesses=</varname>. If not empty, only
-        processes of users listed in <varname>KillOnlyUsers=</varname>
-        will be killed when they log out entirely. Processes of users
-        listed in <varname>KillExcludeUsers=</varname> are excluded
-        from being killed. <varname>KillExcludeUsers=</varname>
-        defaults to <literal>root</literal> and takes precedence over
-        <varname>KillOnlyUsers=</varname>, which defaults to the empty
-        list.</para></listitem>
+        <listitem><para>These settings take space-separated lists of usernames that override
+        the <varname>KillUserProcesses=</varname> setting. A user name may be added to
+        <varname>KillExcludeUsers=</varname> to exclude the processes in the session scopes of
+        that user from being killed even if <varname>KillUserProcesses=yes</varname> is set. If
+        <varname>KillExcludeUsers=</varname> is not set, the <literal>root</literal> user is
+        excluded by default. <varname>KillExcludeUsers=</varname> may be set to an empty value
+        to override this default. If a user is not excluded, <varname>KillOnlyUsers=</varname>
+        is checked next. If this setting is specified, only the session scopes of those users
+        will be killed. Otherwise, users are subject to the
+        <varname>KillUserProcesses=yes</varname> setting.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 967ca01470cf6443ec7f80e9bb99572f8e49285e..4b7f9a0391817b71b250b59e155a6dd67b665908 100644 (file)
 
         <para>When listing VM or container images, do not suppress
         images beginning in a dot character
-        (<literal>.</literal>).</para></listitem>
+        (<literal>.</literal>).</para>
+
+        <para>When cleaning VM or container images, remove all images, not just hidden ones.</para></listitem>
+      </varlistentry>
+
+       <varlistentry>
+        <term><option>--value</option></term>
+
+        <listitem><para>When printing properties with <command>show</command>, only print the value,
+        and skip the property name and <literal>=</literal>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
-         <term><option>--setenv=</option></term>
+        <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+        <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
 
-         <listitem><para>When used with the <command>shell</command>
-         command, sets an environment variable to pass to the executed
-         shell. Takes a pair of environment variable name and value,
-         separated by <literal>=</literal> as argument. This switch
-         may be used multiple times to set multiple environment
-         variables. Note that this switch is not supported for the
-         <command>login</command> command (see
-         below).</para></listitem>
+         <listitem><para>When used with the <command>shell</command> command, sets an environment
+         variable to pass to the executed shell. Takes an environment variable name and value,
+         separated by <literal>=</literal>. This switch may be used multiple times to set multiple
+         environment variables. Note that this switch is not supported for the
+         <command>login</command> command (see below).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--read-only</option></term>
 
         <listitem><para>When used with <command>bind</command>, applies
-        a read-only bind mount.</para></listitem>
-      </varlistentry>
+        a read-only bind mount.</para>
 
+        <para>When used with <command>clone</command>, <command>import-raw</command> or <command>import-tar</command> a
+        read-only container or VM image is created.</para></listitem>
+      </varlistentry>
 
       <varlistentry>
         <term><option>-n</option></term>
       <varlistentry>
         <term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
 
-        <listitem><para>Clones a container or VM image. The
-        arguments specify the name of the image to clone and the name
-        of the newly cloned image. Note that plain directory container
-        images are cloned into subvolume images with this command.
-        Note that cloning a container or VM image is optimized for
-        btrfs file systems, and might not be efficient on others, due
-        to file system limitations.</para>
+        <listitem><para>Clones a container or VM image. The arguments specify the name of the image to clone and the
+        name of the newly cloned image. Note that plain directory container images are cloned into btrfs subvolume
+        images with this command, if the underlying file system supports this.  Note that cloning a container or VM
+        image is optimized for btrfs file systems, and might not be efficient on others, due to file system
+        limitations.</para>
 
         <para>Note that this command leaves host name, machine ID and
         all other settings that could identify the instance
         unmodified. The original image and the cloned copy will hence
         share these credentials, and it might be necessary to manually
-        change them in the copy.</para></listitem>
+        change them in the copy.</para>
+
+        <para>If combined with the <option>--read-only</option> switch a read-only cloned image is
+        created.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         itself.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><command>clean</command></term>
+
+        <listitem><para>Remove hidden VM or container images (or all). This command removes all hidden machine images
+        from <filename>/var/lib/machines</filename>, i.e. those whose name begins with a dot. Use <command>machinectl
+        list-images --all</command> to see a list of all machine images, including the hidden ones.</para>
+
+        <para>When combined with the <option>--all</option> switch removes all images, not just hidden ones. This
+        command effectively empties <filename>/var/lib/machines</filename>.</para>
+
+        <para>Note that commands such as <command>machinectl pull-tar</command> or <command>machinectl
+        pull-raw</command> usually create hidden, read-only, unmodified machine images from the downloaded image first,
+        before cloning a writable working copy of it, in order to avoid duplicate downloads in case of images that are
+        reused multiple times. Use <command>machinectl clean</command> to remove old, hidden images created this
+        way.</para></listitem>
+      </varlistentry>
+
     </variablelist></refsect2>
 
     <refsect2><title>Image Transfer Commands</title><variablelist>
diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
new file mode 100644 (file)
index 0000000..5166e05
--- /dev/null
@@ -0,0 +1,111 @@
+<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2014 Vinay Kulkarni
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="networkd.conf" conditional='ENABLE_NETWORKD'
+    xmlns:xi="http://www.w3.org/2001/XInclude">
+  <refentryinfo>
+    <title>networkd.conf</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Vinay</firstname>
+        <surname>Kulkarni</surname>
+        <email>kulkarniv@vmware.com</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>networkd.conf</refentrytitle>
+    <manvolnum>5</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>networkd.conf</refname>
+    <refname>networkd.conf.d</refname>
+    <refpurpose>Global Network configuration files</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <para><filename>/etc/systemd/networkd.conf</filename></para>
+    <para><filename>/etc/systemd/networkd.conf.d/*.conf</filename></para>
+    <para><filename>/usr/lib/systemd/networkd.conf.d/*.conf</filename></para>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>These configuration files control global network parameters.
+    For e.g. DHCP Unique Identifier (DUID).</para>
+
+  </refsect1>
+
+  <xi:include href="standard-conf.xml" xpointer="main-conf" />
+
+  <refsect1>
+    <title>[DUID] Section Options</title>
+
+    <para>This section configures the DHCP Unique Identifier (DUID) value used by DHCP
+    protocol. DHCPv6 client protocol sends the DHCP Unique Identifier and the interface
+    Identity Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6
+    address. DHCPv4 client protocol sends IAID and DUID to the DHCP server when acquiring
+    a dynamic IPv4 address if <option>ClientIdentifier=duid</option>. IAID and DUID allows
+    a DHCP server to uniquely identify the machine and the interface requesting a DHCP IP.
+    To configure IAID and ClientIdentifier, see <citerefentry><refentrytitle>systemd.network
+    </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+    <para>The DUID value specified here overrides the DUID that systemd-networkd
+    generates using the machine-id from the <filename>/etc/machine-id</filename> file.
+    To configure DUID per-network, see <citerefentry><refentrytitle>systemd.network
+    </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+    <para>The configured DHCP DUID should conform to the specification in 
+    <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
+    <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>. To configure IAID, see
+    <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum>
+    </citerefentry>.</para>
+
+    <para>The following options are available in <literal>[DUID]</literal> section:</para>
+
+    <variablelist class='network-directives'>
+
+      <varlistentry>
+        <term><varname>RawData=</varname></term>
+        <listitem><para>Specifies the DUID bytes as a single newline-terminated, hexadecimal
+        string, with each byte separated by a ':'.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+      <title>See Also</title>
+      <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      </para>
+  </refsect1>
+
+</refentry>
index f8837745ae652f196ed8724b5b84f0f15e5fe020..a920ec334f06207efe4f1e081e1b48dc046f3f79 100644 (file)
       is on the local loopback) and the IPv6 address ::1 (which is the
       local host).</para></listitem>
 
-      <listitem><para>The hostname <literal>localhost</literal> (as well as any hostname ending in
-      <literal>.localhost</literal>, <literal>.localdomain</literal> or equal to <literal>localdomain</literal>) is
-      resolved to the IP addresses 127.0.0.1 and ::1.</para></listitem>
+      <listitem><para>The hostnames <literal>localhost</literal> and
+      <literal>localhost.localdomain</literal> (as well as any hostname
+      ending in <literal>.localhost</literal> or <literal>.localhost.localdomain</literal>)
+      are resolved to the IP addresses 127.0.0.1 and ::1.</para></listitem>
 
       <listitem><para>The hostname <literal>gateway</literal> is
       resolved to all current default routing gateway addresses,
index 9234f4233eeb437c733e9e1a8972d89069cd8db6..8c9b39fe5e2b1c511e7c587dcf8367e943e706a9 100644 (file)
@@ -97,7 +97,7 @@
     <constant>SD_EVENT_PRIORITY_IDLE</constant> (100) may be used to
     indicate event sources that shall be dispatched early, normally or
     late. It is recommended to specify priorities based on these
-    definitions, and relative to them -- however, the full 64bit
+    definitions, and relative to them  however, the full 64bit
     signed integer range is available for ordering event
     sources.</para>
 
index 3b27444f8d777a6407d88ce051bd0f7543a7d1df..98415d53fd16f6fbcde1ce3c5c3e0897d8ef4b1d 100644 (file)
     <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     and
     <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-    Matches are of the form <literal>FIELD=value</literal>, where the
-    field part is a short uppercase string consisting only of 0–9, A–Z
-    and the underscore. It may not begin with two underscores or be
-    the empty string. The value part may be any value, including
-    binary. If a match is applied, only entries with this field set
+    Parameter <parameter>data</parameter> must be of the form
+    <literal><replaceable>FIELD</replaceable>=<replaceable>value</replaceable></literal>,
+    where the <replaceable>FIELD</replaceable> part is a short uppercase string consisting only
+    of 0–9, A–Z and the underscore; it may not begin with two underscores or be the empty
+    string. The <replaceable>value</replaceable> part may be anything, including binary. Parameter
+    <parameter>size</parameter> specifies the number of bytes in <parameter>data</parameter>
+    (i.e. the length of <replaceable>FIELD</replaceable>, plus one, plus the length of
+    <replaceable>value</replaceable>). Parameter <parameter>size</parameter> may also be
+    specified as <constant>0</constant>, in which case <parameter>data</parameter>
+    must be a <constant>NUL</constant>-terminated string, and the bytes before the terminating
+    zero are used as the match.</para>
+
+    <para>If a match is applied, only entries with this field set
     will be iterated. Multiple matches may be active at the same time:
     If they apply to different fields, only entries with both fields
     set like this will be iterated. If they apply to the same fields,
index 1f25d068d71542797b7693e96762af28747841fa..908ee7db16e6a4401ba768df61cf34a408ac3ca2 100644 (file)
     <function>sd_journal_enumerate_unique()</function>. This threshold
     is a hint only: it indicates that the client program is interested
     only in the initial parts of the data fields, up to the threshold
-    in size -- but the library might still return larger data objects.
+    in size  but the library might still return larger data objects.
     That means applications should not rely exclusively on this
     setting to limit the size of the data fields returned, but need to
     apply a explicit size limit on the returned data as well. This
index fef453f8dcbf53910c9b766a9152728aaa8f67ba..153af2387f5a47d068fa1dcf8da02228b3b479c3 100644 (file)
   <refnamediv>
     <refname>sd_journal_open</refname>
     <refname>sd_journal_open_directory</refname>
+    <refname>sd_journal_open_directory_fd</refname>
     <refname>sd_journal_open_files</refname>
-    <refname>sd_journal_open_container</refname>
+    <refname>sd_journal_open_files_fd</refname>
     <refname>sd_journal_close</refname>
     <refname>sd_journal</refname>
     <refname>SD_JOURNAL_LOCAL_ONLY</refname>
     <refname>SD_JOURNAL_RUNTIME_ONLY</refname>
     <refname>SD_JOURNAL_SYSTEM</refname>
     <refname>SD_JOURNAL_CURRENT_USER</refname>
+    <refname>SD_JOURNAL_OS_ROOT</refname>
     <refpurpose>Open the system journal for reading</refpurpose>
   </refnamediv>
 
         <paramdef>int <parameter>flags</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_journal_open_directory_fd</function></funcdef>
+        <paramdef>sd_journal **<parameter>ret</parameter></paramdef>
+        <paramdef>int <parameter>fd</parameter></paramdef>
+        <paramdef>int <parameter>flags</parameter></paramdef>
+      </funcprototype>
+
       <funcprototype>
         <funcdef>int <function>sd_journal_open_files</function></funcdef>
         <paramdef>sd_journal **<parameter>ret</parameter></paramdef>
       </funcprototype>
 
       <funcprototype>
-        <funcdef>int <function>sd_journal_open_container</function></funcdef>
+        <funcdef>int <function>sd_journal_open_files_fd</function></funcdef>
         <paramdef>sd_journal **<parameter>ret</parameter></paramdef>
-        <paramdef>const char *<parameter>machine</parameter></paramdef>
+        <paramdef>int <parameter>fds[]</parameter></paramdef>
+        <paramdef>unsigned <parameter>n_fds</parameter></paramdef>
         <paramdef>int <parameter>flags</parameter></paramdef>
       </funcprototype>
 
     <constant>SD_JOURNAL_CURRENT_USER</constant> are specified, all
     journal file types will be opened.</para>
 
-    <para><function>sd_journal_open_directory()</function> is similar
-    to <function>sd_journal_open()</function> but takes an absolute
-    directory path as argument. All journal files in this directory
-    will be opened and interleaved automatically. This call also takes
-    a flags argument, but it must be passed as 0 as no flags are
-    currently understood for this call.</para>
-
-    <para><function>sd_journal_open_files()</function> is similar to
-    <function>sd_journal_open()</function> but takes a
-    <constant>NULL</constant>-terminated list of file paths to open.
-    All files will be opened and interleaved automatically. This call
-    also takes a flags argument, but it must be passed as 0 as no
-    flags are currently understood for this call. Please note that in
-    the case of a live journal, this function is only useful for
-    debugging, because individual journal files can be rotated at any
-    moment, and the opening of specific files is inherently
-    racy.</para>
-
-    <para><function>sd_journal_open_container()</function> is similar
-    to <function>sd_journal_open()</function> but opens the journal
-    files of a running OS container. The specified machine name refers
-    to a container that is registered with
-    <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
+    <para><function>sd_journal_open_directory()</function> is similar to <function>sd_journal_open()</function> but
+    takes an absolute directory path as argument. All journal files in this directory will be opened and interleaved
+    automatically. This call also takes a flags argument. The only flags parameter accepted by this call is
+    <constant>SD_JOURNAL_OS_ROOT</constant>. If specified, the journal files are searched below the usual
+    <filename>/var/log/journal</filename> and <filename>/run/log/journal</filename> relative to the specified path,
+    instead of directly beneath it.</para>
+
+    <para><function>sd_journal_open_directory_fd()</function> is similar to
+    <function>sd_journal_open_directory()</function>, but takes a file descriptor referencing a directory in the file
+    system instead of an absolute file system path.</para>
+
+    <para><function>sd_journal_open_files()</function> is similar to <function>sd_journal_open()</function> but takes a
+    <constant>NULL</constant>-terminated list of file paths to open.  All files will be opened and interleaved
+    automatically. This call also takes a flags argument, but it must be passed as 0 as no flags are currently
+    understood for this call. Please note that in the case of a live journal, this function is only useful for
+    debugging, because individual journal files can be rotated at any moment, and the opening of specific files is
+    inherently racy.</para>
+
+    <para><function>sd_journal_open_files_fd()</function> is similar to <function>sd_journal_open_files()</function>
+    but takes an array of open file descriptors that must reference journal files, instead of an array of file system
+    paths. Pass the array of file descriptors as second argument, and the number of array entries in the third. The
+    flags parameter must be passed as 0.</para>
 
     <para><varname>sd_journal</varname> objects cannot be used in the
     child after a fork. Functions which take a journal object as an
     file.</para>
   </refsect1>
 
-  <refsect1>
-    <title>History</title>
-
-    <para><function>sd_journal_open()</function>,
-    <function>sd_journal_close()</function>,
-    <constant>SD_JOURNAL_LOCAL_ONLY</constant>,
-    <constant>SD_JOURNAL_RUNTIME_ONLY</constant>,
-    <constant>SD_JOURNAL_SYSTEM_ONLY</constant> were added in
-    systemd-38.</para>
-
-    <para><function>sd_journal_open_directory()</function> was added
-    in systemd-187.</para>
-
-    <para><constant>SD_JOURNAL_SYSTEM</constant>,
-    <constant>SD_JOURNAL_CURRENT_USER</constant>, and
-    <function>sd_journal_open_files()</function> were added in
-    systemd-205. <constant>SD_JOURNAL_SYSTEM_ONLY</constant> was
-    deprecated.</para>
-  </refsect1>
-
   <refsect1>
     <title>See Also</title>
 
index 4cc7405dd655910bffd19ffa8ebfb1c76d64201c..130af761da0d2bad72bd22f7cdbd0b0238ee92d6 100644 (file)
     entry.</para>
   </refsect1>
 
-  <refsect1>
-    <title>History</title>
-
-    <para><function>sd_uid_get_state()</function>,
-    <function>sd_uid_is_on_seat()</function>,
-    <function>sd_uid_get_sessions()</function>, and
-    <function>sd_uid_get_seats()</function> functions were added in
-    systemd-31.</para>
-
-    <para><function>sd_uid_get_display()</function> was added in
-    systemd-213.</para>
-  </refsect1>
-
   <refsect1>
     <title>See Also</title>
 
index 6e27528a715fc9ff2f187baf2477dbc755388398..3de9899453b882fb548342c1a69d417602eb7dca 100644 (file)
     </variablelist>
   </refsect1>
 
-  <refsect1>
-    <title>History</title>
-
-    <para>The watchdog functionality and the
-    <varname>$WATCHDOG_USEC</varname> variable were added in
-    systemd-41.</para>
-
-    <para><function>sd_watchdog_enabled()</function> function was
-    added in systemd-209. Since that version, the
-    <varname>$WATCHDOG_PID</varname> variable is also set.</para>
-  </refsect1>
-
   <refsect1>
     <title>See Also</title>
     <para>
index 1480bf8380192586eee5730f20dddfc2f39924e4..991e9bafafd63f77822aabc33df7cbbc0e858440 100644 (file)
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--value</option></term>
+
+        <listitem>
+          <para>When printing properties with <command>show</command>,
+          only print the value, and skip the property name and
+          <literal>=</literal>.</para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--show-types</option></term>
 
@@ -1074,22 +1084,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
           <term><command>preset <replaceable>NAME</replaceable>...</command></term>
 
           <listitem>
-            <para>Reset one or more unit files, as specified on the
-            command line, to the defaults configured in the preset
-            policy files. This has the same effect as
-            <command>disable</command> or <command>enable</command>,
-            depending how the unit is listed in the preset files.</para>
+            <para>Reset the enable/disable status one or more unit files, as specified on
+            the command line, to the defaults configured in the preset policy files. This
+            has the same effect as <command>disable</command> or
+            <command>enable</command>, depending how the unit is listed in the preset
+            files.</para>
 
-            <para>Use <option>--preset-mode=</option> to control
-            whether units shall be enabled and disabled, or only
-            enabled, or only disabled.</para>
+            <para>Use <option>--preset-mode=</option> to control whether units shall be
+            enabled and disabled, or only enabled, or only disabled.</para>
 
-            <para>For more information on the preset policy format,
-            see
+            <para>If the unit carries no install information, it will be silently ignored
+            by this command.</para>
+
+            <para>For more information on the preset policy format, see
             <citerefentry><refentrytitle>systemd.preset</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-            For more information on the concept of presets, please
-            consult the <ulink
-            url="http://freedesktop.org/wiki/Software/systemd/Preset">Preset</ulink>
+            For more information on the concept of presets, please consult the
+            <ulink url="http://freedesktop.org/wiki/Software/systemd/Preset">Preset</ulink>
             document.</para>
           </listitem>
         </varlistentry>
@@ -1158,22 +1168,32 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
                   </row>
                   <row>
                     <entry><literal>static</literal></entry>
-                    <entry>The unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> section.</entry>
+                    <entry>The unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> unit file section.</entry>
                     <entry>0</entry>
                   </row>
                   <row>
                     <entry><literal>indirect</literal></entry>
-                    <entry>The unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> section, listing other unit files that might be enabled.</entry>
+                    <entry>The unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> unit file section, listing other unit files that might be enabled.</entry>
                     <entry>0</entry>
                   </row>
                   <row>
                     <entry><literal>disabled</literal></entry>
-                    <entry>Unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry>
+                    <entry>The unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry>
                     <entry>&gt; 0</entry>
                   </row>
+                  <row>
+                    <entry><literal>generated</literal></entry>
+                    <entry>The unit file was generated dynamically via a generator tool. See <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>. Generated unit files may not be enabled, they are enabled implicitly by their generator.</entry>
+                    <entry>0</entry>
+                  </row>
+                  <row>
+                    <entry><literal>transient</literal></entry>
+                    <entry>The unit file has been created dynamically with the runtime API. Transient units may not be enabled.</entry>
+                    <entry>0</entry>
+                  </row>
                   <row>
                     <entry><literal>bad</literal></entry>
-                    <entry>Unit file is invalid or another error occurred. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
+                    <entry>The unit file is invalid or another error occurred. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry>
                     <entry>&gt; 0</entry>
                   </row>
                 </tbody>
@@ -1224,6 +1244,28 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term><command>revert <replaceable>NAME</replaceable>...</command></term>
+
+          <listitem>
+            <para>Revert one or more unit files to their vendor versions. This command removes drop-in configuration
+            files that modify the specified units, as well as any user-configured unit file that overrides a matching
+            vendor supplied unit file. Specifically, for a unit <literal>foo.service</literal> the matching directories
+            <literal>foo.service.d/</literal> with all their contained files are removed, both below the persistent and
+            runtime configuration directories (i.e. below <filename>/etc/systemd/system</filename> and
+            <filename>/run/systemd/system</filename>); if the unit file has a vendor-supplied version (i.e. a unit file
+            located below <filename>/usr</filename>) any matching peristent or runtime unit file that overrides it is
+            removed, too. Note that if a unit file has no vendor-supplied version (i.e. is only defined below
+            <filename>/etc/systemd/system</filename> or <filename>/run/systemd/system</filename>, but not in a unit
+            file stored below <filename>/usr</filename>), then it is not removed. Also, if a unit is masked, it is
+            unmasked.</para>
+
+            <para>Effectively, this command may be used to undo all changes made with <command>systemctl
+            edit</command>, <command>systemctl set-property</command> and <command>systemctl mask</command> and puts
+            the original unit file with its settings back in effect.</para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term><command>add-wants <replaceable>TARGET</replaceable>
           <replaceable>NAME</replaceable>...</command></term>
index e84a15c554e51dedbfce62e68ce20e7c9b2af2f2..2b6fb5a82f8ef9c220a33cb236c60ea679d4a366 100644 (file)
@@ -67,7 +67,7 @@
     processes.</para>
 
     <para>The purpose of this tool is to query system-wide passwords
-    -- that is passwords not attached to a specific user account.
+     that is passwords not attached to a specific user account.
     Examples include: unlocking encrypted hard disks when they are
     plugged in or at boot, entering an SSL certificate passphrase for
     web and VPN servers.</para>
index f1598461ef618b95535d96efda62370e9f37402a..51dc27e8d36691d44ed3901d401d94b58ec4ecd2 100644 (file)
 
   <refnamediv>
     <refname>systemd-coredump</refname>
+    <refname>systemd-coredump.socket</refname>
+    <refname>systemd-coredump@.service</refname>
     <refpurpose>Log and store core dumps</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
     <para><filename>/usr/lib/systemd/systemd-coredump</filename></para>
+    <para><filename>systemd-coredump@.service</filename></para>
+    <para><filename>systemd-coredump.socket</filename></para>
   </refsynopsisdiv>
 
   <refsect1>
     signal and dumps core. For it to be used in this capacity, it must
     be specified by the
     <varname>kernel.core_pattern</varname> <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    setting. Systemd installs
-    <filename>/usr/lib/sysctl.d/50-coredump.conf</filename> which
-    configures <varname>kernel.core_pattern</varname> to invoke
-    <command>systemd-coredump</command>. This file may be masked or
-    overridden to use a different setting following normal
-    <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> rules.</para>
+    setting. The syntax of this setting is explained in
+    <citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    Systemd installs <filename>/usr/lib/sysctl.d/50-coredump.conf</filename> which configures
+    <varname>kernel.core_pattern</varname> to invoke <command>systemd-coredump</command>.
+    This file may be masked or overridden to use a different setting following normal
+    <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    rules.</para>
 
     <para>The behavior of a specific program upon reception of a
     signal is governed by a few factors which are described in detail
     <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
     </para>
 
-    <para><command>systemd-coredump</command> will log the coredump
-    including a backtrace if possible, and store the core (contents of
-    process' memory contents) in an external file on disk in
-    <filename>/var/lib/systemd/coredump</filename>, or directly in
-    the journal. This behavior may be modified using
-    <citerefentry><refentrytitle>coredump.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
-
-    <para>Apart from the
-    <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    log viewer,
+    <para>The behaviour of <command>systemd-coredump</command> is configured through
+    <filename>/etc/systemd/coredump.conf</filename> and other configuration files. See
+    <citerefentry><refentrytitle>coredump.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for details. By default, <command>systemd-coredump</command> will log the coredump including a
+    backtrace if possible, and store the core (contents of process' memory contents) in an external
+    file on disk in <filename>/var/lib/systemd/coredump</filename>.</para>
+
+    <para>When the kernel invokes <command>systemd-coredump</command> to handle a coredump,
+    it will connect to the socket created by the <filename>systemd-coredump.socket</filename>
+    unit, which in turn will spawn a <filename>systemd-coredump@.service</filename> instance
+    to process the coredump. Hence <filename>systemd-coredump.socket</filename>
+    and <filename>systemd-coredump@.service</filename> are helper units which do the actual
+    processing of coredumps and are subject to normal service management.</para>
+
+    <para>The log entry and a backtrace are stored in the journal, and can be viewed with
+    <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
     <citerefentry><refentrytitle>coredumpctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    may be used to list and extract coredumps.</para>
+    may be used to list and extract coredumps or load them in
+    <citerefentry project='man-pages'><refentrytitle>gdb</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
+    </para>
+
+    <para>The coredump helper is invoked anew each time. Therefore, any configuration
+    changes will take effect on the invocation of <command>systemd-coredump</command>.
+    If the sysctl configuration is modified, it must be updated in the kernel before
+    it takes effect, see
+    <citerefentry><refentrytitle>systemd-sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    and
+    <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+    </para>
   </refsect1>
 
   <refsect1>
index e32ac268505f2b7c915c7ba718e8e08c947b9e41..9ed85c3950d40e42523eb5c317f056647b4d0aa1 100644 (file)
         <term><uri>boot</uri></term>
 
         <listitem><para>Limit events to the current boot of the system
-        (like <command>journalctl --this--boot</command>).</para></listitem>
+        (like <command>journalctl --this-boot</command>).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 7e87865ba83c79cb859ba92f164abd8a49a4b591..bd688a0ee196473a552721296d3c3df269b78bdb 100644 (file)
@@ -58,7 +58,7 @@
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-nspawn</command>
-      <arg choice="plain">-b</arg>
+      <arg choice="plain">--boot</arg>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
       <arg choice="opt" rep="repeat">ARGS</arg>
     </cmdsynopsis>
         signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been
         modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands,
         except when the command refers to an init or shell implementation, as these are generally capable of running
-        correctly as PID 1). This option may not be combined with <option>--boot</option> or
+        correctly as PID 1. This option may not be combined with <option>--boot</option> or
         <option>--share-system</option>.</para>
         </listitem>
       </varlistentry>
             <tbody>
               <row>
                 <entry>Neither <option>--as-pid2</option> nor <option>--boot</option> specified</entry>
-                <entry>The passed parameters are interpreted as command line, which is executed as PID 1 in the container.</entry>
+                <entry>The passed parameters are interpreted as the command line, which is executed as PID 1 in the container.</entry>
               </row>
 
               <row>
                 <entry><option>--as-pid2</option> specified</entry>
-                <entry>The passed parameters are interpreted as command line, which are executed as PID 2 in the container. A stub init process is run as PID 1.</entry>
+                <entry>The passed parameters are interpreted as the command line, which is executed as PID 2 in the container. A stub init process is run as PID 1.</entry>
               </row>
 
               <row>
         <listitem><para>Set the specified UUID for the container. The
         init system will initialize
         <filename>/etc/machine-id</filename> from this if this file is
-        not set yet. </para></listitem>
+        not set yet. Note that this option takes effect only if
+        <filename>/etc/machine-id</filename> in the container is
+        unpopulated.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       <varlistentry>
         <term><option>--private-users=</option></term>
 
-        <listitem><para>Enables user namespacing. If enabled, the
-        container will run with its own private set of Unix user and
-        group ids (UIDs and GIDs). Takes none, one or two
-        colon-separated parameters: the first parameter specifies the
-        first host UID to assign to the container, the second
-        parameter specifies the number of host UIDs to assign to the
-        container. If the second parameter is omitted, 65536 UIDs are
-        assigned. If the first parameter is also omitted (and hence
-        no parameter passed at all), the first UID assigned to the
-        container is read from the owner of the root directory of the
-        container's directory tree. By default, no user namespacing is
-        applied.</para>
-
-        <para>Note that user namespacing currently requires OS trees
-        that are prepared for the UID shift that is being applied:
-        UIDs and GIDs used for file ownership or in file ACL entries
-        must be shifted to the container UID base that is
-        used during container runtime.</para>
+        <listitem><para>Controls user namespacing. If enabled, the container will run with its own private set of UNIX
+        user and group ids (UIDs and GIDs). This involves mapping the private UIDs/GIDs used in the container (starting
+        with the container's root user 0 and up) to a range of UIDs/GIDs on the host that are not used for other
+        purposes (usually in the range beyond the host's UID/GID 65536). The parameter may be specified as follows:</para>
+
+        <orderedlist>
+          <listitem><para>The value <literal>no</literal> turns off user namespacing. This is the default.</para></listitem>
+
+          <listitem><para>The value <literal>yes</literal> (or the omission of a parameter) turns on user
+          namespacing. The UID/GID range to use is determined automatically from the file ownership of the root
+          directory of the container's directory tree. To use this option, make sure to prepare the directory tree in
+          advance, and ensure that all files and directories in it are owned by UIDs/GIDs in the range you'd like to
+          use. Also, make sure that used file ACLs exclusively reference UIDs/GIDs in the appropriate range. If this
+          mode is used the number of UIDs/GIDs assigned to the container for use is 65536, and the UID/GID of the
+          root directory must be a multiple of 65536.</para></listitem>
+
+          <listitem><para>The value "pick" turns on user namespacing. In this case the UID/GID range is automatically
+          chosen. As first step, the file owner of the root directory of the container's directory tree is read, and it
+          is checked that it is currently not used by the system otherwise (in particular, that no other container is
+          using it). If this check is successful, the UID/GID range determined this way is used, similar to the
+          behaviour if "yes" is specified. If the check is not successful (and thus the UID/GID range indicated in the
+          root directory's file owner is already used elsewhere) a new – currently unused – UID/GID range of 65536
+          UIDs/GIDs is randomly chosen between the host UID/GIDs of 524288 and 1878982656, always starting at a
+          multiple of 65536. This setting implies <option>--private-users-chown</option> (see below), which has the
+          effect that the files and directories in the container's directory tree will be owned by the appropriate
+          users of the range picked. Using this option makes user namespace behaviour fully automatic. Note that the
+          first invocation of a previously unused container image might result in picking a new UID/GID range for it,
+          and thus in the (possibly expensive) file ownership adjustment operation. However, subsequent invocations of
+          the container will be cheap (unless of course the picked UID/GID range is assigned to a different use by
+          then).</para></listitem>
+
+          <listitem><para>Finally if one or two colon-separated numeric parameters are specified, user namespacing is
+          turned on, too. The first parameter specifies the first host UID/GID to assign to the container, the second
+          parameter specifies the number of host UIDs/GIDs to assign to the container. If the second parameter is
+          omitted, 65536 UIDs/GIDs are assigned.</para></listitem>
+        </orderedlist>
+
+        <para>It is recommended to assign at least 65536 UIDs/GIDs to each container, so that the usable UID/GID range in the
+        container covers 16 bit. For best security, do not assign overlapping UID/GID ranges to multiple containers. It is
+        hence a good idea to use the upper 16 bit of the host 32-bit UIDs/GIDs as container identifier, while the lower 16
+        bit encode the container UID/GID used. This is in fact the behaviour enforced by the
+        <option>--private-users=pick</option> option.</para>
+
+        <para>When user namespaces are used, the GID range assigned to each container is always chosen identical to the
+        UID range.</para>
+
+        <para>In most cases, using <option>--private-users=pick</option> is the recommended option as it enhances
+        container security massively and operates fully automatically in most cases.</para>
+
+        <para>Note that the picked UID/GID range is not written to <filename>/etc/passwd</filename> or
+        <filename>/etc/group</filename>. In fact, the allocation of the range is not stored persistently anywhere,
+        except in the file ownership of the files and directories of the container.</para></listitem>
+      </varlistentry>
 
-        <para>It is recommended to assign at least 65536 UIDs to each
-        container, so that the usable UID range in the container
-        covers 16 bit. For best security, do not assign overlapping UID
-        ranges to multiple containers. It is hence a good idea to use
-        the upper 16 bit of the host 32-bit UIDs as container
-        identifier, while the lower 16 bit encode the container UID
-        used.</para>
+      <varlistentry>
+        <term><option>-U</option></term>
 
-        <para>When user namespaces are used, the GID range assigned to
-        each container is always chosen identical to the UID
-        range.</para></listitem>
+        <listitem><para>If the kernel supports the user namespaces feature, equivalent to
+        <option>--private-users=pick</option>, otherwise equivalent to
+        <option>--private-users=no</option>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--private-users-chown</option></term>
+
+        <listitem><para>If specified, all files and directories in the container's directory tree will adjusted so that
+        they are owned to the appropriate UIDs/GIDs selected for the container (see above). This operation is
+        potentially expensive, as it involves descending and iterating through the full directory tree of the
+        container. Besides actual file ownership, file ACLs are adjusted as well.</para>
+
+        <para>This option is implied if <option>--private-users=pick</option> is used. This option has no effect if
+        user namespacing is not used.</para></listitem>
+      </varlistentry>
 
       <varlistentry>
         <term><option>--private-network</option></term>
         host interface name and container interface name. The latter
         may be omitted in which case the container and host sides will
         be assigned the same name. This switch is independent of
-        <option>--network-veth</option>, and -- in contrast -- may be
+        <option>--network-veth</option>, and — in contrast — may be
         used multiple times, and allows configuration of the network
         interface names. Note that <option>--network-bridge=</option>
         has no effect on interfaces created with
       </varlistentry>
 
       <varlistentry>
-        <term><option>--setenv=</option></term>
+        <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+        <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
 
         <listitem><para>Specifies an environment variable assignment
         to pass to the init process in the container, in the format
index 7a9e23a2c61e7bcb30a9db0f5d08276f10228bde..829729ca09012c901a1f5a3c246d6d06efa3aa0e 100644 (file)
       is on the local loopback) and the IPv6 address ::1 (which is the
       local host).</para></listitem>
 
-      <listitem><para>The hostname <literal>localhost</literal> (as well as any hostname ending in
-      <literal>.localhost</literal>, <literal>.localdomain</literal> or equal to <literal>localdomain</literal>) is
-      resolved to the IP addresses 127.0.0.1 and ::1.</para></listitem>
+      <listitem><para>The hostnames <literal>localhost</literal> and
+      <literal>localhost.localdomain</literal> (as well as any hostname
+      ending in <literal>.localhost</literal> or <literal>.localhost.localdomain</literal>)
+      are resolved to the IP addresses 127.0.0.1 and ::1.</para></listitem>
 
       <listitem><para>The hostname <literal>gateway</literal> is
       resolved to all current default routing gateway addresses,
index a92dfb402a7b4db6815352a3a23aa4a995e25df5..9c1a29218ede0eaedb980b1448557a161f882e06 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><option>--setenv=</option></term>
+        <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+        <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
 
-        <listitem><para>Runs the service process with the specified
-        environment variables set. Also see
-        <varname>Environment=</varname> in
+        <listitem><para>Runs the service process with the specified environment variable set.
+        Also see <varname>Environment=</varname> in
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
         </listitem>
       </varlistentry>
   <refsect1>
     <title>Examples</title>
 
-    <para>The following command will log the environment variables
-    provided by systemd to services:</para>
+    <example>
+      <title>Logging environment variables provided by systemd to services</title>
 
-    <programlisting># systemd-run env
-Running as unit run-19945.service
+      <programlisting># systemd-run env
+Running as unit: run-19945.service
 # journalctl -u run-19945.service
 Sep 08 07:37:21 bupkis systemd[1]: Starting /usr/bin/env...
 Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env.
 Sep 08 07:37:21 bupkis env[19948]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
 Sep 08 07:37:21 bupkis env[19948]: LANG=en_US.UTF-8
 Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.x86_64</programlisting>
+    </example>
+
+    <example>
+      <title>Limiting resources available to a command</title>
+
+      <programlisting># systemd-run -p BlockIOWeight=10 updatedb</programlisting>
 
-    <para>The following command invokes the
-    <citerefentry project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    tool, but lowers the block I/O weight for it to 10. See
-    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    for more information on the <varname>BlockIOWeight=</varname>
-    property.</para>
+      <para>This command invokes the
+      <citerefentry project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      tool, but lowers the block I/O weight for it to 10. See
+      <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      for more information on the <varname>BlockIOWeight=</varname>
+      property.</para>
+    </example>
 
-    <programlisting># systemd-run -p BlockIOWeight=10 updatedb</programlisting>
+    <example>
+      <title>Running commands at a specified time</title>
 
-    <para>The following command will touch a file after 30 seconds.</para>
+      <para>The following command will touch a file after 30 seconds.</para>
 
-    <programlisting># date; systemd-run --on-active=30 --timer-property=AccuracySec=100ms /bin/touch /tmp/foo
+      <programlisting># date; systemd-run --on-active=30 --timer-property=AccuracySec=100ms /bin/touch /tmp/foo
 Mon Dec  8 20:44:24 KST 2014
-Running as unit run-71.timer
-Will run service as unit run-71.service
+Running as unit: run-71.timer
+Will run service as unit: run-71.service
 # journalctl -b -u run-71.timer
 -- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
 Dec 08 20:44:38 container systemd[1]: Starting /bin/touch /tmp/foo.
@@ -376,13 +384,60 @@ Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
 -- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
 Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
 Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
-
-    <para>The following command invokes <filename>/bin/bash</filename>
-    as a service passing its standard input, output and error to
-    the calling TTY.</para>
-
-    <programlisting># systemd-run -t --send-sighup /bin/bash</programlisting>
-
+    </example>
+
+    <example>
+      <title>Allowing access to the tty</title>
+
+      <para>The following command invokes <filename>/bin/bash</filename> as a service
+      passing its standard input, output and error to the calling TTY.</para>
+
+      <programlisting># systemd-run -t --send-sighup /bin/bash</programlisting>
+    </example>
+
+    <example>
+      <title>Start <command>screen</command> as a user service</title>
+
+      <programlisting>$ systemd-run --scope --user screen
+Running scope as unit run-r14b0047ab6df45bfb45e7786cc839e76.scope.
+
+$ screen -ls
+There is a screen on:
+        492..laptop     (Detached)
+1 Socket in /var/run/screen/S-fatima.
+</programlisting>
+
+      <para>This starts the <command>screen</command> process as a child of the
+      <command>systemd --user</command> process that was started by
+      <filename>user@.service</filename>, in a scope unit. A
+      <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      unit is used instead of a
+      <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      unit, because <command>screen</command> will exit when detaching from the terminal,
+      and a service unit would be terminated. Running <command>screen</command>
+      as a user unit has the advantage that it is not part of the session scope.
+      If <varname>KillUserProcesses=yes</varname> is configured in
+      <citerefentry><refentrytitle>logind.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      the default, the session scope will be terminated when the user logs
+      out of that session.</para>
+
+      <para>The <filename>user@.service</filename> is started automatically
+      when the user first logs in, and stays around as long as at least one
+      login session is open. After the user logs out of the last session,
+      <filename>user@.service</filename> and all services underneath it
+      are terminated. This behaviour is the default, when "lingering" is
+      not enabled for that user. Enabling lingering means that
+      <filename>user@.service</filename> is started automatically during
+      boot, even if the user is not logged in, and that the service is
+      not terminated when the user logs out.</para>
+
+      <para>Enabling lingering allows the user to run processes without being logged in,
+      for example to allow <command>screen</command> to persist after the user logs out,
+      even if the session scope is terminated. In the default configuration, users can
+      enable lingering for themselves:</para>
+
+      <programlisting>$ loginctl enable-linger</programlisting>
+    </example>
   </refsect1>
 
   <refsect1>
index 9027ff0f3fce3a6025ee9b1b398616f2f0068016..686b2cdef43bd66d1fbc963a7bec128733522b23 100644 (file)
     <para><filename>systemd-sysctl.service</filename> is an early boot
     service that configures
     <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    kernel parameters.</para>
+    kernel parameters by invoking <command>/usr/lib/systemd/systemd-sysctl</command>.</para>
 
-    <para>If invoked with no arguments, it applies all directives from
-    all configuration files in
-    <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    are searched for a matching file. If one or more filenames are passed on
-    the command line, only the directives in these files are applied.
-    </para>
+    <para>When invoked with no arguments, <command>/usr/lib/systemd/systemd-sysctl</command> applies
+    all directives from configuration files listed in
+    <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    If one or more filenames are passed on the command line, only the directives in these files are
+    applied.</para>
+
+    <para>In addition, <option>--prefix=</option> option may be used to limit which sysctl
+    settings are applied.</para>
 
     <para>See
     <citerefentry project='man-pages'><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    for information about the configuration of this service.</para>
+    for information about the configuration of sysctl settings. After sysctl configuration is
+    changed on disk, it must be written to the files in <filename>/proc/sys</filename> before it
+    takes effect. It is possible to update specific settings, or simply to reload all configuration,
+    see Examples below.</para>
   </refsect1>
 
   <refsect1><title>Options</title>
     <variablelist>
-      <varlistentry id='path'>
-        <term><option>--path=</option></term>
+      <varlistentry id='prefix'>
+        <term><option>--prefix=</option></term>
         <listitem>
           <para>Only apply rules with the specified prefix.</para>
         </listitem>
     </variablelist>
   </refsect1>
 
+  <refsect1>
+    <title>Examples</title>
+
+    <example>
+      <title>Reset all sysctl settings</title>
+
+      <programlisting>systemctl restart systemd-sysctl</programlisting>
+    </example>
+
+    <example>
+      <title>View coredump handler configuration</title>
+
+      <programlisting># sysctl kernel.core_pattern
+kernel.core_pattern = |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t %P %I
+</programlisting>
+    </example>
+
+    <example>
+      <title>Update coredump handler configuration</title>
+
+      <programlisting># /usr/lib/systemd/systemd-sysctl --prefix kernel.core_pattern</programlisting>
+
+      <para>This searches all the directories listed in
+      <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      for configuration files and writes <filename>/proc/sys/kernel/core_pattern</filename>.</para>
+    </example>
+
+    <example>
+      <title>Update coredump handler configuration according to a specific file</title>
+
+      <programlisting># /usr/lib/systemd/systemd-sysctl 50-coredump.conf</programlisting>
+
+      <para>This applies all the settings found in <filename>50-coredump.conf</filename>.
+      Either <filename>/etc/sysctl.d/50-coredump.conf</filename>, or
+      <filename>/run/sysctl.d/50-coredump.conf</filename>, or
+      <filename>/usr/lib/sysctl.d/50-coredump.conf</filename> will be used, in the order
+      of preference.</para>
+    </example>
+
+    <para>See
+    <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    for various ways to directly apply sysctl settings.</para>
+  </refsect1>
+
   <refsect1>
     <title>See Also</title>
     <para>
index edc6df914aba2c1736a3c4f7594edd8cc0c6a949..8833e73c7296b93c5358e751e71ff8821133be6e 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><varname>DefaultStartLimitInterval=</varname></term>
+        <term><varname>DefaultStartLimitIntervalSec=</varname></term>
         <term><varname>DefaultStartLimitBurst=</varname></term>
 
         <listitem><para>Configure the default unit start rate
         limiting, as configured per-service by
-        <varname>StartLimitInterval=</varname> and
+        <varname>StartLimitIntervalSec=</varname> and
         <varname>StartLimitBurst=</varname>. See
         <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for details on the per-service settings.
-        <varname>DefaultStartLimitInterval=</varname> defaults to
+        <varname>DefaultStartLimitIntervalSec=</varname> defaults to
         10s. <varname>DefaultStartLimitBurst=</varname> defaults to
         5.</para></listitem>
       </varlistentry>
index 447a7eaa17746b765abc1802b31ac62cca623b8f..c1aab5155178ab81d8e1b29122c2893d0086c6c9 100644 (file)
     <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     </para>
 
-    <para>If invoked with no arguments, it applies all directives from
-    all configuration files. If one or more absolute filenames are passed on
-    the command line, only the directives in these files are applied.
-    If only the basename of a configuration file is specified, all
-    configuration directories as specified in
+    <para>If invoked with no arguments, it applies all directives from all configuration
+    files. If one or more absolute filenames are passed on the command line, only the
+    directives in these files are applied.  If <literal>-</literal> is specified instead
+    of a filename, directives are read from standard input.  If only the basename of a
+    configuration file is specified, all configuration directories as specified in
     <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     are searched for a matching file.</para>
   </refsect1>
index 1b0ae832dac0c167dd569e148039d0a1614f9996..a43dc981bdf8d63305def471e32b17c9ce815a07 100644 (file)
     [Install] sections. The automount specific configuration options
     are configured in the [Automount] section.</para>
 
-    <para>Automount units must be named after the automount
-    directories they control. Example: the automount point
-    <filename noindex='true'>/home/lennart</filename> must be
-    configured in a unit file
-    <filename>home-lennart.automount</filename>. For details about the
-    escaping logic used to convert a file system path to a unit name
-    see
-    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+    <para>Automount units must be named after the automount directories they control. Example: the automount point
+    <filename noindex='true'>/home/lennart</filename> must be configured in a unit file
+    <filename>home-lennart.automount</filename>. For details about the escaping logic used to convert a file system
+    path to a unit name see
+    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that
+    automount units cannot be templated, nor is it possible to add multiple names to an automount unit by creating
+    additional symlinks to its unit file.</para>
 
     <para>For each automount unit file a matching mount unit file (see
     <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     <para>An implicit <varname>Before=</varname> dependency is created
     between an automount unit and the mount unit it activates.</para>
 
-    <para>Automount units acquire automatic <varname>Before=</varname>
-    and <varname>Conflicts=</varname> on
-    <filename>umount.target</filename> in order to be stopped during
-    shutdown, unless <varname>DefaultDependencies=no</varname> is
-    set.</para>
+    <para>Automount units acquire automatic <varname>Before=</varname> and <varname>Conflicts=</varname> on
+    <filename>umount.target</filename> in order to be stopped during shutdown, unless
+    <varname>DefaultDependencies=no</varname> is set in the <literal>[Unit]</literal> section.</para>
 
   </refsect1>
 
index 3e1a2cb22461cb48012fbd31f3cd2e0d1f262690..2a937604288c9ac88efd8ab34e0c7b20dc1d485d 100644 (file)
     required to access <filename>/tmp</filename> and
     <filename>/var/tmp</filename>.</para>
 
-    <para>Units whose output standard output or error output is
-    connected to any other sink but <option>null</option>,
-    <option>tty</option> and <option>socket</option> automatically
-    acquire dependencies of type <varname>After=</varname> on
-    <filename>journald.socket</filename>.</para>
+    <para>Units whose standard output or error output is connected to <option>journal</option>, <option>syslog</option>
+    or <option>kmsg</option> (or their combinations with console output, see below) automatically acquire dependencies
+    of type <varname>After=</varname> on <filename>systemd-journald.socket</filename>.</para>
   </refsect1>
 
   <refsect1>
         similar to the same option of
         <varname>StandardInput=</varname>.</para>
 
+        <para>If the standard output (or error output, see below) of a unit is connected to the journal, syslog or the
+        kernel log buffer, the unit will implicitly gain a dependency of type <varname>After=</varname> on
+        <filename>systemd-journald.socket</filename> (also see the automatic dependencies section above).</para>
+
         <para>This setting defaults to the value set with
         <option>DefaultStandardOutput=</option> in
         <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <term><varname>LimitNICE=</varname></term>
         <term><varname>LimitRTPRIO=</varname></term>
         <term><varname>LimitRTTIME=</varname></term>
-        <listitem><para>These settings set both soft and hard limits
-        of various resources for executed processes. See
-        <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        for details. The resource limit is possible to specify in two formats,
-        <option>value</option> to set soft and hard limits to the same value,
-        or <option>soft:hard</option> to set both limits individually (e.g. LimitAS=4G:16G).
-        Use the string <varname>infinity</varname> to
-        configure no limit on a specific resource. The multiplicative
-        suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E
-        may be used for resource limits measured in bytes
-        (e.g. LimitAS=16G). For the limits referring to time values,
-        the usual time units ms, s, min, h and so on may be used (see
-        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-        for details). Note that if no time unit is specified for
-        <varname>LimitCPU=</varname> the default unit of seconds is
-        implied, while for <varname>LimitRTTIME=</varname> the default
-        unit of microseconds is implied. Also, note that the effective
-        granularity of the limits might influence their
-        enforcement. For example, time limits specified for
-        <varname>LimitCPU=</varname> will be rounded up implicitly to
-        multiples of 1s.</para>
+        <listitem><para>Set soft and hard limits on various resources for executed processes. See
+        <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details on
+        the resource limit concept. Resource limits may be specified in two formats: either as single value to set a
+        specific soft and hard limit to the same value, or as colon-separated pair <option>soft:hard</option> to set
+        both limits individually (e.g. <literal>LimitAS=4G:16G</literal>).  Use the string <varname>infinity</varname>
+        to configure no limit on a specific resource. The multiplicative suffixes K, M, G, T, P and E (to the base
+        1024) may be used for resource limits measured in bytes (e.g. LimitAS=16G). For the limits referring to time
+        values, the usual time units ms, s, min, h and so on may be used (see
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details). Note that if no time unit is specified for <varname>LimitCPU=</varname> the default unit of seconds
+        is implied, while for <varname>LimitRTTIME=</varname> the default unit of microseconds is implied. Also, note
+        that the effective granularity of the limits might influence their enforcement. For example, time limits
+        specified for <varname>LimitCPU=</varname> will be rounded up implicitly to multiples of 1s. For
+        <varname>LimitNICE=</varname> the value may be specified in two syntaxes: if prefixed with <literal>+</literal>
+        or <literal>-</literal>, the value is understood as regular Linux nice value in the range -20..19. If not
+        prefixed like this the value is understood as raw resource limit parameter in the range 0..40 (with 0 being
+        equivalent to 1).</para>
 
         <para>Note that most process resource limits configured with
         these options are per-process, and processes may fork in order
         reading only, writing will be refused even if the usual file
         access controls would permit this. Directories listed in
         <varname>InaccessibleDirectories=</varname> will be made
-        inaccessible for processes inside the namespace. Note that
-        restricting access with these options does not extend to
-        submounts of a directory that are created later on. These
+        inaccessible for processes inside the namespace, and may not
+        countain any other mountpoints, including those specified by
+        <varname>ReadWriteDirectories=</varname> or
+        <varname>ReadOnlyDirectories=</varname>.
+        Note that restricting access with these options does not extend
+        to submounts of a directory that are created later on. These
         options may be specified more than once, in which case all
         directories listed will have limited access from within the
         namespace. If the empty string is assigned to this option, the
index 4a8d265fed72f140b2a3f34c4c530e5fbac72549..bf56a49e589ffd6ae36f71bff6edc6fe5a0faf14 100644 (file)
     will refuse options that are not listed in
     <filename>/etc/fstab</filename> if it is not run as UID 0.</para>
 
-    <para>Mount units must be named after the mount point directories
-    they control. Example: the mount point
-    <filename noindex='true'>/home/lennart</filename> must be
-    configured in a unit file <filename>home-lennart.mount</filename>.
-    For details about the escaping logic used to convert a file system
-    path to a unit name, see
-    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-    Note that mount units cannot be templated.</para>
+    <para>Mount units must be named after the mount point directories they control. Example: the mount point <filename
+    noindex='true'>/home/lennart</filename> must be configured in a unit file <filename>home-lennart.mount</filename>.
+    For details about the escaping logic used to convert a file system path to a unit name, see
+    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.  Note that mount
+    units cannot be templated, nor is possible to add multiple names to a mount unit by creating additional symlinks to
+    it.</para>
 
     <para>Optionally, a mount unit may be accompanied by an automount
     unit, to allow on-demand or parallelized mounting. See
     <filename>systemd-quotacheck.service</filename> and
     <filename>quotaon.service</filename> are added.</para>
 
-    <para>For mount units with
-    <varname>DefaultDependencies=yes</varname> (the default) a couple
-    additional dependencies are added. Mount units referring to local
-    file systems automatically gain an <varname>After=</varname>
-    dependency on <filename>local-fs-pre.target</filename>. Network
-    mount units automatically acquire <varname>After=</varname>
-    dependencies on <filename>remote-fs-pre.target</filename>,
-    <filename>network.target</filename> and
-    <filename>network-online.target</filename>. Towards the latter a
-    <varname>Wants=</varname> unit is added as well. Mount units
-    referring to local and network file systems are distinguished by
-    their file system type specification. In some cases this is not
-    sufficient (for example network block device based mounts, such as
-    iSCSI), in which case <option>_netdev</option> may be added to the
-    mount option string of the unit, which forces systemd to consider the
-    mount unit a network mount. Mount units (regardless if local or
-    network) also acquire automatic <varname>Before=</varname> and
-    <varname>Conflicts=</varname> on
-    <filename>umount.target</filename> in order to be stopped
-    during shutdown.</para>
+    <para>For mount units with <varname>DefaultDependencies=yes</varname> in the <literal>[Unit]</literal> section (the
+    default) a couple additional dependencies are added. Mount units referring to local file systems automatically gain
+    an <varname>After=</varname> dependency on <filename>local-fs-pre.target</filename>. Network mount units
+    automatically acquire <varname>After=</varname> dependencies on <filename>remote-fs-pre.target</filename>,
+    <filename>network.target</filename> and <filename>network-online.target</filename>. Towards the latter a
+    <varname>Wants=</varname> unit is added as well. Mount units referring to local and network file systems are
+    distinguished by their file system type specification. In some cases this is not sufficient (for example network
+    block device based mounts, such as iSCSI), in which case <option>_netdev</option> may be added to the mount option
+    string of the unit, which forces systemd to consider the mount unit a network mount. Mount units (regardless if
+    local or network) also acquire automatic <varname>Before=</varname> and <varname>Conflicts=</varname> on
+    <filename>umount.target</filename> in order to be stopped during shutdown.</para>
 
     <para>Additional implicit dependencies may be added as result of
     execution and resource control parameters as documented in
index c5fb2fa7fb1f048c50e79e0c222eb755b74a6288..48c283c8df432ca174c3b3790b8741f9762d9f7c 100644 (file)
             of the Listening and Learning states before the Forwarding state is entered.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>MulticastQuerier=</varname></term>
+          <listitem>
+            <para>A boolean. This setting controls the IFLA_BR_MCAST_QUERIER option in the kernel.
+            If enabled, the kernel will send general ICMP queries from a zero source address.
+            This feature should allow faster convergence on startup, but it causes some
+            multicast-aware switches to misbehave and disrupt forwarding of multicast packets.
+            When unset, the kernel's default setting applies.
+            </para>
+          </listitem>
+        </varlistentry>
       </variablelist>
 
   </refsect1>
index f2e715cf6f3b18af079275cabebec34dff3f7f45..2a2074837608d15349f5f870436323e8ef4ddd24 100644 (file)
           <para>The maximum transmission unit in bytes to set for the
           device. The usual suffixes K, M, G, are supported and are
           understood to the base of 1024.</para>
+          <para>Note that if IPv6 is enabled on the interface, and the MTU is chosen
+          below 1280 (the minimum MTU for IPv6) it will automatically be increased to this value.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>IAID=</varname></term>
+        <listitem>
+          <para>Identity Association Identifier for the interface, a 32-bit unsigned integer.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+      <listitem>
+        <para>Note that an interface without any static IPv6 addresses configured, and neither
+        DHCPv6 nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be
+        automatically disabled for that interface by writing "1" to
+        <filename>/proc/sys/net/ipv6/conf/<replaceable>ifname</replaceable>/disable_ipv6</filename>.
+        </para>
+      </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
           Defaults to unset.
         </para></listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>ProxyARP=</varname></term>
+          <listitem><para>A boolean. Configures proxy ARP. Proxy ARP is the technique in which one host,
+          usually a router, answers ARP requests intended for another machine. By "faking" its identity,
+          the router accepts responsibility for routing packets to the "real" destination. (see <ulink
+          url="https://tools.ietf.org/html/rfc1027">RFC 1027</ulink>.
+          Defaults to unset.
+        </para></listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>Bridge=</varname></term>
           <listitem>
         <varlistentry>
           <term><varname>ClientIdentifier=</varname></term>
           <listitem>
-            <para>DHCP client identifier to use. Either <literal>mac</literal>
-            to use the MAC address of the link or <literal>duid</literal>
-            (the default) to use a RFC4361-compliant Client ID.</para>
+            <para>The DHCPv4 client identifier to use. Either <literal>mac</literal> to use the MAC address of the link
+            or <literal>duid</literal> (the default, see below) to use a RFC4361-compliant Client ID.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
             type and configuration.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>DUIDRawData=</varname></term>
+          <listitem><para>Specifies the DHCP DUID bytes as a single newline-terminated, hexadecimal string, with each
+          byte separated by a ':'.  A DHCPv6 client sends the DHCP Unique Identifier (DUID) and the interface Identity
+          Association Identifier (IAID) to a DHCP server when acquiring a dynamic IPv6 address. Similar, DHCPv4 clients
+          send the IAID and DUID to the DHCP server when acquiring a dynamic IPv4 address if
+          <option>ClientIdentifier=duid</option>. IAID and DUID allows a DHCP server to uniquely identify the machine
+          and the interface requesting a DHCP IP address.</para>
+
+          <para>The DUID value specified here takes precedence over the DUID that systemd-networkd generates
+          using the machine-id from the <filename>/etc/machine-id</filename> file, as well as the
+          global DUID that may be specified in <citerefentry><refentrytitle>networkd.conf
+          </refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+          <para>The configured DHCP DUID should conform to the specification in
+          <ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
+          <ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>RequestBroadcast=</varname></term>
           <listitem>
           </listitem>
         </varlistentry>
       </variablelist>
-
-  </refsect1>
+    </refsect1>
 
   <refsect1>
     <title>[DHCPServer] Section Options</title>
index 5ec878512a08dfcb3106136245756165ad2ee583..15360078ef210c1352380977a881098a1129590c 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term><option>KillSignal=</option></term>
+        <term><varname>KillSignal=</varname></term>
 
         <listitem><para>Specify the process signal to send to the
         container's PID 1 when nspawn itself receives SIGTERM, in
         <option>--uuid=</option> command line switch. This option is
         privileged (see above). </para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>PrivateUsers=</varname></term>
+
+        <listitem><para>Configures support for usernamespacing. This is equivalent to the
+        <option>--private-users=</option> command line switch, and takes the same options. This option is privileged
+        (see above). </para></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
         for details about the specific options supported. This setting
         is privileged (see above).</para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>PrivateUsersChown=</varname></term>
+
+        <listitem><para>Configures whether the ownership of the files and directories in the container tree shall be
+        adjusted to the UID/GID range used, if necessary and user namespacing is enabled. This is equivalent to the
+        <option>--private-users-chown</option> command line switch. This option is privileged (see
+        above). </para></listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
diff --git a/man/systemd.offline-updates.xml b/man/systemd.offline-updates.xml
new file mode 100644 (file)
index 0000000..946234a
--- /dev/null
@@ -0,0 +1,169 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<!--
+  This file is part of systemd.
+
+  Copyright 2013 Lennart Poettering
+  Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<refentry id="systemd.offline-updates">
+  <refentryinfo>
+    <title>systemd.offline-updates</title>
+    <productname>systemd</productname>
+
+    <authorgroup>
+      <author>
+        <contrib>Developer</contrib>
+        <firstname>Lennart</firstname>
+        <surname>Poettering</surname>
+        <email>lennart@poettering.net</email>
+      </author>
+    </authorgroup>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>systemd.offline-updates</refentrytitle>
+    <manvolnum>7</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>systemd.offline-updates</refname>
+    <refpurpose>Implementation of offline updates in systemd</refpurpose>
+  </refnamediv>
+
+  <refsect1>
+    <title>Implementing Offline System Updates</title>
+
+    <para>This man page describes how to implement "offline" system updates with systemd. By "offline"
+    OS updates we mean package installations and updates that are run with the system booted into a
+    special system update mode, in order to avoid problems related to conflicts of libraries and
+    services that are currently running with those on disk. This document is inspired by this
+    <ulink url="https://wiki.gnome.org/Design/OS/SoftwareUpdates">GNOME design whiteboard</ulink>.
+    </para>
+
+    <para>The logic:</para>
+
+    <orderedlist>
+      <listitem>
+        <para>The package manager prepares system updates by downloading all (RPM or DEB or
+        whatever) packages to update off-line in a special directory
+        <filename noindex="true">/var/lib/system-update</filename> (or
+        another directory of the package/upgrade manager's choice).</para>
+      </listitem>
+
+      <listitem>
+        <para>When the user OK'ed the update, the symlink <filename>/system-update</filename> is
+        created that points to <filename noindex="true">/var/lib/system-update</filename> (or
+        wherever the directory with the upgrade files is located) and the system is rebooted. This
+        symlink is in the root directory, since we need to check for it very early at boot, at a
+        time where <filename>/var</filename> is not available yet.</para>
+      </listitem>
+
+      <listitem>
+        <para>Very early in the new boot
+        <citerefentry><refentrytitle>systemd-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+        checks whether <filename>/system-update</filename> exists. If so, it (temporarily and for
+        this boot only) redirects (i.e. symlinks) <filename>default.target</filename> to
+        <filename>system-update.target</filename>, a special target that is pulls in the base system
+        (i.e. <filename>sysinit.target</filename>, so that all file systems are mounted but little
+        else) and the system update units.</para>
+      </listitem>
+
+      <listitem>
+        <para>The system now continues to boot into <filename>default.target</filename>, and thus
+        into <filename>system-update.target</filename>. This target pulls in the system update unit,
+        which starts the system update script after all file systems have been mounted.</para>
+      </listitem>
+
+      <listitem>
+        <para>As the first step, the update script should check if the
+        <filename>/system-update</filename> symlink points to the the location used by that update
+        script. In case it does not exists or points to a different location, the script must exit
+        without error. It is possible for multiple update services to be installed, and for multiple
+        update scripts to be launched in parallel, and only the one that corresponds to the tool
+        that <emphasis>created</emphasis> the symlink before reboot should perform any actions. It
+        is unsafe to run multiple updates in parallel.</para>
+      </listitem>
+
+      <listitem>
+        <para>The update script should now do its job. If applicable and possible, it should
+        create a file system snapshot, then install all packages.
+        After completion (regardless whether the update succeeded or failed) the machine
+        must be rebooted, for example by calling <command>systemctl reboot</command>.
+        In addition, on failure the script should revert to the old file system snapshot
+        (without the symlink).</para>
+      </listitem>
+
+      <listitem>
+        <para>The system is rebooted. Since the <filename>/system-update</filename> symlink is gone,
+        the generator won't redirect <filename>default.target</filename> after reboot and the
+        system now boots into the default target again.</para>
+      </listitem>
+    </orderedlist>
+  </refsect1>
+
+  <refsect1>
+    <title>Recommendations</title>
+
+    <orderedlist>
+      <listitem>
+        <para>To make things a bit more robust we recommend hooking the update script into
+        <filename>system-update.target</filename> via a <filename noindex='true'>.wants/</filename>
+        symlink in the distribution package, rather than depending on <command>systemctl
+        enable</command> in the postinst scriptlets of your package. More specifically, for your
+        update script create a .service file, without [Install] section, and then add a symlink like
+        <filename noindex='true'>/usr/lib/systemd/system-update.target.wants/foobar.service</filename>
+        → <filename noindex='true'>../foobar.service</filename> to your package.</para>
+      </listitem>
+
+      <listitem>
+        <para>Make sure to remove the <filename>/system-update</filename> symlink as early as
+        possible in the update script to avoid reboot loops in case the update fails.</para>
+      </listitem>
+
+      <listitem>
+        <para>Use <varname>FailureAction=reboot</varname> in the service file for your update script
+        to ensure that a reboot is automatically triggered if the update fails.
+        <varname>FailureAction=</varname> makes sure that the specified unit is activated if your
+        script exits uncleanly (by non-zero error code, or signal/coredump). If your script succeeds
+        you should trigger the reboot in your own code, for example by invoking logind's
+        <command>Reboot()</command> call or calling <command>systemct reboot</command>. See
+        <ulink url="http://www.freedesktop.org/wiki/Software/systemd/logind">logind dbus API</ulink>
+        for details.</para>
+      </listitem>
+
+      <listitem>
+        <para>The update service should declare <varname>DefaultDependencies=false</varname>,
+        and pull in any services it requires explicitly.</para>
+      </listitem>
+    </orderedlist>
+  </refsect1>
+
+  <refsect1>
+    <title>See also</title>
+
+    <para>
+      <ulink url="http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates/">Implementing Offline System Updates</ulink>,
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>dnf.plugin.system-upgrade</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+</refentry>
index 1bd65ce86d76ab78d21dfcdce89f12f7966c98ff..7200c8fe27671621187d3a58ddc57ca1c61af783 100644 (file)
     <para>An implicit <varname>Before=</varname> dependency is added
     between a path unit and the unit it is supposed to activate.</para>
 
-    <para>Unless <varname>DefaultDependencies=false</varname> is used,
-    path units will implicitly have dependencies of type
-    <varname>Before=</varname> on <filename>paths.target</filename>,
-    dependencies of type <varname>After=</varname> and
-    <varname>Requires=</varname> on
-    <filename>sysinit.target</filename>, and have dependencies of type
-    <varname>Conflicts=</varname> and <varname>Before=</varname> on
-    <filename>shutdown.target</filename>. These ensure that path units
-    are terminated cleanly prior to system shutdown. Only path units
-    involved with early boot or late system shutdown should disable
+    <para>Unless <varname>DefaultDependencies=false</varname> in the <literal>[Unit]</literal> section is used, path
+    units will implicitly have dependencies of type <varname>Before=</varname> on <filename>paths.target</filename>,
+    dependencies of type <varname>After=</varname> and <varname>Requires=</varname> on
+    <filename>sysinit.target</filename>, and have dependencies of type <varname>Conflicts=</varname> and
+    <varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure that path units are terminated
+    cleanly prior to system shutdown. Only path units involved with early boot or late system shutdown should disable
     this option.
     </para>
   </refsect1>
index 08cdf06e23cc92ed04f44161373e6eae39e6152e..fd6f7a1b69b2660ed7260e4011c0bdb58f905b93 100644 (file)
           controls the <literal>memory.limit_in_bytes</literal>
           control group attribute. For details about this control
           group attribute, see <ulink
-          url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>.</para>
+          url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt</ulink>.</para>
 
           <para>Implies <literal>MemoryAccounting=true</literal>.</para>
         </listitem>
           controls the <literal>pids.max</literal> control group
           attribute. For details about this control group attribute,
           see <ulink
-          url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
+          url="https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt">pids.txt</ulink>.</para>
 
           <para>Implies <literal>TasksAccounting=true</literal>. The
           system default for this setting may be controlled with
         the <literal>blkio.weight</literal> control group attribute,
         which defaults to 500. For details about this control group
         attribute, see <ulink
-        url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.
+        url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
         The available I/O bandwidth is split up among all units within
         one slice relative to their block I/O weight.</para>
 
           attribute, which defaults to 1000. Use this option multiple
           times to set weights for multiple devices. For details about
           this control group attribute, see <ulink
-          url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.</para>
+          url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.</para>
 
           <para>Implies
           <literal>BlockIOAccounting=true</literal>.</para>
           Gigabytes, or Terabytes, respectively, to the base of
           1000. (Example:
           "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This
-          controls the <literal>blkio.read_bps_device</literal> and
-          <literal>blkio.write_bps_device</literal> control group
+          controls the <literal>blkio.throttle.read_bps_device</literal> and
+          <literal>blkio.throttle.write_bps_device</literal> control group
           attributes. Use this option multiple times to set bandwidth
           limits for multiple devices. For details about these control
           group attributes, see <ulink
-          url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.
+          url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
           </para>
 
           <para>Implies
           <literal>devices.deny</literal> control group
           attributes. For details about these control group
           attributes, see <ulink
-          url="https://www.kernel.org/doc/Documentation/cgroups/devices.txt">devices.txt</ulink>.</para>
+          url="https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt">devices.txt</ulink>.</para>
 
           <para>The device node specifier is either a path to a device
           node in the file system, starting with
       <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
       The documentation for control groups and specific controllers in the Linux kernel:
-      <ulink url="https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt">cgroups.txt</ulink>,
-      <ulink url="https://www.kernel.org/doc/Documentation/cgroups/cpuacct.txt">cpuacct.txt</ulink>,
-      <ulink url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>,
-      <ulink url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.
+      <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt">cgroups.txt</ulink>,
+      <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt">cpuacct.txt</ulink>,
+      <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt</ulink>,
+      <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt">blkio-controller.txt</ulink>.
     </para>
   </refsect1>
 </refentry>
index e55534700af8c96b2d049479025cc76a9c6d0234..6641dfed4f20b4613a87b002aa9b72d77f58fff3 100644 (file)
     their activated <filename>.socket</filename> units via an
     automatic <varname>After=</varname> dependency.</para>
 
-    <para>Unless <varname>DefaultDependencies=</varname> is set to
-    <option>false</option>, service units will implicitly have
-    dependencies of type <varname>Requires=</varname> and
-    <varname>After=</varname> on <filename>sysinit.target</filename>,
-    a dependency of type <varname>After=</varname> on
-    <filename>basic.target</filename> as well as dependencies of
-    type <varname>Conflicts=</varname> and <varname>Before=</varname>
-    on <filename>shutdown.target</filename>. These ensure that normal
-    service units pull in basic system initialization, and are
-    terminated cleanly prior to system shutdown. Only services
-    involved with early boot or late system shutdown should disable
-    this option.</para>
+    <para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> is set to
+    <option>false</option>, service units will implicitly have dependencies of type <varname>Requires=</varname> and
+    <varname>After=</varname> on <filename>sysinit.target</filename>, a dependency of type <varname>After=</varname> on
+    <filename>basic.target</filename> as well as dependencies of type <varname>Conflicts=</varname> and
+    <varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure that normal service units pull in
+    basic system initialization, and are terminated cleanly prior to system shutdown. Only services involved with early
+    boot or late system shutdown should disable this option.</para>
 
     <para>Instanced service units (i.e. service units with an <literal>@</literal> in their name) are assigned by
     default a per-template slice unit (see
index 5c87bf02608cd1477dbb551eaa6a0ebc1981d402..eee98d99ee04a20b6d85097a7b84776bdd353175 100644 (file)
@@ -71,6 +71,9 @@
     the root slice <filename>-.slice</filename>.
     </para>
 
+    <para>Note that slice units cannot be templated, nor is possible to add multiple names to a slice unit by creating
+    additional symlinks to it.</para>
+
     <para>By default, service and scope units are placed in
     <filename>system.slice</filename>, virtual machines and containers
     registered with
     <varname>After=</varname> and <varname>Requires=</varname> on
     their immediate parent slice unit.</para>
 
-    <para>Unless <varname>DefaultDependencies=false</varname>
-    is used, slice units will implicitly have dependencies of
-    type <varname>Conflicts=</varname> and
-    <varname>Before=</varname> on
-    <filename>shutdown.target</filename>. These ensure
-    that slice units are removed prior to system
-    shutdown. Only slice units involved with early boot or
-    late system shutdown should disable this option.
+    <para>Unless <varname>DefaultDependencies=false</varname> is used in the <literal>[Unit]</literal> section, slice
+    units will implicitly have dependencies of type <varname>Conflicts=</varname> and <varname>Before=</varname> on
+    <filename>shutdown.target</filename>. These ensure that slice units are removed prior to system shutdown. Only
+    slice units involved with early boot or late system shutdown should disable this option.
     </para>
   </refsect1>
 
index 43841c23996144b3de099b90518622fe743efc3e..735268c79d6e3b5b1c829c9978a10791d883f109 100644 (file)
     <filename>foo@.service</filename> must exist from which services
     are instantiated for each incoming connection.</para>
 
-    <para>Unless <varname>DefaultDependencies=</varname> is set to
-    <option>false</option>, socket units will implicitly have
-    dependencies of type <varname>Requires=</varname> and
-    <varname>After=</varname> on <filename>sysinit.target</filename>
-    as well as dependencies of type <varname>Conflicts=</varname> and
-    <varname>Before=</varname> on
-    <filename>shutdown.target</filename>. These ensure that socket
-    units pull in basic system initialization, and are terminated
-    cleanly prior to system shutdown. Only sockets involved with early
-    boot or late system shutdown should disable this option.</para>
+    <para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
+    <option>false</option>, socket units will implicitly have dependencies of type <varname>Requires=</varname> and
+    <varname>After=</varname> on <filename>sysinit.target</filename> as well as dependencies of type
+    <varname>Conflicts=</varname> and <varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure
+    that socket units pull in basic system initialization, and are terminated cleanly prior to system shutdown. Only
+    sockets involved with early boot or late system shutdown should disable this option.</para>
 
     <para>Socket units will have a <varname>Before=</varname>
     dependency on the service which they trigger added implicitly. No
         suffix.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>TriggerLimitIntervalSec=</varname></term>
+        <term><varname>TriggerLimitBurst=</varname></term>
+
+        <listitem><para>Configures a limit on how often this socket unit my be activated within a specific time
+        interval. The <varname>TriggerLimitIntervalSec=</varname> may be used to configure the length of the time
+        interval in the usual time units <literal>us</literal>, <literal>ms</literal>, <literal>s</literal>,
+        <literal>min</literal>, <literal>h</literal>, … and defaults to 5s (See
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details on
+        the various time units available). The <varname>TriggerLimitBurst=</varname> setting takes an integer value and
+        specifies the numer of permitted activations per time interval, and defaults to 2500 (thus by default
+        permitting 2500 activations per 5s). Set either to 0 to disable any form of trigger rate limiting. If the limit
+        is hit, the socket unit is placed into a failure mode, and will not be connectible anymore until
+        restarted. Note that this limit is enforced before the service activation is enqueued.</para></listitem>
+      </varlistentry>
+
     </variablelist>
 
     <para>Check
index 80c15b700d9302ea6a1dbe9bcb5cc4125736da18..14998b9647dd089f6f1b11fd38d4834ddfbba69d 100644 (file)
           defined what that is supposed to mean, with one exception:
           at shutdown, a unit that is ordered after
           <filename>network.target</filename> will be stopped before
-          the network -- to whatever level it might be set up then --
+          the network — to whatever level it might be set up then —
           is shut down. It is hence useful when writing service files
           that require network access on shutdown, which should order
           themselves after this target, but not pull it in. Also see
index 69d4be4769a03ef733e12b998bc8e6a8a6326cb8..cf4e1ba8398584ef1c9f7e2fc390a914729104e3 100644 (file)
     which configure resource control settings for these processes of the
     unit.</para>
 
-    <para>Swap units must be named after the devices
-    or files they control. Example: the swap device
-    <filename noindex='true'>/dev/sda5</filename> must be configured in a
-    unit file <filename>dev-sda5.swap</filename>. For details about
-    the escaping logic used to convert a file system path to a unit
-    name, see
-    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+    <para>Swap units must be named after the devices or files they control. Example: the swap device <filename
+    noindex='true'>/dev/sda5</filename> must be configured in a unit file <filename>dev-sda5.swap</filename>. For
+    details about the escaping logic used to convert a file system path to a unit name, see
+    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that swap
+    units cannot be templated, nor is possible to add multiple names to a swap unit by creating additional symlinks to
+    it.</para>
   </refsect1>
 
   <refsect1>
     dependencies on the device units or the mount units of the files
     they are activated from.</para>
 
-    <para>Swap units with <varname>DefaultDependencies=</varname>
-    enabled implicitly acquire a <varname>Conflicts=</varname> and an
-    <varname>After=</varname> dependency on
-    <filename>umount.target</filename> so that they are deactivated at
-    shutdown, unless <varname>DefaultDependencies=no</varname> is
-    specified.</para>
+    <para>Swap units with <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section enabled
+    implicitly acquire a <varname>Conflicts=</varname> and an <varname>After=</varname> dependency on
+    <filename>umount.target</filename> so that they are deactivated at shutdown, unless
+    <varname>DefaultDependencies=no</varname> is specified.</para>
 
     <para>Additional implicit dependencies may be added as result of
     execution and resource control parameters as documented in
index bd4ab3903e7e94000ae42adf3c212a0bea224dbc..ab910d75dddbca25bbe8b972a5ae81e704bca54c 100644 (file)
   <refsect1>
     <title>Automatic Dependencies</title>
 
-    <para>Unless <varname>DefaultDependencies=</varname> is set to
-    <option>no</option>, target units will implicitly complement all
-    configured dependencies of type <varname>Wants=</varname>,
-    <varname>Requires=</varname> with dependencies of type
-    <varname>After=</varname>, unless an ordering dependency of any
-    kind between the target and the respective other unit is already
-    in place. Note that this behaviour is disabled if either unit has
-    <varname>DefaultDependencies=no</varname>.</para>
+    <para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
+    <option>no</option>, target units will implicitly complement all configured dependencies of type
+    <varname>Wants=</varname>, <varname>Requires=</varname> with dependencies of type <varname>After=</varname>, unless
+    an ordering dependency of any kind between the target and the respective other unit is already in place. Note that
+    this behaviour is disabled if either unit has <varname>DefaultDependencies=no</varname>.</para>
   </refsect1>
 
   <refsect1>
index 29e235e2dc61fb204afa1d944d58f1fe4d6c69a2..0d0cccf152202359f2f5fd481f316d45295503a7 100644 (file)
     <filename>foo.timer</filename> activates a matching service
     <filename>foo.service</filename>. The unit to activate may be
     controlled by <varname>Unit=</varname> (see below).</para>
+
+    <para>Note that in case the unit to activate is already active at the time the timer elapses it is not restarted,
+    but simply left running. There is no concept of spawning new service instances in this case. Due to this, services
+    with <varname>RemainAfterExit=</varname> set (which stay around continously even after the service's main process
+    exited) are usually not suitable for activation via repetitive timers, as they will only be activated once, and
+    then stay around forever.</para>
   </refsect1>
 
   <refsect1>
     <para>Timer units automatically gain a <varname>Before=</varname>
     dependency on the service they are supposed to activate.</para>
 
-    <para>Unless <varname>DefaultDependencies=</varname> is set to
-    <option>false</option>, all timer units will implicitly have
-    dependencies of type <varname>Requires=</varname> and
-    <varname>After=</varname> on <filename>sysinit.target</filename>,
-    a dependency of type <varname>Before=</varname> on
-    <filename>timers.target</filename>, as well as
-    <varname>Conflicts=</varname> and <varname>Before=</varname> on
-    <filename>shutdown.target</filename> to ensure that they are
-    stopped cleanly prior to system shutdown.  Timer units with at
-    least one <varname>OnCalendar=</varname> directive will have an
-    additional <varname>After=</varname> dependency on
-    <filename>timer-sync.target</filename> to avoid being started
-    before the system clock has been correctly set. Only timer units
-    involved with early boot or late system shutdown should disable
-    the <varname>DefaultDependencies=</varname> option.</para>
+    <para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
+    <option>false</option>, all timer units will implicitly have dependencies of type <varname>Requires=</varname> and
+    <varname>After=</varname> on <filename>sysinit.target</filename>, a dependency of type <varname>Before=</varname>
+    on <filename>timers.target</filename>, as well as <varname>Conflicts=</varname> and <varname>Before=</varname> on
+    <filename>shutdown.target</filename> to ensure that they are stopped cleanly prior to system shutdown.  Timer units
+    with at least one <varname>OnCalendar=</varname> directive will have an additional <varname>After=</varname>
+    dependency on <filename>timer-sync.target</filename> to avoid being started before the system clock has been
+    correctly set. Only timer units involved with early boot or late system shutdown should disable the
+    <varname>DefaultDependencies=</varname> option.</para>
   </refsect1>
 
   <refsect1>
         during the time when the timer was inactive. This is useful to
         catch up on missed runs of the service when the machine was
         off. Note that this setting only has an effect on timers
-        configured with <varname>OnCalendar=</varname>.
+        configured with <varname>OnCalendar=</varname>. Defaults
+        to <varname>false</varname>.
         </para></listitem>
       </varlistentry>
 
index f5022b03cc1827ca2095c84dddccbe8ae4ee5c77..abd47bd2372cb2793bd7d6005830ee2bf49b58c8 100644 (file)
     <para><literallayout><filename>/etc/systemd/system/*</filename>
 <filename>/run/systemd/system/*</filename>
 <filename>/usr/lib/systemd/system/*</filename>
-<filename>...</filename>
+<filename></filename>
     </literallayout></para>
 
-    <para><literallayout><filename>$XDG_CONFIG_HOME/systemd/user/*</filename>
-<filename>$HOME/.config/systemd/user/*</filename>
+    <para><literallayout><filename>~/.config/systemd/user/*</filename>
 <filename>/etc/systemd/user/*</filename>
 <filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>
 <filename>/run/systemd/user/*</filename>
-<filename>$XDG_DATA_HOME/systemd/user/*</filename>
-<filename>$HOME/.local/share/systemd/user/*</filename>
+<filename>~/.local/share/systemd/user/*</filename>
 <filename>/usr/lib/systemd/user/*</filename>
-<filename>...</filename>
+<filename></filename>
     </literallayout></para>
   </refsynopsisdiv>
 
       </varlistentry>
 
       <varlistentry>
-        <term><varname>StartLimitInterval=</varname></term>
+        <term><varname>StartLimitIntervalSec=</varname></term>
         <term><varname>StartLimitBurst=</varname></term>
 
         <listitem><para>Configure unit start rate limiting. By default, units which are started more than 5 times
         within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two
-        options, this rate limiting may be modified. Use <varname>StartLimitInterval=</varname> to configure the
-        checking interval (defaults to <varname>DefaultStartLimitInterval=</varname> in manager configuration file, set
-        to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
+        options, this rate limiting may be modified. Use <varname>StartLimitIntervalSec=</varname> to configure the
+        checking interval (defaults to <varname>DefaultStartLimitIntervalSec=</varname> in manager configuration file,
+        set to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
         starts per interval are allowed (defaults to <varname>DefaultStartLimitBurst=</varname> in manager
         configuration file). These configuration options are particularly useful in conjunction with the service
         setting <varname>Restart=</varname> (see
         manually at a later point, from which point on, the restart logic is again activated. Note that
         <command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
         which is useful if the administrator wants to manually start a unit and the start limit interferes with
-        that.</para></listitem>
+        that. Note that this rate-limiting is enforced after any unit condition checks are executed, and hence unit
+        activations with failing conditions are not counted by this rate limiting.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>StartLimitAction=</varname></term>
 
         <listitem><para>Configure the action to take if the rate limit configured with
-        <varname>StartLimitInterval=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
+        <varname>StartLimitIntervalSec=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
         <option>none</option>, <option>reboot</option>, <option>reboot-force</option>,
         <option>reboot-immediate</option>, <option>poweroff</option>, <option>poweroff-force</option> or
         <option>poweroff-immediate</option>. If <option>none</option> is set, hitting the rate limit will trigger no
       <varlistentry>
         <term><varname>Alias=</varname></term>
 
-        <listitem><para>A space-separated list of additional names
-        this unit shall be installed under. The names listed here must
-        have the same suffix (i.e. type) as the unit file name. This
-        option may be specified more than once, in which case all
-        listed names are used. At installation time,
-        <command>systemctl enable</command> will create symlinks from
-        these names to the unit filename.</para></listitem>
+        <listitem><para>A space-separated list of additional names this unit shall be installed under. The names listed
+        here must have the same suffix (i.e. type) as the unit file name. This option may be specified more than once,
+        in which case all listed names are used. At installation time, <command>systemctl enable</command> will create
+        symlinks from these names to the unit filename. Note that not all unit types support such alias names, and this
+        setting is not supported for them. Specifically, mount, slice, swap, and automount units do not support
+        aliasing.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 3b6b1e3f112f6f69f6539677b7f1430c3c2950e9..957475d2bd44fa4dbc740e66b0752429ec4c9cf8 100644 (file)
 
         <varlistentry>
           <term><varname>d</varname></term>
-          <listitem><para>Create a directory if it does not exist yet.
-          </para></listitem>
+          <listitem><para>Create a directory. The mode and ownership will be adjusted if
+          specified and the directory already exists. Contents of this directory are subject
+          to time based cleanup if the time argument is specified.</para></listitem>
         </varlistentry>
 
         <varlistentry>
           <term><varname>D</varname></term>
-          <listitem><para>Create or empty a directory.</para></listitem>
+          <listitem><para>Similar to <varname>d</varname>, but in addition the contents
+          of the directory will be removed when <option>--remove</option> is used.
+          </para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>e</varname></term>
+          <listitem><para>Similar to <varname>d</varname>, but the directory will not be
+          created if it does not exist. Lines of this type accept shell-style globs in
+          place of normal path names.</para></listitem>
         </varlistentry>
 
         <varlistentry>
       unconditionally.</para>
 
       <para>The age field only applies to lines starting with
-      <varname>d</varname>, <varname>D</varname>,
+      <varname>d</varname>, <varname>D</varname>, <varname>e</varname>,
       <varname>v</varname>, <varname>q</varname>,
       <varname>Q</varname>, <varname>C</varname>, <varname>x</varname>
       and <varname>X</varname>. If omitted or set to
   </refsect1>
 
   <refsect1>
-    <title>Example</title>
+    <title>Examples</title>
     <example>
-      <title>/etc/tmpfiles.d/screen.conf example</title>
-      <para><command>screen</command> needs two directories created at
-      boot with specific modes and ownership.</para>
+      <title>Create directories with specific mode and ownership</title>
+      <para>
+      <citerefentry><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      needs two directories created at boot with specific modes and ownership:</para>
+
+      <programlisting># /usr/lib/tmpfiles.d/screen.conf
+d /run/screens  1777 root screen 10d
+d /run/uscreens 0755 root screen 10d12h
+</programlisting>
+
+      <para>Contents of <filename>/run/screens</filename> and /run/uscreens will
+      cleaned up after 10 and 10½ days, respectively.</para>
+    </example>
 
-      <programlisting>d /run/screens  1777 root root 10d
-d /run/uscreens 0755 root root 10d12h
-t /run/screen - - - - user.name="John Smith" security.SMACK64=screen</programlisting>
+    <example>
+      <title>Create a directory with a SMACK attribute</title>
+      <programlisting>D /run/cups - - - -
+t /run/cups - - - - security.SMACK64=printing user.attr-with-spaces="foo bar"
+      </programlisting>
+
+      <para>The direcory will be owned by root and have default mode. It's contents are
+      not subject to time based cleanup, but will be obliterated when
+      <command>systemd-tmpfiles --remove</command> runs.</para>
     </example>
+
     <example>
-      <title>/etc/tmpfiles.d/abrt.conf example</title>
-      <para><command>abrt</command> needs a directory created at boot with specific mode and ownership and its content should be preserved.</para>
+      <title>Create a directory and prevent its contents from cleanup</title>
+      <para>
+      <citerefentry><refentrytitle>abrt</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      needs a directory created at boot with specific mode and ownership and its content
+      should be preserved from the automatic cleanup applied to the contents of
+      <filename>/var/tmp</filename>:</para>
+
+      <programlisting># /usr/lib/tmpfiles.d/tmp.conf
+d /var/tmp 1777 root root 30d
+</programlisting>
+
+      <programlisting># /usr/lib/tmpfiles.d/abrt.conf
+d /var/tmp/abrt 0755 abrt abrt -
+</programlisting>
+    </example>
 
-      <programlisting>d /var/tmp/abrt 0755 abrt abrt
-x /var/tmp/abrt/*</programlisting>
+    <example>
+      <title>Apply clean up during boot and based on time</title>
+
+      <programlisting># /usr/lib/tmpfiles.d/dnf.conf
+r! /var/cache/dnf/*/*/download_lock.pid
+r! /var/cache/dnf/*/*/metadata_lock.pid
+r! /var/lib/dnf/rpmdb_lock.pid
+e  /var/chache/dnf/ - - - 30d
+</programlisting>
+
+     <para>The lock files will be removed during boot. Any files and directories in
+     <filename>/var/chache/dnf/</filename> will be removed after they have not been
+     accessed in 30 days.</para>
     </example>
   </refsect1>
 
index 2774a3228f4341a67220e12df25804f6462889e1..0916707be0b4e86bd9917b81965a6ad7845442e0 100644 (file)
@@ -2,6 +2,7 @@ de
 el
 fr
 gl
+hr
 hu
 it
 ko
index 96cdc7e774dfaab4a7981cdaf2eb4a6e2edab64c..17550c755ec65903ea30b1933a8e2ec693b28643 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -1,13 +1,13 @@
 # French translations for systemd package
 # Traductions françaises du paquet systemd.
 # This file is distributed under the same license as the systemd package.
-# Sylvain Plantefève <sylvain.plantefeve@gmail.com>, 2013-2015
+# Sylvain Plantefève <sylvain.plantefeve@gmail.com>, 2013-2016
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-09-21 20:11+0200\n"
+"POT-Creation-Date: 2016-04-24 21:13+0200\n"
 "PO-Revision-Date: 2014-12-28 13:04+0100\n"
 "Last-Translator: Sylvain Plantefève <sylvain.plantefeve@gmail.com>\n"
 "Language-Team: French\n"
@@ -254,48 +254,58 @@ msgstr ""
 "gestion par le système du rabat de l'écran."
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in user to run programs"
+msgstr "Permet à un utilisateur non connecté d'exécuter des programmes"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"Requête explicite requise pour exécuter des programmes en tant "
+"qu'utilisateur non connecté."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
 msgid "Allow non-logged-in users to run programs"
 msgstr "Permet aux utilisateurs non connectés d'exécuter des programmes"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
-"Authentification requise pour permettre aux utilisateurs non connectés "
-"d'exécuter des programmes."
+"Authentification requise pour exécuter des programmes en tant qu'utilisateur "
+"non connecté."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
 msgid "Allow attaching devices to seats"
 msgstr "Permet d'associer des périphériques à des postes (seats)"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
 msgid "Authentication is required for attaching a device to a seat."
 msgstr ""
 "Authentification requise pour associer un périphérique à un poste (seat)."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
 msgid "Flush device to seat attachments"
 msgstr "Révoquer les associations de périphériques aux postes (seats)"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
 msgid ""
 "Authentication is required for resetting how devices are attached to seats."
 msgstr ""
 "Authentification requise pour révoquer les associations de périphériques aux "
 "postes (seats)."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
 msgid "Power off the system"
 msgstr "Éteindre le système"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
 msgid "Authentication is required for powering off the system."
 msgstr "Authentification requise pour éteindre le système."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
 msgid "Power off the system while other users are logged in"
 msgstr "Éteindre le système alors que d'autres utilisateurs sont connectés"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
 msgid ""
 "Authentication is required for powering off the system while other users are "
 "logged in."
@@ -303,11 +313,11 @@ msgstr ""
 "Authentification requise pour éteindre le système alors que d'autres "
 "utilisateurs sont connectés."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
 msgid "Power off the system while an application asked to inhibit it"
 msgstr "Éteindre le système alors qu'une application a demandé de l'empêcher"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
 msgid ""
 "Authentication is required for powering off the system while an application "
 "asked to inhibit it."
@@ -315,19 +325,19 @@ msgstr ""
 "Authentification requise pour éteindre le système alors qu'une application a "
 "demandé de l'empêcher."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
 msgid "Reboot the system"
 msgstr "Redémarrer le système"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
 msgid "Authentication is required for rebooting the system."
 msgstr "Authentification requise pour redémarrer le système."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
 msgid "Reboot the system while other users are logged in"
 msgstr "Redémarrer le système alors que d'autres utilisateurs sont connectés"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
 msgid ""
 "Authentication is required for rebooting the system while other users are "
 "logged in."
@@ -335,11 +345,11 @@ msgstr ""
 "Authentification requise pour redémarrer le système alors que d'autres "
 "utilisateurs sont connectés."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
 msgid "Reboot the system while an application asked to inhibit it"
 msgstr "Redémarrer le système alors qu'une application a demandé de l'empêcher"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
 msgid ""
 "Authentication is required for rebooting the system while an application "
 "asked to inhibit it."
@@ -347,20 +357,20 @@ msgstr ""
 "Authentification requise pour redémarrer le système alors qu'une application "
 "a demandé de l'empêcher."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
 msgid "Suspend the system"
 msgstr "Mettre le système en veille"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
 msgid "Authentication is required for suspending the system."
 msgstr "Authentification requise pour mettre le système en veille."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
 msgid "Suspend the system while other users are logged in"
 msgstr ""
 "Mettre le système en veille alors que d'autres utilisateurs sont connectés"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
 msgid ""
 "Authentication is required for suspending the system while other users are "
 "logged in."
@@ -368,12 +378,12 @@ msgstr ""
 "Authentification requise pour mettre le système en veille alors que d'autres "
 "utilisateurs sont connectés."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
 msgid "Suspend the system while an application asked to inhibit it"
 msgstr ""
 "Mettre le système en veille alors qu'une application a demandé de l'empêcher"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
 msgid ""
 "Authentication is required for suspending the system while an application "
 "asked to inhibit it."
@@ -381,21 +391,21 @@ msgstr ""
 "Authentification requise pour mettre le système en veille alors qu'une "
 "application a demandé de l'empêcher."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
 msgid "Hibernate the system"
 msgstr "Mettre le système en hibernation"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
 msgid "Authentication is required for hibernating the system."
 msgstr "Authentification requise pour mettre le système en hibernation."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
 msgid "Hibernate the system while other users are logged in"
 msgstr ""
 "Mettre le système en hibernation alors que d'autres utilisateurs sont "
 "connectés"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
 msgid ""
 "Authentication is required for hibernating the system while other users are "
 "logged in."
@@ -403,13 +413,13 @@ msgstr ""
 "Authentification requise pour mettre le système en hibernation alors que "
 "d'autres utilisateurs sont connectés."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
 msgid "Hibernate the system while an application asked to inhibit it"
 msgstr ""
 "Mettre le système en hibernation alors qu'une application a demandé de "
 "l'empêcher"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
 msgid ""
 "Authentication is required for hibernating the system while an application "
 "asked to inhibit it."
@@ -417,34 +427,34 @@ msgstr ""
 "Authentification requise pour mettre le système en hibernation alors qu'une "
 "application a demandé de l'empêcher."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
 msgid "Manage active sessions, users and seats"
 msgstr "Gérer les sessions actives, les utilisateurs et les postes (seats)"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
 msgid ""
 "Authentication is required for managing active sessions, users and seats."
 msgstr ""
 "Authentification requise pour gérer les sessions actives, les utilisateurs "
 "et les postes (seats)."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
 msgid "Lock or unlock active sessions"
 msgstr "Verrouiller ou déverrouiller des sessions actives"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
 msgid "Authentication is required to lock or unlock active sessions."
 msgstr ""
 "Authentification requise pour verrouiller ou déverrouiller des sessions "
 "actives."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
 msgid "Allow indication to the firmware to boot to setup interface"
 msgstr ""
 "Permet d'indiquer au micrologiciel de démarrer sur l'interface de "
 "configuration"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
@@ -452,11 +462,11 @@ msgstr ""
 "Authentification requise pour indiquer au micrologiciel de démarrer sur "
 "l'interface de configuration."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
 msgid "Set a wall message"
 msgstr "Définir un message wall"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
 msgid "Authentication is required to set a wall message"
 msgstr "Authentification requise pour définir un message wall."
 
@@ -581,33 +591,33 @@ msgstr ""
 "Authentification requise pour activer ou désactiver la synchronisation de "
 "l'heure avec le réseau."
 
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Authentification requise pour démarrer « $(unit) »."
 
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Authentification requise pour arrêter « $(unit) »."
 
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
 msgid "Authentication is required to reload '$(unit)'."
 msgstr "Authentification requise pour recharger « $(unit) »."
 
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
 msgid "Authentication is required to restart '$(unit)'."
 msgstr "Authentification requise pour redémarrer « $(unit) »."
 
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
 msgid "Authentication is required to kill '$(unit)'."
 msgstr "Authentification requise pour tuer « $(unit) »."
 
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Authentification requise pour réinitialiser l'état d'« échec » de "
 "« $(unit) »."
 
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr "Authentification requise pour définir des propriétés de « $(unit) »."
 
diff --git a/po/hr.po b/po/hr.po
new file mode 100644 (file)
index 0000000..a0aff43
--- /dev/null
+++ b/po/hr.po
@@ -0,0 +1,570 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# gogo <trebelnik2@gmail.com>, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: systemd master\n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
+"POT-Creation-Date: 2016-27-04 11:57+0100\n"
+"PO-Revision-Date: 2016-04-27 12:11+0200\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7.1\n"
+"Last-Translator: gogo <trebelnik2@gmail.com>com>\n"
+"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Language: hr\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Pošalji lozinku natrag u sustav"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr "Potrebna je ovjera za slanje upisane lozinke natrag u sustav."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Upravljajte uslugama sustava ili drugim jedinicama"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr "Potrebna je ovjera za upravljanje uslugama sustava ili jedinicama."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Upravljajte uslugama sustava ili datotekama jedinica"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr ""
+"Potrebna je ovjera za upravljanje uslugama sustava ili datotekama jedinica."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "Postavite ili uklonite varijable okruženja sustava i usluga"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Potrebna je ovjera za postavljanje ili uklanjanje varijabla okruženja "
+"sustava i usluga."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Ponovno učitaj systemd stanje"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Potrebna je ovjera za ponovno učitavanje systemd stanja."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+msgid "Set host name"
+msgstr "Postavi naziv računala"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+msgid "Authentication is required to set the local host name."
+msgstr "Potrebna je ovjera za postavljanje naziva lokalnog računala."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+msgid "Set static host name"
+msgstr "Postavi nepromjenjivi naziv račumala"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
+msgid ""
+"Authentication is required to set the statically configured local host name, "
+"as well as the pretty host name."
+msgstr ""
+"Potrebna je ovjera za postavljenje nepromjenjivog naziva lokalnog računala, "
+"kao i prijatnog naziva računala."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+msgid "Set machine information"
+msgstr "Postavi informacije računala"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+msgid "Authentication is required to set local machine information."
+msgstr "Potrebna je ovjera za postavljanje informacije lokalnog računala."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Uvezi VM ili spremnik slike"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr "Potrebna je ovjera za uvoz WM ili spremnika slike"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Izvezi VM ili spremnik slike"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr "Potrebna je ovjera za izvoz WM ili spremnika slike"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "Preuzmi VM ili spremnik slike"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr "Potrebna je ovjera za preuzimanje VM ili spremnika slike."
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+msgid "Set system locale"
+msgstr "Postavi sustav lokalizacije"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+msgid "Authentication is required to set the system locale."
+msgstr "Potrebna je ovjera za postavljanje sustava lokalizacije."
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+msgid "Set system keyboard settings"
+msgstr "Postavi postavke tipkovnice sustava"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+msgid "Authentication is required to set the system keyboard settings."
+msgstr "Potrebna je ovjera za postavljanje postavki tipkovnice sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:1
+msgid "Allow applications to inhibit system shutdown"
+msgstr "Dopusti aplikacijama zaustavljanje isključivanja sustava"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:2
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama zaustavljanje isključivanja "
+"sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:3
+msgid "Allow applications to delay system shutdown"
+msgstr "Dopusti aplikacijama odgodu isključivanja sustava"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:4
+msgid "Authentication is required for an application to delay system shutdown."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama odgode isključivanja sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:5
+msgid "Allow applications to inhibit system sleep"
+msgstr "Dopusti aplikacijama zaustavljanje spavanja sustava"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:6
+msgid "Authentication is required for an application to inhibit system sleep."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama zaustavljanja spavanja sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:7
+msgid "Allow applications to delay system sleep"
+msgstr "Dopusti aplikacijama odgodu spavanja sustava"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:8
+msgid "Authentication is required for an application to delay system sleep."
+msgstr "Potrebna je ovjera za odgodu spavanja sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:9
+msgid "Allow applications to inhibit automatic system suspend"
+msgstr "Dopusti aplikacijama zaustavljanje automatskog suspendiranja sustava"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:10
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama zaustavljanje automatskog "
+"suspendiranja sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:11
+msgid "Allow applications to inhibit system handling of the power key"
+msgstr ""
+"Dopusti aplikacijama sprječavanje rukovanja sustava tipkom isključivanja"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:12
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the power key."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama sprječavanje rukovanja sustava "
+"tipkom isključivanja."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:13
+msgid "Allow applications to inhibit system handling of the suspend key"
+msgstr "Dopusti aplikacijama sprječavanje rukovanja sustava tipkom suspenzije"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:14
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the suspend key."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama sprječavanje rukovanja sustava "
+"tipkom suspenzije."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:15
+msgid "Allow applications to inhibit system handling of the hibernate key"
+msgstr "Dopusti aplikacijama sprječavanje rukovanja sustava tipkom hibernacije"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:16
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the hibernate key."
+msgstr ""
+"Potrebna je ovjera za dopuštanje aplikacijama sprječavanje rukovanja sustava "
+"tipkom hibernacije."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:17
+msgid "Allow applications to inhibit system handling of the lid switch"
+msgstr "Dopusti aplikacijama sprječavanje rukovanja sustava preklopnicama"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:18
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the lid switch."
+msgstr ""
+"Potrebna je ovjera za dopuštenje sprječavanja rukovanja sustava "
+"preklopnicama."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in users to run programs"
+msgstr "Dopusti neprijavljenim korisnicima pokretanje programa"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Authentication is required to run programs as a non-logged-in user."
+msgstr ""
+"Potrebna je ovjera za dopuštenje neprijavljenim korisnicima pokretanje "
+"programa."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow attaching devices to seats"
+msgstr "Dopusti povezivanje uređaja skupu sesija i hardvera"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
+msgid "Authentication is required for attaching a device to a seat."
+msgstr "Potrebna je ovjera za povezivanje uređaja sa skupom sesija i hardvera."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
+msgid "Flush device to seat attachments"
+msgstr "Ukloni povezani uređaj sa skupa sesija i hardvera"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr ""
+"Potrebna je ovjera za obnovu povezivanja uređaja sa skupom sesija i hardvera."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
+msgid "Power off the system"
+msgstr "Isključi sustav"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
+msgid "Authentication is required for powering off the system."
+msgstr "Potrebna je ovjera za isključivanje sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
+msgid "Power off the system while other users are logged in"
+msgstr "Isključi sustav kada su ostali korisnici prijavljeni"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
+msgid ""
+"Authentication is required for powering off the system while other users are "
+"logged in."
+msgstr ""
+"Potrebna je ovjera za isključivanje sustava kada su ostali korisnici "
+"prijavljeni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
+msgid "Power off the system while an application asked to inhibit it"
+msgstr ""
+"Isključi sustav kada je aplikacija zatražila zaustavljanje isključivanja"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
+msgid ""
+"Authentication is required for powering off the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Potrebna je ovjera za isključivanje sustava kada je aplikacija zatražila "
+"zaustavljanje isključivanja."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
+msgid "Reboot the system"
+msgstr "Ponovno pokreni sustav"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
+msgid "Authentication is required for rebooting the system."
+msgstr "Potrebna je ovjera za ponovno pokretanje sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
+msgid "Reboot the system while other users are logged in"
+msgstr "Ponovno pokreni sustav kada su ostali korisnici prijavljeni"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr ""
+"Potrebna je ovjera za ponovno pokretanje sustava kada su ostali korisnici "
+"prijavljeni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
+msgid "Reboot the system while an application asked to inhibit it"
+msgstr ""
+"Ponovno pokreni sustav kada je aplikacija zatražila zaustavljanje ponovnog "
+"pokretanja"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
+msgid ""
+"Authentication is required for rebooting the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Potrebna je ovjera za ponovno pokretanje sustava kada je aplikacija "
+"zatražila zaustavljanje ponovnog pokretanja."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
+msgid "Suspend the system"
+msgstr "Suspendiraj sustav"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
+msgid "Authentication is required for suspending the system."
+msgstr "Potrebna je ovjera za suspendiranje sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
+msgid "Suspend the system while other users are logged in"
+msgstr "Suspendiraj sustav kada su drugi korisnici prijavljeni"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr ""
+"Potrebna je ovjera za suspendiranje sustava kada su drugi korisnici "
+"prijavljeni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
+msgid "Suspend the system while an application asked to inhibit it"
+msgstr ""
+"Suspendiraj sustav kada je aplikacija zatražila zaustavljanje suspendiranja"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
+msgid ""
+"Authentication is required for suspending the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Potrebna je ovjera za suspendiranje sustava kada je aplikacija zatražila "
+"zaustavljanje suspendiranja."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
+msgid "Hibernate the system"
+msgstr "Hiberniraj sustav"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
+msgid "Authentication is required for hibernating the system."
+msgstr "Potrebna je ovjera za hibernaciju sustava."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
+msgid "Hibernate the system while other users are logged in"
+msgstr "Hiberniraj sustav kada su ostali korisnici prijavljeni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr ""
+"Potrebna je ovjera za hibernaciju sustava kada su drugi korisnici "
+"prijavljeni."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
+msgid "Hibernate the system while an application asked to inhibit it"
+msgstr ""
+"Hiberniraj sustav kada je aplikacija zatražila zaustavljanje hibernacije"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
+msgid ""
+"Authentication is required for hibernating the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Potrebna je ovjera za hibernaciju sustava kada je aplikacija zatražila "
+"zaustavljanje hibernacije."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr ""
+"Upravljanje aktivnim sesijama, korisnicima i skupovima sesija i hardvera"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Potrebna je ovjera za upravljanje aktivnim sesijama, korisnicima i skupovima "
+"sesija i hardvera."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Zaključavanje ili otključavanje aktivne sesije"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "Potrebna je ovjera za zaključavanje ili otključavanje aktivne sesije."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr "Dopusti najavu frimveru za pokretanje sučelja postavljanja"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr "Potrebna je ovjera najave frimvera za pokretanje sučelja postavljanja."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
+msgid "Set a wall message"
+msgstr "Postavljanje zaslonske pruke"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
+msgid "Authentication is required to set a wall message"
+msgstr "Potrebna je ovjera za postavljanje zaslonske pruke."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+msgid "Log into a local container"
+msgstr "Prijavi se u lokalni spremnik"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+msgid "Authentication is required to log into a local container."
+msgstr "Potrebna je ovjera za prijavu u lokalni spremnik."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Log into the local host"
+msgstr "Prijava na lokalno računalo"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid "Authentication is required to log into the local host."
+msgstr "Potrebna je ovjera za prijavu na lokalno račuanlo."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Acquire a shell in a local container"
+msgstr "Pokretanje ljuske u lokalnom spremniku"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to acquire a shell in a local container."
+msgstr "Potrebna je ovjera za pokretanje ljuske u lokalnom spremniku."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+msgid "Acquire a shell on the local host"
+msgstr "Pokretanje ljuske na lokalnom računalu"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+msgid "Authentication is required to acquire a shell on the local host."
+msgstr "Potrebna je ovjera za pokretanje ljuske na lokalnom računalu."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+msgid "Acquire a pseudo TTY in a local container"
+msgstr "Pokretanje pseudo TTY na lokalnom spremniku"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
+msgstr "Potrebna je ovjera za pokretanje pseudo TTY na lokalnom spremniku."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+msgid "Acquire a pseudo TTY on the local host"
+msgstr "Pokretanje pseudo TTY na lokalnom računalu"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+msgid "Authentication is required to acquire a pseudo TTY on the local host."
+msgstr "Potrebna je ovjera za pokretanje pseudo TTY na lokalnom računalu."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+msgid "Manage local virtual machines and containers"
+msgstr "Upravljanje lokalnim vurtualnim strojevima i spremnicima"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Potrebna je ovjera za upravljanje lokalnim vurtualnim strojevima i "
+"spremnicima."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
+msgid "Manage local virtual machine and container images"
+msgstr "Upravljanje lokalnim vurtualnim strojevima i spremnicima slika"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Potrebna je ovjera za upravljanje lokalnim vurtualnim strojevima i "
+"spremnicima slika."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+msgid "Set system time"
+msgstr "Postavi vrijeme sustava"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+msgid "Authentication is required to set the system time."
+msgstr "Potrebna je ovjera za postavljanje vremena sustava."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+msgid "Set system timezone"
+msgstr "Postavi vremensku zonu sustava"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+msgid "Authentication is required to set the system timezone."
+msgstr "Potrebna je ovjera za postavljanje vremenske zone sustava."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+msgid "Set RTC to local timezone or UTC"
+msgstr "Postavi RTC u lokalnu vremensku zonu ili UTC"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6
+msgid ""
+"Authentication is required to control whether the RTC stores the local or "
+"UTC time."
+msgstr ""
+"Potrebna je ovjera za postavljanje RTC-a u lokalnu vremensku zonu ili UTC."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+msgid "Turn network time synchronization on or off"
+msgstr "Uključi ili isključi mrežno uklađivanje vremena"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+msgid ""
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
+msgstr ""
+"Potrebna je ovjera za uključivanje ili isključivanje mrežnog usklađivanja "
+"vremena."
+
+#: ../src/core/dbus-unit.c:428
+msgid "Authentication is required to start '$(unit)'."
+msgstr "Potrebna je ovjera za pokretanje '$(unit)'."
+
+#: ../src/core/dbus-unit.c:429
+msgid "Authentication is required to stop '$(unit)'."
+msgstr "Potrebna je ovjera za zaustavljanje '$(unit)'."
+
+#: ../src/core/dbus-unit.c:430
+msgid "Authentication is required to reload '$(unit)'."
+msgstr "Potrebna je ovjera za ponovno učitavnje '$(unit)'."
+
+#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+msgid "Authentication is required to restart '$(unit)'."
+msgstr "Potrebna je ovjera za ponovno pokretanje'$(unit)'."
+
+#: ../src/core/dbus-unit.c:535
+msgid "Authentication is required to kill '$(unit)'."
+msgstr "Potrebna je ovjera za ubijanje '$(unit)'."
+
+#: ../src/core/dbus-unit.c:565
+msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
+msgstr "Potrebna je ovjera za vraćanje \"neuspjelog\" stanja '$(unit)'."
+
+#: ../src/core/dbus-unit.c:597
+msgid "Authentication is required to set properties on '$(unit)'."
+msgstr "Potrebna je ovjera za postavljanje svojstava na '$(unit)'."
index d3e2ae8418d58582ff863f197cd2114c7e0dabfa..92e9a209cca4f576b243edeaf8c43ff14f5a99e0 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,13 +1,13 @@
 # translation of pl.po to Polish
-# Piotr Drąg <piotrdrag@gmail.com>, 2011, 2013, 2014, 2015.
+# Piotr Drąg <piotrdrag@gmail.com>, 2011, 2013, 2014, 2015, 2016.
 # Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>, 2011.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-09-06 20:39+0200\n"
-"PO-Revision-Date: 2015-09-06 20:40+0200\n"
+"POT-Creation-Date: 2016-04-23 14:24+0200\n"
+"PO-Revision-Date: 2016-04-23 14:25+0200\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
 "Language: pl\n"
@@ -241,48 +241,58 @@ msgstr ""
 "przez system."
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in user to run programs"
+msgstr "Zezwolenie niezalogowanemu użytkownikowi na uruchamianie programów"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Explicit request is required to run programs as a non-logged-in user."
+msgstr ""
+"Wymagane jest bezpośrednie żądanie, aby uruchamiać programy jako "
+"niezalogowany użytkownik."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
 msgid "Allow non-logged-in users to run programs"
 msgstr "Zezwolenie niezalogowanym użytkownikom na uruchamianie programów"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
 msgid "Authentication is required to run programs as a non-logged-in user."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby uruchamiać programy jako niezalogowany "
 "użytkownik."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
 msgid "Allow attaching devices to seats"
 msgstr "Zezwolenie na podłączanie urządzeń do stanowisk"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
 msgid "Authentication is required for attaching a device to a seat."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby podłączyć urządzenie do stanowiska."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
 msgid "Flush device to seat attachments"
 msgstr "Usunięcie podłączenia urządzeń do stanowisk"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
 msgid ""
 "Authentication is required for resetting how devices are attached to seats."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie ustawić sposób podłączenia "
 "urządzeń do stanowisk."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
 msgid "Power off the system"
 msgstr "Wyłączenie systemu"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
 msgid "Authentication is required for powering off the system."
 msgstr "Wymagane jest uwierzytelnienie, aby wyłączyć system."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
 msgid "Power off the system while other users are logged in"
 msgstr "Wyłączenie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
 msgid ""
 "Authentication is required for powering off the system while other users are "
 "logged in."
@@ -290,11 +300,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy są zalogowani "
 "inni użytkownicy."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
 msgid "Power off the system while an application asked to inhibit it"
 msgstr "Wyłączenie systemu, kiedy program zażądał jego wstrzymania"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
 msgid ""
 "Authentication is required for powering off the system while an application "
 "asked to inhibit it."
@@ -302,19 +312,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wyłączyć system, kiedy program zażądał "
 "jego wstrzymania."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
 msgid "Reboot the system"
 msgstr "Ponowne uruchomienie systemu"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
 msgid "Authentication is required for rebooting the system."
 msgstr "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
 msgid "Reboot the system while other users are logged in"
 msgstr "Ponowne uruchomienie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
 msgid ""
 "Authentication is required for rebooting the system while other users are "
 "logged in."
@@ -322,11 +332,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy są "
 "zalogowani inni użytkownicy."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
 msgid "Reboot the system while an application asked to inhibit it"
 msgstr "Ponowne uruchomienie systemu, kiedy program zażądał jego wstrzymania"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
 msgid ""
 "Authentication is required for rebooting the system while an application "
 "asked to inhibit it."
@@ -334,19 +344,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić system, kiedy program "
 "zażądał jego wstrzymania."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
 msgid "Suspend the system"
 msgstr "Uśpienie systemu"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
 msgid "Authentication is required for suspending the system."
 msgstr "Wymagane jest uwierzytelnienie, aby uśpić system."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
 msgid "Suspend the system while other users are logged in"
 msgstr "Uśpienie systemu, kiedy są zalogowani inni użytkownicy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
 msgid ""
 "Authentication is required for suspending the system while other users are "
 "logged in."
@@ -354,11 +364,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby uśpić system, kiedy są zalogowani inni "
 "użytkownicy."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
 msgid "Suspend the system while an application asked to inhibit it"
 msgstr "Uśpienie systemu, kiedy program zażądał jego wstrzymania"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
 msgid ""
 "Authentication is required for suspending the system while an application "
 "asked to inhibit it."
@@ -366,19 +376,19 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby uśpić system, kiedy program zażądał jego "
 "wstrzymania."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
 msgid "Hibernate the system"
 msgstr "Hibernacja systemu"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
 msgid "Authentication is required for hibernating the system."
 msgstr "Wymagane jest uwierzytelnienie, aby zahibernować system."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
 msgid "Hibernate the system while other users are logged in"
 msgstr "Hibernacja systemu, kiedy są zalogowani inni użytkownicy"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
 msgid ""
 "Authentication is required for hibernating the system while other users are "
 "logged in."
@@ -386,11 +396,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy są zalogowani "
 "inni użytkownicy."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
 msgid "Hibernate the system while an application asked to inhibit it"
 msgstr "Hibernacja systemu, kiedy program zażądał jej wstrzymania"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
 msgid ""
 "Authentication is required for hibernating the system while an application "
 "asked to inhibit it."
@@ -398,31 +408,31 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zahibernować system, kiedy program "
 "zażądał jej wstrzymania."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
 msgid "Manage active sessions, users and seats"
 msgstr "Zarządzanie aktywnymi sesjami, użytkownikami i stanowiskami"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
 msgid ""
 "Authentication is required for managing active sessions, users and seats."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby zarządzać aktywnymi sesjami, "
 "użytkownikami i stanowiskami."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
 msgid "Lock or unlock active sessions"
 msgstr "Zablokowanie lub odblokowanie aktywnych sesji"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
 msgid "Authentication is required to lock or unlock active sessions."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby zablokować lub odblokować aktywne sesje."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
 msgid "Allow indication to the firmware to boot to setup interface"
 msgstr "Wskazanie oprogramowaniu sprzętowemu, aby uruchomić interfejs ustawień"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
@@ -430,11 +440,11 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wskazać oprogramowaniu sprzętowemu, że "
 "należy uruchomić interfejs ustawień."
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
+#: ../src/login/org.freedesktop.login1.policy.in.h:57
 msgid "Set a wall message"
 msgstr "Ustawienie komunikatu wall"
 
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#: ../src/login/org.freedesktop.login1.policy.in.h:58
 msgid "Authentication is required to set a wall message"
 msgstr "Wymagane jest uwierzytelnienie, aby ustawić komunikat wall"
 
@@ -557,36 +567,36 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
 "czasu przez sieć."
 
-#: ../src/core/dbus-unit.c:428
+#: ../src/core/dbus-unit.c:450
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
 
-#: ../src/core/dbus-unit.c:429
+#: ../src/core/dbus-unit.c:451
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
 
-#: ../src/core/dbus-unit.c:430
+#: ../src/core/dbus-unit.c:452
 msgid "Authentication is required to reload '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
 
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+#: ../src/core/dbus-unit.c:453 ../src/core/dbus-unit.c:454
 msgid "Authentication is required to restart '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
 
-#: ../src/core/dbus-unit.c:535
+#: ../src/core/dbus-unit.c:560
 msgid "Authentication is required to kill '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby wymusić wyłączenie jednostki „$(unit)”."
 
-#: ../src/core/dbus-unit.c:565
+#: ../src/core/dbus-unit.c:590
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
 "jednostki „$(unit)”."
 
-#: ../src/core/dbus-unit.c:597
+#: ../src/core/dbus-unit.c:622
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
index 0b14bb4a112c4286cef1feeba26bd78b6b29321b..7ad8a557ffc775703dfd601fbec224c35af5ea2b 100644 (file)
@@ -14,6 +14,10 @@ TEST=="whole_disk", GOTO="persistent_storage_end"
 # for partitions import parent information
 ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
 
+# NVMe
+KERNEL=="nvme*[0-9]n*[0-9]", ATTR{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}"
+KERNEL=="nvme*[0-9]n*[0-9]p*[0-9]", ENV{DEVTYPE}=="partition", ATTRS{wwid}=="?*", SYMLINK+="disk/by-id/nvme-$attr{wwid}-part%n"
+
 # virtio-blk
 KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
 KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n"
index 5c2cda51eca3925a240fe387e59f8189b01b07b0..fb4517606d395454a63b22140aa51776776bbd69 100644 (file)
@@ -11,7 +11,7 @@ SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270
 KERNEL=="vport*", TAG+="systemd"
 
 SUBSYSTEM=="block", TAG+="systemd"
-SUBSYSTEM=="block", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
 
 # Ignore encrypted devices with no identified superblock on it, since
 # we are probably still calling mke2fs or mkswap on it.
@@ -24,8 +24,8 @@ SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="
 # Ignore loop devices that don't have any file attached
 SUBSYSTEM=="block", KERNEL=="loop[0-9]*", ENV{DEVTYPE}=="disk", TEST!="loop/backing_file", ENV{SYSTEMD_READY}="0"
 
-# Ignore nbd devices in the "add" event, with "change" the nbd is ready
-ACTION=="add", SUBSYSTEM=="block", KERNEL=="nbd*", ENV{SYSTEMD_READY}="0"
+# Ignore nbd devices until the PID file exists (which signals a connected device)
+SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTEMD_READY}="0"
 
 # We need a hardware independent way to identify network devices. We
 # use the /sys/subsystem/ path for this. Kernel "bus" and "class" names
index 833c7e2bb1b96a7e262eacdb01607be1e99b11bb..e4c04a697fa639b0ed59130a91357de86088d3b5 100644 (file)
@@ -16,7 +16,7 @@ _coredumpctl_command(){
         cmd="${${_coredumpctl_cmds[(r)$words[1]:*]%%:*}}"
         if (( $#cmd  )); then
             # user can set zstyle ':completion:*:*:coredumpctl:*' sort no for coredumps to be ordered by date, otherwise they get ordered by pid
-            _dumps=( "${(foa)$(coredumpctl list | awk 'BEGIN{OFS=":"} /^\s/ {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" )
+            _dumps=( "${(foa)$(coredumpctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $5,$0}' 2>/dev/null)}" )
             if [[ -n "$_dumps" ]]; then
                 _describe -t pids 'coredumps' _dumps
             else
diff --git a/shell-completion/zsh/_networkctl b/shell-completion/zsh/_networkctl
new file mode 100644 (file)
index 0000000..61f173b
--- /dev/null
@@ -0,0 +1,35 @@
+#compdef networkctl
+
+_networkctl_command(){
+    local -a _networkctl_cmds
+    _networkctl_cmds=(
+            'list:List existing links'
+           'status:Show information about the specified links'
+           'lldp:Show Link Layer Discovery Protocol status'
+    )
+    if (( CURRENT == 1 )); then
+        _describe -t commands 'networkctl command' _networkctl_cmds
+    else
+        local curcontext="$curcontext"
+        local -a _links
+        cmd="${${_networkctl_cmds[(r)$words[1]:*]%%:*}}"
+        if [ $cmd = "status" ]; then
+            _links=( "${(foa)$(networkctl list --no-legend | awk 'BEGIN{OFS=":"} {sub(/[[ \t]+/, ""); print $2,$0}' 2>/dev/null)}" )
+            if [[ -n "$_links" ]]; then
+                _describe -t links 'links' _links
+            else
+                _message "no links"
+            fi
+        else
+            _message "no more options"
+        fi
+    fi
+}
+
+_arguments \
+    {-a,--all}'[Show all links with status]' \
+    '--no-pager[Do not pipe output into a pager]' \
+    '--no-legend[Do not print the column headers]' \
+    {-h,--help}'[Show this help]' \
+    '--version[Show package version]' \
+    '*::networkctl commands:_networkctl_command'
index 8ac8dd8e727f459f8da42637d8fac2cdbb086e87..a0cfc22000a395e695314caeee2ccd5eeb584ea3 100644 (file)
@@ -316,19 +316,31 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) {
 }
 
 /* SIGCHLD handler. */
-static void sigchld_hdl(int sig, siginfo_t *t, void *data) {
+static void sigchld_hdl(int sig) {
         PROTECT_ERRNO;
 
-        log_info("Child %d died with code %d", t->si_pid, t->si_status);
+        for (;;) {
+                siginfo_t si;
+                int r;
 
-        /* Wait for a dead child. */
-        (void) waitpid(t->si_pid, NULL, 0);
+                si.si_pid = 0;
+                r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG);
+                if (r < 0) {
+                        if (errno != ECHILD)
+                                log_error_errno(errno, "Failed to reap children: %m");
+                        return;
+                }
+                if (si.si_pid == 0)
+                        return;
+
+                log_info("Child %d died with code %d", si.si_pid, si.si_status);
+        }
 }
 
 static int install_chld_handler(void) {
         static const struct sigaction act = {
-                .sa_flags = SA_SIGINFO,
-                .sa_sigaction = sigchld_hdl,
+                .sa_flags = SA_NOCLDSTOP,
+                .sa_handler = sigchld_hdl,
         };
 
         int r;
index b83f559e7db931d92970223d1e8b656d785beef6..5fd3ee49eb30228d7ad149af9652accad96ce76d 100644 (file)
@@ -231,14 +231,12 @@ static int verify_unit(Unit *u, bool check_man) {
         return r;
 }
 
-int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
+int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
         _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *var = NULL;
         Manager *m = NULL;
         FILE *serial = NULL;
         FDSet *fdset = NULL;
-
-        _cleanup_free_ char *var = NULL;
-
         char **filename;
         int r = 0, k;
 
@@ -255,7 +253,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man)
 
         assert_se(set_unit_path(var) >= 0);
 
-        r = manager_new(running_as, true, &m);
+        r = manager_new(scope, true, &m);
         if (r < 0)
                 return log_error_errno(r, "Failed to initialize manager: %m");
 
index 27c253a56280439d4f2a3c9937d258832d3faece..d8204dc69c01421c7c209e2f4ac71a9f2bb5de16 100644 (file)
@@ -23,4 +23,4 @@
 
 #include "path-lookup.h"
 
-int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man);
+int verify_units(char **filenames, UnitFileScope scope, bool check_man);
index 42754a27415e589cfd8c7fc874d3b528bf7216d2..a790ccd33e00ef22cdb5ad7a86bd5be31ad84645 100644 (file)
@@ -28,6 +28,7 @@
 #include "alloc-util.h"
 #include "analyze-verify.h"
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "glob-util.h"
 #include "hashmap.h"
@@ -1443,7 +1444,7 @@ int main(int argc, char *argv[]) {
 
         if (streq_ptr(argv[optind], "verify"))
                 r = verify_units(argv+optind+1,
-                                 arg_user ? MANAGER_USER : MANAGER_SYSTEM,
+                                 arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
                                  arg_man);
         else {
                 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
index a9ecfc1cd632245210af1eef14d5e26898dbf5cc..8e2c2b02d2dc9a90cc1135ad3e7c5fe55aef14dd 100644 (file)
@@ -121,6 +121,8 @@ int uname_architecture(void) {
                 { "tilegx",     ARCHITECTURE_TILEGX   },
 #elif defined(__cris__)
                 { "crisv32",    ARCHITECTURE_CRIS     },
+#elif defined(__nios2__)
+                { "nios2",      ARCHITECTURE_NIOS2    },
 #else
 #error "Please register your architecture here!"
 #endif
@@ -171,6 +173,7 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
         [ARCHITECTURE_M68K] = "m68k",
         [ARCHITECTURE_TILEGX] = "tilegx",
         [ARCHITECTURE_CRIS] = "cris",
+        [ARCHITECTURE_NIOS2] = "nios2",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(architecture, int);
index c22cbc82798cbbe66fb14c331661d1e4fdbef250..91ec108e04d712d2a809751674b45d3f84c030d7 100644 (file)
@@ -57,6 +57,7 @@ enum {
         ARCHITECTURE_M68K,
         ARCHITECTURE_TILEGX,
         ARCHITECTURE_CRIS,
+        ARCHITECTURE_NIOS2,
         _ARCHITECTURE_MAX,
         _ARCHITECTURE_INVALID = -1
 };
@@ -187,6 +188,9 @@ int uname_architecture(void);
 #elif defined(__cris__)
 #  define native_architecture() ARCHITECTURE_CRIS
 #  error "Missing LIB_ARCH_TUPLE for CRIS"
+#elif defined(__nios2__)
+#  define native_architecture() ARCHITECTURE_NIOS2
+#  define LIB_ARCH_TUPLE "nios2-linux-gnu"
 #else
 #  error "Please register your architecture here!"
 #endif
diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c
deleted file mode 100644 (file)
index cf5a724..0000000
+++ /dev/null
@@ -1,674 +0,0 @@
-/***
-  This file is part of systemd. See COPYING for details.
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * RB-Tree Implementation
- * This implements the insertion/removal of elements in RB-Trees. You're highly
- * recommended to have an RB-Tree documentation at hand when reading this. Both
- * insertion and removal can be split into a handful of situations that can
- * occur. Those situations are enumerated as "Case 1" to "Case n" here, and
- * follow closely the cases described in most RB-Tree documentations. This file
- * does not explain why it is enough to handle just those cases, nor does it
- * provide a proof of correctness. Dig out your algorithm 101 handbook if
- * you're interested.
- *
- * This implementation is *not* straightforward. Usually, a handful of
- * rotation, reparent, swap and link helpers can be used to implement the
- * rebalance operations. However, those often perform unnecessary writes.
- * Therefore, this implementation hard-codes all the operations. You're highly
- * recommended to look at the two basic helpers before reading the code:
- *     c_rbtree_swap_child()
- *     c_rbtree_set_parent_and_color()
- * Those are the only helpers used, hence, you should really know what they do
- * before digging into the code.
- *
- * For a highlevel documentation of the API, see the header file and docbook
- * comments.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include "c-rbtree.h"
-
-enum {
-        C_RBNODE_RED   = 0,
-        C_RBNODE_BLACK = 1,
-};
-
-static inline unsigned long c_rbnode_color(CRBNode *n) {
-        return (unsigned long)n->__parent_and_color & 1UL;
-}
-
-static inline _Bool c_rbnode_is_red(CRBNode *n) {
-        return c_rbnode_color(n) == C_RBNODE_RED;
-}
-
-static inline _Bool c_rbnode_is_black(CRBNode *n) {
-        return c_rbnode_color(n) == C_RBNODE_BLACK;
-}
-
-/**
- * c_rbnode_leftmost() - return leftmost child
- * @n:          current node, or NULL
- *
- * This returns the leftmost child of @n. If @n is NULL, this will return NULL.
- * In all other cases, this function returns a valid pointer. That is, if @n
- * does not have any left children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to leftmost child, or NULL.
- */
-CRBNode *c_rbnode_leftmost(CRBNode *n) {
-        if (n)
-                while (n->left)
-                        n = n->left;
-        return n;
-}
-
-/**
- * c_rbnode_rightmost() - return rightmost child
- * @n:          current node, or NULL
- *
- * This returns the rightmost child of @n. If @n is NULL, this will return
- * NULL. In all other cases, this function returns a valid pointer. That is, if
- * @n does not have any right children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to rightmost child, or NULL.
- */
-CRBNode *c_rbnode_rightmost(CRBNode *n) {
-        if (n)
-                while (n->right)
-                        n = n->right;
-        return n;
-}
-
-/**
- * c_rbnode_next() - return next node
- * @n:          current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically next node to @n. If @n is NULL, the last node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to next node, or NULL.
- */
-CRBNode *c_rbnode_next(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-        if (n->right)
-                return c_rbnode_leftmost(n->right);
-
-        while ((p = c_rbnode_parent(n)) && n == p->right)
-                n = p;
-
-        return p;
-}
-
-/**
- * c_rbnode_prev() - return previous node
- * @n:          current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically previous node to @n. If @n is NULL, the first node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to previous node, or NULL.
- */
-CRBNode *c_rbnode_prev(CRBNode *n) {
-        CRBNode *p;
-
-        if (!c_rbnode_is_linked(n))
-                return NULL;
-        if (n->left)
-                return c_rbnode_rightmost(n->left);
-
-        while ((p = c_rbnode_parent(n)) && n == p->left)
-                n = p;
-
-        return p;
-}
-
-/**
- * c_rbtree_first() - return first node
- * @t:          tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically first node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to first node, or NULL.
- */
-CRBNode *c_rbtree_first(CRBTree *t) {
-        assert(t);
-        return c_rbnode_leftmost(t->root);
-}
-
-/**
- * c_rbtree_last() - return last node
- * @t:          tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically last node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to last node, or NULL.
- */
-CRBNode *c_rbtree_last(CRBTree *t) {
-        assert(t);
-        return c_rbnode_rightmost(t->root);
-}
-
-/*
- * Set the color and parent of a node. This should be treated as a simple
- * assignment of the 'color' and 'parent' fields of the node. No other magic is
- * applied. But since both fields share its backing memory, this helper
- * function is provided.
- */
-static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) {
-        assert(!((unsigned long)p & 1));
-        assert(c < 2);
-        n->__parent_and_color = (CRBNode*)((unsigned long)p | c);
-}
-
-/* same as c_rbnode_set_parent_and_color(), but keeps the current color */
-static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) {
-        c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n));
-}
-
-/*
- * This function partially replaces an existing child pointer to a new one. The
- * existing child must be given as @old, the new child as @new. @p must be the
- * parent of @old (or NULL if it has no parent).
- * This function ensures that the parent of @old now points to @new. However,
- * it does *NOT* change the parent pointer of @new. The caller must ensure
- * this.
- * If @p is NULL, this function ensures that the root-pointer is adjusted
- * instead (given as @t).
- */
-static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) {
-        if (p) {
-                if (p->left == old)
-                        p->left = new;
-                else
-                        p->right = new;
-        } else {
-                t->root = new;
-        }
-}
-
-static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) {
-        CRBNode *p, *g, *gg, *u, *x;
-
-        /*
-         * Paint a single node according to RB-Tree rules. The node must
-         * already be linked into the tree and painted red.
-         * We repaint the node or rotate the tree, if required. In case a
-         * recursive repaint is required, the next node to be re-painted
-         * is returned.
-         *      p: parent
-         *      g: grandparent
-         *      gg: grandgrandparent
-         *      u: uncle
-         *      x: temporary
-         */
-
-        /* node is red, so we can access the parent directly */
-        p = n->__parent_and_color;
-
-        if (!p) {
-                /* Case 1:
-                 * We reached the root. Mark it black and be done. As all
-                 * leaf-paths share the root, the ratio of black nodes on each
-                 * path stays the same. */
-                c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK);
-                n = NULL;
-        } else if (c_rbnode_is_black(p)) {
-                /* Case 2:
-                 * The parent is already black. As our node is red, we did not
-                 * change the number of black nodes on any path, nor do we have
-                 * multiple consecutive red nodes. */
-                n = NULL;
-        } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */
-                g = p->__parent_and_color;
-                gg = c_rbnode_parent(g);
-                u = g->right;
-
-                if (u && c_rbnode_is_red(u)) {
-                        /* Case 3:
-                         * Parent and uncle are both red. We know the
-                         * grandparent must be black then. Repaint parent and
-                         * uncle black, the grandparent red and recurse into
-                         * the grandparent. */
-                        c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
-                        n = g;
-                } else {
-                        /* parent is red, uncle is black */
-
-                        if (n == p->right) {
-                                /* Case 4:
-                                 * We're the right child. Rotate on parent to
-                                 * become left child, so we can handle it the
-                                 * same as case 5. */
-                                x = n->left;
-                                p->right = n->left;
-                                n->left = p;
-                                if (x)
-                                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
-                                c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
-                                p = n;
-                        }
-
-                        /* 'n' is invalid from here on! */
-                        n = NULL;
-
-                        /* Case 5:
-                         * We're the red left child or a red parent, black
-                         * grandparent and uncle. Rotate on grandparent and
-                         * switch color with parent. Number of black nodes on
-                         * each path stays the same, but we got rid of the
-                         * double red path. As the grandparent is still black,
-                         * we're done. */
-                        x = p->right;
-                        g->left = x;
-                        p->right = g;
-                        if (x)
-                                c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
-                        c_rbtree_swap_child(t, gg, g, p);
-                }
-        } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */
-                g = p->__parent_and_color;
-                gg = c_rbnode_parent(g);
-                u = g->left;
-
-                if (u && c_rbnode_is_red(u)) {
-                        c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
-                        n = g;
-                } else {
-                        if (n == p->left) {
-                                x = n->right;
-                                p->left = n->right;
-                                n->right = p;
-                                if (x)
-                                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
-                                c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
-                                p = n;
-                        }
-
-                        n = NULL;
-
-                        x = p->left;
-                        g->right = x;
-                        p->left = g;
-                        if (x)
-                                c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
-                        c_rbtree_swap_child(t, gg, g, p);
-                }
-        }
-
-        return n;
-}
-
-static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) {
-        assert(t);
-        assert(n);
-
-        while (n)
-                n = c_rbtree_paint_one(t, n);
-}
-
-/**
- * c_rbtree_add() - add node to tree
- * @t:          tree to operate one
- * @p:          parent node to link under, or NULL
- * @l:          left/right slot of @p (or root) to link at
- * @n:          node to add
- *
- * This links @n into the tree given as @t. The caller must provide the exact
- * spot where to link the node. That is, the caller must traverse the tree
- * based on their search order. Once they hit a leaf where to insert the node,
- * call this function to link it and rebalance the tree.
- *
- * A typical insertion would look like this (@t is your tree, @n is your node):
- *
- *        CRBNode **i, *p;
- *
- *        i = &t->root;
- *        p = NULL;
- *        while (*i) {
- *                p = *i;
- *                if (compare(n, *i) < 0)
- *                        i = &(*i)->left;
- *                else
- *                        i = &(*i)->right;
- *        }
- *
- *        c_rbtree_add(t, p, i, n);
- *
- * Once the node is linked into the tree, a simple lookup on the same tree can
- * be coded like this:
- *
- *        CRBNode *i;
- *
- *        i = t->root;
- *        while (i) {
- *                int v = compare(n, i);
- *                if (v < 0)
- *                        i = (*i)->left;
- *                else if (v > 0)
- *                        i = (*i)->right;
- *                else
- *                        break;
- *        }
- *
- * When you add nodes to a tree, the memory contents of the node do not matter.
- * That is, there is no need to initialize the node via c_rbnode_init().
- * However, if you relink nodes multiple times during their lifetime, it is
- * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init().
- * In those cases, you should validate that a node is unlinked before you call
- * c_rbtree_add().
- */
-void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) {
-        assert(t);
-        assert(l);
-        assert(n);
-        assert(!p || l == &p->left || l == &p->right);
-        assert(p || l == &t->root);
-
-        c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED);
-        n->left = n->right = NULL;
-        *l = n;
-
-        c_rbtree_paint(t, n);
-}
-
-static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) {
-        CRBNode *s, *x, *y, *g;
-
-        /*
-         * Rebalance tree after a node was removed. This happens only if you
-         * remove a black node and one path is now left with an unbalanced
-         * number or black nodes.
-         * This function assumes all paths through p and n have one black node
-         * less than all other paths. If recursive fixup is required, the
-         * current node is returned.
-         */
-
-        if (n == p->left) {
-                s = p->right;
-                if (c_rbnode_is_red(s)) {
-                        /* Case 3:
-                         * We have a red node as sibling. Rotate it onto our
-                         * side so we can later on turn it black. This way, we
-                         * gain the additional black node in our path. */
-                        g = c_rbnode_parent(p);
-                        x = s->left;
-                        p->right = x;
-                        s->left = p;
-                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
-                        c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
-                        c_rbtree_swap_child(t, g, p, s);
-                        s = x;
-                }
-
-                x = s->right;
-                if (!x || c_rbnode_is_black(x)) {
-                        y = s->left;
-                        if (!y || c_rbnode_is_black(y)) {
-                                /* Case 4:
-                                 * Our sibling is black and has only black
-                                 * children. Flip it red and turn parent black.
-                                 * This way we gained a black node in our path,
-                                 * or we fix it recursively one layer up, which
-                                 * will rotate the red sibling as parent. */
-                                c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
-                                if (c_rbnode_is_black(p))
-                                        return p;
-
-                                c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
-                                return NULL;
-                        }
-
-                        /* Case 5:
-                         * Left child of our sibling is red, right one is black.
-                         * Rotate on parent so the right child of our sibling is
-                         * now red, and we can fall through to case 6. */
-                        x = y->right;
-                        s->left = y->right;
-                        y->right = s;
-                        p->right = y;
-                        if (x)
-                                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
-                        x = s;
-                        s = y;
-                }
-
-                /* Case 6:
-                 * The right child of our sibling is red. Rotate left and flip
-                 * colors, which gains us an additional black node in our path,
-                 * that was previously on our sibling. */
-                g = c_rbnode_parent(p);
-                y = s->left;
-                p->right = y;
-                s->left = p;
-                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
-                if (y)
-                        c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
-                c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
-                c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
-                c_rbtree_swap_child(t, g, p, s);
-        } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */
-                s = p->left;
-                if (c_rbnode_is_red(s)) {
-                        g = c_rbnode_parent(p);
-                        x = s->right;
-                        p->left = x;
-                        s->right = p;
-                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK);
-                        c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
-                        c_rbtree_swap_child(t, g, p, s);
-                        s = x;
-                }
-
-                x = s->left;
-                if (!x || c_rbnode_is_black(x)) {
-                        y = s->right;
-                        if (!y || c_rbnode_is_black(y)) {
-                                c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
-                                if (c_rbnode_is_black(p))
-                                        return p;
-
-                                c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
-                                return NULL;
-                        }
-
-                        x = y->left;
-                        s->right = y->left;
-                        y->left = s;
-                        p->left = y;
-                        if (x)
-                                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
-                        x = s;
-                        s = y;
-                }
-
-                g = c_rbnode_parent(p);
-                y = s->right;
-                p->left = y;
-                s->right = p;
-                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
-                if (y)
-                        c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
-                c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
-                c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
-                c_rbtree_swap_child(t, g, p, s);
-        }
-
-        return NULL;
-}
-
-static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) {
-        CRBNode *n = NULL;
-
-        assert(t);
-        assert(p);
-
-        do {
-                n = c_rbtree_rebalance_one(t, p, n);
-                p = n ? c_rbnode_parent(n) : NULL;
-        } while (p);
-}
-
-/**
- * c_rbtree_remove() - remove node from tree
- * @t:          tree to operate one
- * @n:          node to remove
- *
- * This removes the given node from its tree. Once unlinked, the tree is
- * rebalanced.
- * The caller *must* ensure that the given tree is actually the tree it is
- * linked on. Otherwise, behavior is undefined.
- *
- * This does *NOT* reset @n to being unlinked (for performance reason, this
- * function *never* modifies @n at all). If you need this, use
- * c_rbtree_remove_init().
- */
-void c_rbtree_remove(CRBTree *t, CRBNode *n) {
-        CRBNode *p, *s, *gc, *x, *next = NULL;
-        unsigned long c;
-
-        assert(t);
-        assert(n);
-        assert(c_rbnode_is_linked(n));
-
-        /*
-         * There are three distinct cases during node removal of a tree:
-         *  * The node has no children, in which case it can simply be removed.
-         *  * The node has exactly one child, in which case the child displaces
-         *    its parent.
-         *  * The node has two children, in which case there is guaranteed to
-         *    be a successor to the node (successor being the node ordered
-         *    directly after it). This successor cannot have two children by
-         *    itself (two interior nodes can never be successive). Therefore,
-         *    we can simply swap the node with its successor (including color)
-         *    and have reduced this case to either of the first two.
-         *
-         * Whenever the node we removed was black, we have to rebalance the
-         * tree. Note that this affects the actual node we _remove_, not @n (in
-         * case we swap it).
-         *
-         *      p: parent
-         *      s: successor
-         *      gc: grand-...-child
-         *      x: temporary
-         *      next: next node to rebalance on
-         */
-
-        if (!n->left) {
-                /*
-                 * Case 1:
-                 * The node has no left child. If it neither has a right child,
-                 * it is a leaf-node and we can simply unlink it. If it also
-                 * was black, we have to rebalance, as always if we remove a
-                 * black node.
-                 * But if the node has a right child, the child *must* be red
-                 * (otherwise, the right path has more black nodes as the
-                 * non-existing left path), and the node to be removed must
-                 * hence be black. We simply replace the node with its child,
-                 * turning the red child black, and thus no rebalancing is
-                 * required.
-                 */
-                p = c_rbnode_parent(n);
-                c = c_rbnode_color(n);
-                c_rbtree_swap_child(t, p, n, n->right);
-                if (n->right)
-                        c_rbnode_set_parent_and_color(n->right, p, c);
-                else
-                        next = (c == C_RBNODE_BLACK) ? p : NULL;
-        } else if (!n->right) {
-                /*
-                 * Case 1.1:
-                 * The node has exactly one child, and it is on the left. Treat
-                 * it as mirrored case of Case 1 (i.e., replace the node by its
-                 * child).
-                 */
-                p = c_rbnode_parent(n);
-                c = c_rbnode_color(n);
-                c_rbtree_swap_child(t, p, n, n->left);
-                c_rbnode_set_parent_and_color(n->left, p, c);
-        } else {
-                /*
-                 * Case 2:
-                 * We are dealing with a full interior node with a child not on
-                 * both sides. Find its successor and swap it. Then remove the
-                 * node similar to Case 1. For performance reasons we don't
-                 * perform the full swap, but skip links that are about to be
-                 * removed, anyway.
-                 */
-                s = n->right;
-                if (!s->left) {
-                        /* right child is next, no need to touch grandchild */
-                        p = s;
-                        gc = s->right;
-                } else {
-                        /* find successor and swap partially */
-                        s = c_rbnode_leftmost(s);
-                        p = c_rbnode_parent(s);
-
-                        gc = s->right;
-                        p->left = s->right;
-                        s->right = n->right;
-                        c_rbnode_set_parent(n->right, s);
-                }
-
-                /* node is partially swapped, now remove as in Case 1 */
-                s->left = n->left;
-                c_rbnode_set_parent(n->left, s);
-
-                x = c_rbnode_parent(n);
-                c = c_rbnode_color(n);
-                c_rbtree_swap_child(t, x, n, s);
-                if (gc)
-                        c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK);
-                else
-                        next = c_rbnode_is_black(s) ? p : NULL;
-                c_rbnode_set_parent_and_color(s, x, c);
-        }
-
-        if (next)
-                c_rbtree_rebalance(t, next);
-}
diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h
deleted file mode 100644 (file)
index 20c5515..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-#pragma once
-
-/***
-  This file is part of systemd. See COPYING for details.
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Standalone Red-Black-Tree Implementation in Standard ISO-C11
- *
- * This header provides an RB-Tree API, that is fully implemented in ISO-C11
- * and has no external dependencies. Furthermore, tree traversal, memory
- * allocations, and key comparisons a fully in control of the API user. The
- * implementation only provides the RB-Tree specific rebalancing and coloring.
- *
- * A tree is represented by the "CRBTree" structure. It contains a *singly*
- * field, which is a pointer to the root node. If NULL, the tree is empty. If
- * non-NULL, there is at least a single element in the tree.
- *
- * Each node of the tree is represented by the "CRBNode" structure. It has
- * three fields. The @left and @right members can be accessed by the API user
- * directly to traverse the tree. The third member is an implementation detail
- * and encodes the parent pointer and color of the node.
- * API users are required to embed the CRBNode object into their own objects
- * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode
- * pointers into pointers to their own structure.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct CRBNode CRBNode;
-typedef struct CRBTree CRBTree;
-
-/**
- * struct CRBNode - Node of a Red-Black Tree
- * @__parent_and_color:         internal state
- * @left:                       left child, or NULL
- * @right:                      right child, or NULL
- *
- * Each node in an RB-Tree must embed an CRBNode object. This object contains
- * pointers to its left and right child, which can be freely accessed by the
- * API user at any time. They are NULL, if the node does not have a left/right
- * child.
- *
- * The @__parent_and_color field must never be accessed directly. It encodes
- * the pointer to the parent node, and the color of the node. Use the accessor
- * functions instead.
- *
- * There is no reason to initialize a CRBNode object before linking it.
- * However, if you need a boolean state that tells you whether the node is
- * linked or not, you should initialize the node via c_rbnode_init() or
- * C_RBNODE_INIT.
- */
-struct CRBNode {
-        CRBNode *__parent_and_color;
-        CRBNode *left;
-        CRBNode *right;
-};
-
-#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) }
-
-CRBNode *c_rbnode_leftmost(CRBNode *n);
-CRBNode *c_rbnode_rightmost(CRBNode *n);
-CRBNode *c_rbnode_next(CRBNode *n);
-CRBNode *c_rbnode_prev(CRBNode *n);
-
-/**
- * struct CRBTree - Red-Black Tree
- * @root:       pointer to the root node, or NULL
- *
- * Each Red-Black Tree is rooted in an CRBTree object. This object contains a
- * pointer to the root node of the tree. The API user is free to access the
- * @root member at any time, and use it to traverse the tree.
- *
- * To initialize an RB-Tree, set it to NULL / all zero.
- */
-struct CRBTree {
-        CRBNode *root;
-};
-
-CRBNode *c_rbtree_first(CRBTree *t);
-CRBNode *c_rbtree_last(CRBTree *t);
-
-void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n);
-void c_rbtree_remove(CRBTree *t, CRBNode *n);
-
-/**
- * c_rbnode_init() - mark a node as unlinked
- * @n:          node to operate on
- *
- * This marks the node @n as unlinked. The node will be set to a valid state
- * that can never happen if the node is linked in a tree. Furthermore, this
- * state is fully known to the implementation, and as such handled gracefully
- * in all cases.
- *
- * You are *NOT* required to call this on your node. c_rbtree_add() can handle
- * uninitialized nodes just fine. However, calling this allows to use
- * c_rbnode_is_linked() to check for the state of a node. Furthermore,
- * iterators and accessors can be called on initialized (yet unlinked) nodes.
- *
- * Use the C_RBNODE_INIT macro if you want to initialize static variables.
- */
-static inline void c_rbnode_init(CRBNode *n) {
-        *n = (CRBNode)C_RBNODE_INIT(*n);
-}
-
-/**
- * c_rbnode_is_linked() - check whether a node is linked
- * @n:          node to check, or NULL
- *
- * This checks whether the passed node is linked. If you pass NULL, or if the
- * node is not linked into a tree, this will return false. Otherwise, this
- * returns true.
- *
- * Note that you must have either linked the node or initialized it, before
- * calling this function. Never call this function on uninitialized nodes.
- * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node
- * as unlinked. You have to call c_rbnode_init() yourself after removal, or use
- * the c_rbtree_remove_init() helper.
- *
- * Return: true if the node is linked, false if not.
- */
-static inline _Bool c_rbnode_is_linked(CRBNode *n) {
-        return n && n->__parent_and_color != n;
-}
-
-/**
- * c_rbnode_parent() - return parent pointer
- * @n           node to access
- *
- * This returns a pointer to the parent of the given node @n. If @n does not
- * have a parent, NULL is returned. If @n is not linked, @n itself is returned.
- *
- * You should not call this on unlinked or uninitialized nodes! If you do, you
- * better know how its semantics.
- *
- * Return: Pointer to parent.
- */
-static inline CRBNode *c_rbnode_parent(CRBNode *n) {
-        return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL);
-}
-
-/**
- * c_rbtree_remove_init() - safely remove node from tree and reinitialize it
- * @t:          tree to operate on
- * @n:          node to remove, or NULL
- *
- * This is almost the same as c_rbtree_remove(), but extends it slightly, to be
- * more convenient to use in many cases:
- *  - if @n is unlinked or NULL, this is a no-op
- *  - @n is reinitialized after being removed
- */
-static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) {
-        if (c_rbnode_is_linked(n)) {
-                c_rbtree_remove(t, n);
-                c_rbnode_init(n);
-        }
-}
-
-/**
- * CRBCompareFunc - compare a node to a key
- * @t:          tree where the node is linked to
- * @k:          key to compare
- * @n:          node to compare
- *
- * If you use the tree-traversal helpers (which are optional), you need to
- * provide this callback so they can compare nodes in a tree to the key you
- * look for.
- *
- * The tree @t is provided as optional context to this callback. The key you
- * look for is provided as @k, the current node that should be compared to is
- * provided as @n. This function should work like strcmp(), that is, return -1
- * if @key orders before @n, 0 if both compare equal, and 1 if it orders after
- * @n.
- */
-typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n);
-
-/**
- * c_rbtree_find_node() - find node
- * @t:          tree to search through
- * @f:          comparison function
- * @k:          key to search for
- *
- * This searches through @t for a node that compares equal to @k. The function
- * @f must be provided by the caller, which is used to compare nodes to @k. See
- * the documentation of CRBCompareFunc for details.
- *
- * If there are multiple entries that compare equal to @k, this will return a
- * pseudo-randomly picked node. If you need stable lookup functions for trees
- * where duplicate entries are allowed, you better code your own lookup.
- *
- * Return: Pointer to matching node, or NULL.
- */
-static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) {
-        CRBNode *i;
-
-        assert(t);
-        assert(f);
-
-        i = t->root;
-        while (i) {
-                int v = f(t, (void *)k, i);
-                if (v < 0)
-                        i = i->left;
-                else if (v > 0)
-                        i = i->right;
-                else
-                        return i;
-        }
-
-        return NULL;
-}
-
-/**
- * c_rbtree_find_entry() - find entry
- * @_t:         tree to search through
- * @_f:         comparison function
- * @_k:         key to search for
- * @_t:         type of the structure that embeds the nodes
- * @_o:         name of the node-member in type @_t
- *
- * This is very similar to c_rbtree_find_node(), but instead of returning a
- * pointer to the CRBNode, it returns a pointer to the surrounding object. This
- * object must embed the CRBNode object. The type of the surrounding object
- * must be given as @_t, and the name of the embedded CRBNode member as @_o.
- *
- * See c_rbtree_find_node() for more details.
- *
- * Return: Pointer to found entry, NULL if not found.
- */
-#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \
-        ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \
-                (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o)))
-
-/**
- * c_rbtree_find_slot() - find slot to insert new node
- * @t:          tree to search through
- * @f:          comparison function
- * @k:          key to search for
- * @p:          output storage for parent pointer
- *
- * This searches through @t just like c_rbtree_find_node() does. However,
- * instead of returning a pointer to a node that compares equal to @k, this
- * searches for a slot to insert a node with key @k. A pointer to the slot is
- * returned, and a pointer to the parent of the slot is stored in @p. Both
- * can be passed directly to c_rbtree_add(), together with your node to insert.
- *
- * If there already is a node in the tree, that compares equal to @k, this will
- * return NULL and store the conflicting node in @p. In all other cases,
- * this will return a pointer (non-NULL) to the empty slot to insert the node
- * at. @p will point to the parent node of that slot.
- *
- * If you want trees that allow duplicate nodes, you better code your own
- * insertion function.
- *
- * Return: Pointer to slot to insert node, or NULL on conflicts.
- */
-static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) {
-        CRBNode **i;
-
-        assert(t);
-        assert(f);
-        assert(p);
-
-        i = &t->root;
-        *p = NULL;
-        while (*i) {
-                int v = f(t, (void *)k, *i);
-                *p = *i;
-                if (v < 0)
-                        i = &(*i)->left;
-                else if (v > 0)
-                        i = &(*i)->right;
-                else
-                        return NULL;
-        }
-
-        return i;
-}
-
-#ifdef __cplusplus
-}
-#endif
index 41dc8ca79a60314362fb9ebc0c6d19ead654f991..c3586728d09fd909050ffff0fcebc32d34ec2666 100644 (file)
@@ -71,7 +71,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
 int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
         bool try_cfr = true, try_sendfile = true, try_splice = true;
         int r;
-        size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */
+        size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
 
         assert(fdf >= 0);
         assert(fdt >= 0);
@@ -94,15 +94,15 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
                         if (max_bytes <= 0)
                                 return 1; /* return > 0 if we hit the max_bytes limit */
 
-                        if ((uint64_t) m > max_bytes)
-                                m = (size_t) max_bytes;
+                        if (m > max_bytes)
+                                m = max_bytes;
                 }
 
                 /* First try copy_file_range(), unless we already tried */
                 if (try_cfr) {
                         n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u);
                         if (n < 0) {
-                                if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV))
+                                if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF))
                                         return n;
 
                                 try_cfr = false;
@@ -305,6 +305,8 @@ static int fd_copy_directory(
                 fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
         else
                 fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
+        if (fdf < 0)
+                return -errno;
 
         d = fdopendir(fdf);
         if (!d)
@@ -325,22 +327,6 @@ static int fd_copy_directory(
 
         r = 0;
 
-        if (created) {
-                struct timespec ut[2] = {
-                        st->st_atim,
-                        st->st_mtim
-                };
-
-                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
-                        r = -errno;
-
-                if (fchmod(fdt, st->st_mode & 07777) < 0)
-                        r = -errno;
-
-                (void) futimens(fdt, ut);
-                (void) copy_xattr(dirfd(d), fdt);
-        }
-
         FOREACH_DIRENT_ALL(de, d, return -errno) {
                 struct stat buf;
                 int q;
@@ -364,7 +350,7 @@ static int fd_copy_directory(
                         q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                 else if (S_ISFIFO(buf.st_mode))
                         q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
-                else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
+                else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
                         q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
                 else
                         q = -EOPNOTSUPP;
@@ -376,6 +362,22 @@ static int fd_copy_directory(
                         r = q;
         }
 
+        if (created) {
+                struct timespec ut[2] = {
+                        st->st_atim,
+                        st->st_mtim
+                };
+
+                if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+                        r = -errno;
+
+                if (fchmod(fdt, st->st_mode & 07777) < 0)
+                        r = -errno;
+
+                (void) copy_xattr(dirfd(d), fdt);
+                (void) futimens(fdt, ut);
+        }
+
         return r;
 }
 
@@ -396,7 +398,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
                 return fd_copy_symlink(fdf, from, &st, fdt, to);
         else if (S_ISFIFO(st.st_mode))
                 return fd_copy_fifo(fdf, from, &st, fdt, to);
-        else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
+        else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
                 return fd_copy_node(fdf, from, &st, fdt, to);
         else
                 return -EOPNOTSUPP;
@@ -407,7 +409,6 @@ int copy_tree(const char *from, const char *to, bool merge) {
 }
 
 int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
         struct stat st;
 
         assert(dirfd >= 0);
@@ -422,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
         return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
 }
 
+int copy_directory(const char *from, const char *to, bool merge) {
+        struct stat st;
+
+        assert(from);
+        assert(to);
+
+        if (lstat(from, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode))
+                return -ENOTDIR;
+
+        return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
 int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         _cleanup_close_ int fdf = -1;
         int r;
index 3e5eb525064440cca67c4a718acf600c6b041e85..b5d08ebafe6a23117e7783c77a76fc38d5e420e1 100644 (file)
@@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
 int copy_tree(const char *from, const char *to, bool merge);
 int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
 int copy_directory_fd(int dirfd, const char *to, bool merge);
+int copy_directory(const char *from, const char *to, bool merge);
 int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
 int copy_times(int fdf, int fdt);
 int copy_xattr(int fdf, int fdt);
index 963343eb7df548b77dda82636be2fe6a4b5ce922..1a7a0f4928b908bd22163c37e8c32179cb9aa1a0 100644 (file)
@@ -41,8 +41,6 @@
 #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
 #define SIGNALS_IGNORE SIGPIPE
 
-#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
-
 #ifdef HAVE_SPLIT_USR
 #define KBD_KEYMAP_DIRS                         \
         "/usr/share/keymaps/\0"                 \
index 5fb535cb13a2a55f86170747a9d4752b4f400864..59067121b74f0c93c56a27673eeb1c7cfa109e12 100644 (file)
@@ -52,12 +52,10 @@ int dirent_ensure_type(DIR *d, struct dirent *de) {
 bool dirent_is_file(const struct dirent *de) {
         assert(de);
 
-        if (hidden_file(de->d_name))
+        if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
                 return false;
 
-        if (de->d_type != DT_REG &&
-            de->d_type != DT_LNK &&
-            de->d_type != DT_UNKNOWN)
+        if (hidden_or_backup_file(de->d_name))
                 return false;
 
         return true;
@@ -66,12 +64,10 @@ bool dirent_is_file(const struct dirent *de) {
 bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
         assert(de);
 
-        if (de->d_type != DT_REG &&
-            de->d_type != DT_LNK &&
-            de->d_type != DT_UNKNOWN)
+        if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
                 return false;
 
-        if (hidden_file_allow_backup(de->d_name))
+        if (de->d_name[0] == '.')
                 return false;
 
         return endswith(de->d_name, suffix);
index 6bf099b46c0a51ba6cb304aecfaf1e02d045d828..b91d04908f9a01545ed7f68e4f32fbc91323288d 100644 (file)
@@ -38,7 +38,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu
                                 on_error;                               \
                         }                                               \
                         break;                                          \
-                } else if (hidden_file((de)->d_name))                   \
+                } else if (hidden_or_backup_file((de)->d_name))         \
                         continue;                                       \
                 else
 
index ec9560cd07702d80603d427d890037e6d405e1b9..8b466cff154d94da5ad731624f0cc909e2a62372 100644 (file)
 #include <unistd.h>
 
 #include "fd-util.h"
+#include "fs-util.h"
 #include "macro.h"
 #include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "socket-util.h"
+#include "stdio-util.h"
 #include "util.h"
 
 int close_nointr(int fd) {
@@ -229,7 +231,7 @@ int close_all_fds(const int except[], unsigned n_except) {
         while ((de = readdir(d))) {
                 int fd = -1;
 
-                if (hidden_file(de->d_name))
+                if (hidden_or_backup_file(de->d_name))
                         continue;
 
                 if (safe_atoi(de->d_name, &fd) < 0)
@@ -356,3 +358,17 @@ bool fdname_is_valid(const char *s) {
 
         return p - s < 256;
 }
+
+int fd_get_path(int fd, char **ret) {
+        char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+        int r;
+
+        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+
+        r = readlink_malloc(procfs_path, ret);
+
+        if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */
+                return -EBADF;
+
+        return r;
+}
index 44528c6e35f97c965d8cc40e98314054eec052fa..b86e41698acb58afaa5c9e1079626feba4130fdf 100644 (file)
@@ -72,6 +72,8 @@ void cmsg_close_all(struct msghdr *mh);
 
 bool fdname_is_valid(const char *s);
 
+int fd_get_path(int fd, char **ret);
+
 /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
 #define ERRNO_IS_DISCONNECT(r) \
         IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
index 06f8ecbdbcf3c682c34bdb4f8b8296f10587c2d1..527f27bc67a730a5ef596ca20facb079cf46b8c1 100644 (file)
@@ -151,7 +151,7 @@ int fdset_new_fill(FDSet **_s) {
         while ((de = readdir(d))) {
                 int fd = -1;
 
-                if (hidden_file(de->d_name))
+                if (hidden_or_backup_file(de->d_name))
                         continue;
 
                 r = safe_atoi(de->d_name, &fd);
index 69590941e55e5b02f85bd29b6710f6a6ca4ee1b6..2a9b6e46ad84098306ea33e344385e8d2b820c6e 100644 (file)
@@ -1083,30 +1083,6 @@ int mkostemp_safe(char *pattern, int flags) {
         return fd;
 }
 
-int open_tmpfile(const char *path, int flags) {
-        char *p;
-        int fd;
-
-        assert(path);
-
-#ifdef O_TMPFILE
-        /* Try O_TMPFILE first, if it is supported */
-        fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
-        if (fd >= 0)
-                return fd;
-#endif
-
-        /* Fall back to unguessable name + unlinking */
-        p = strjoina(path, "/systemd-tmp-XXXXXX");
-
-        fd = mkostemp_safe(p, flags);
-        if (fd < 0)
-                return fd;
-
-        unlink(p);
-        return fd;
-}
-
 int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
         const char *fn;
         char *t;
@@ -1278,3 +1254,103 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
 
         return fputs(s, f);
 }
+
+int open_tmpfile_unlinkable(const char *directory, int flags) {
+        char *p;
+        int fd;
+
+        assert(directory);
+
+        /* 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);
+        if (fd < 0)
+                return fd;
+
+        (void) unlink(p);
+
+        return fd;
+}
+
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
+        _cleanup_free_ char *tmp = NULL;
+        int r, fd;
+
+        assert(target);
+        assert(ret_path);
+
+        /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
+        assert((flags & O_EXCL) == 0);
+
+        /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
+         * 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;
+
+                dn = dirname_malloc(target);
+                if (!dn)
+                        return -ENOMEM;
+
+                fd = open(dn, O_TMPFILE|flags, 0640);
+                if (fd >= 0) {
+                        *ret_path = NULL;
+                        return fd;
+                }
+
+                log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
+        }
+#endif
+
+        r = tempfn_random(target, NULL, &tmp);
+        if (r < 0)
+                return r;
+
+        fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
+        if (fd < 0)
+                return -errno;
+
+        *ret_path = tmp;
+        tmp = NULL;
+
+        return fd;
+}
+
+int link_tmpfile(int fd, const char *path, const char *target) {
+
+        assert(fd >= 0);
+        assert(target);
+
+        /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
+         * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
+         * on the directory, and renameat2() is used instead.
+         *
+         * Note that in both cases we will not replace existing files. This is because linkat() dos not support this
+         * operation currently (renameat2() does), and there is no nice way to emulate this. */
+
+        if (path) {
+                if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
+                        return -errno;
+        } else {
+                char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
+
+                xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
+
+                if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
+                        return -errno;
+        }
+
+        return 0;
+}
index 8084895ff32a1ee22205e7356a37edbe1265594a..58dbc80c24718f9756e8cc38f43d83b399419d1b 100644 (file)
@@ -72,7 +72,6 @@ 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 open_tmpfile(const char *path, int flags);
 
 int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
 int tempfn_random(const char *p, const char *extra, char **ret);
@@ -82,3 +81,8 @@ int write_timestamp_file_atomic(const char *fn, usec_t n);
 int read_timestamp_file(const char *fn, usec_t *ret);
 
 int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
+
+int open_tmpfile_unlinkable(const char *directory, int flags);
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
+
+int link_tmpfile(int fd, const char *path, const char *target);
index 51268828af4f07ea2ee4f0e6451d67d2c0877081..e24e7036f751a88056836b8352127cfd3a4a2847 100644 (file)
@@ -38,6 +38,7 @@
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
@@ -493,3 +494,17 @@ int get_files_in_directory(const char *path, char ***list) {
 
         return n;
 }
+
+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;
+
+        /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
+        xsprintf(path, "/proc/self/fd/%i", what);
+
+        r = inotify_add_watch(fd, path, mask);
+        if (r < 0)
+                return -errno;
+
+        return r;
+}
index 0d23f8635fe6b14a729f83dc32d7558bb7245748..517b599d6f09751b9128612572e904f56513ba42 100644 (file)
@@ -72,3 +72,5 @@ union inotify_event_buffer {
         struct inotify_event ev;
         uint8_t raw[INOTIFY_EVENT_MAX];
 };
+
+int inotify_add_watch_fd(int fd, int what, uint32_t mask);
index 85b8d812b3981fa7e3c55cfc224876a34b83ae34..49a04795923bc07c41adf3c8de77b95d51ca8302 100644 (file)
@@ -1773,20 +1773,18 @@ int set_consume(Set *s, void *value) {
 
 int set_put_strdup(Set *s, const char *p) {
         char *c;
-        int r;
 
         assert(s);
         assert(p);
 
+        if (set_contains(s, (char*) p))
+                return 0;
+
         c = strdup(p);
         if (!c)
                 return -ENOMEM;
 
-        r = set_consume(s, c);
-        if (r == -EEXIST)
-                return 0;
-
-        return r;
+        return set_consume(s, c);
 }
 
 int set_put_strdupv(Set *s, char **l) {
index 5a7ee87a20cb42f9669513a4cdb55fcbb20c52d9..13c3bb644621dc863ce3f04eddcd5c3565aee973 100644 (file)
@@ -178,16 +178,16 @@ bool is_localhost(const char *hostname) {
         assert(hostname);
 
         /* This tries to identify local host and domain names
-         * described in RFC6761 plus the redhatism of .localdomain */
+         * described in RFC6761 plus the redhatism of localdomain */
 
         return strcaseeq(hostname, "localhost") ||
                strcaseeq(hostname, "localhost.") ||
-               strcaseeq(hostname, "localdomain.") ||
-               strcaseeq(hostname, "localdomain") ||
+               strcaseeq(hostname, "localhost.localdomain") ||
+               strcaseeq(hostname, "localhost.localdomain.") ||
                endswith_no_case(hostname, ".localhost") ||
                endswith_no_case(hostname, ".localhost.") ||
-               endswith_no_case(hostname, ".localdomain") ||
-               endswith_no_case(hostname, ".localdomain.");
+               endswith_no_case(hostname, ".localhost.localdomain") ||
+               endswith_no_case(hostname, ".localhost.localdomain.");
 }
 
 bool is_gateway_hostname(const char *hostname) {
index cda6b2895d6497dc237aba91001c8e74f88458d4..eaad25e65bf92c143b332cb11d048480e8804e69 100644 (file)
@@ -153,6 +153,8 @@ static int add_locales_from_libdir (Set *locales) {
         FOREACH_DIRENT(entry, dir, return -errno) {
                 char *z;
 
+                dirent_ensure_type(dir, entry);
+
                 if (entry->d_type != DT_DIR)
                         continue;
 
index 66cd5921adf0de622ce8fb93236c5701f01890ad..22ea8f67cc2b3fadf12bf67453bc5da03a891711 100644 (file)
@@ -445,6 +445,10 @@ struct btrfs_ioctl_quota_ctl_args {
 #define TMPFS_MAGIC 0x01021994
 #endif
 
+#ifndef MQUEUE_MAGIC
+#define MQUEUE_MAGIC 0x19800202
+#endif
+
 #ifndef MS_MOVE
 #define MS_MOVE 8192
 #endif
@@ -553,7 +557,7 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IFLA_INET6_ADDR_GEN_MODE 8
 #define __IFLA_INET6_MAX 9
 
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
 
 #define IN6_ADDR_GEN_MODE_EUI64 0
 #define IN6_ADDR_GEN_MODE_NONE 1
@@ -738,7 +742,7 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
 #endif
 
-#if !HAVE_DECL_IFLA_BR_PRIORITY
+#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
 #define IFLA_BR_UNSPEC 0
 #define IFLA_BR_FORWARD_DELAY 1
 #define IFLA_BR_HELLO_TIME 2
@@ -746,7 +750,40 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IFLA_BR_AGEING_TIME 4
 #define IFLA_BR_STP_STATE 5
 #define IFLA_BR_PRIORITY 6
-#define __IFLA_BR_MAX 7
+#define IFLA_BR_VLAN_FILTERING 7
+#define IFLA_BR_VLAN_PROTOCOL 8
+#define IFLA_BR_GROUP_FWD_MASK 9
+#define IFLA_BR_ROOT_ID 10
+#define IFLA_BR_BRIDGE_ID 11
+#define IFLA_BR_ROOT_PORT 12
+#define IFLA_BR_ROOT_PATH_COST 13
+#define IFLA_BR_TOPOLOGY_CHANGE 14
+#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED 15
+#define IFLA_BR_HELLO_TIMER 16
+#define IFLA_BR_TCN_TIMER 17
+#define IFLA_BR_TOPOLOGY_CHANGE_TIMER 18
+#define IFLA_BR_GC_TIMER 19
+#define IFLA_BR_GROUP_ADDR 20
+#define IFLA_BR_FDB_FLUSH 21
+#define IFLA_BR_MCAST_ROUTER 22
+#define IFLA_BR_MCAST_SNOOPING 23
+#define IFLA_BR_MCAST_QUERY_USE_IFADDR 24
+#define IFLA_BR_MCAST_QUERIER 25
+#define IFLA_BR_MCAST_HASH_ELASTICITY 26
+#define IFLA_BR_MCAST_HASH_MAX 27
+#define IFLA_BR_MCAST_LAST_MEMBER_CNT 28
+#define IFLA_BR_MCAST_STARTUP_QUERY_CNT 29
+#define IFLA_BR_MCAST_LAST_MEMBER_INTVL 30
+#define IFLA_BR_MCAST_MEMBERSHIP_INTVL 31
+#define IFLA_BR_MCAST_QUERIER_INTVL 32
+#define IFLA_BR_MCAST_QUERY_INTVL 33
+#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34
+#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL 35
+#define IFLA_BR_NF_CALL_IPTABLES 36
+#define IFLA_BR_NF_CALL_IP6TABLES 37
+#define IFLA_BR_NF_CALL_ARPTABLES 38
+#define IFLA_BR_VLAN_DEFAULT_PVID 39
+#define __IFLA_BR_MAX 40
 
 #define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
 #endif
@@ -795,6 +832,10 @@ struct btrfs_ioctl_quota_ctl_args {
 #define IPV6_UNICAST_IF 76
 #endif
 
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
+
 #ifndef IFF_MULTI_QUEUE
 #define IFF_MULTI_QUEUE 0x100
 #endif
index 5faa2eba055b04da668eb7882bfefdaa8ac044b9..ba698959b7a70e385addeeb9f9667504cbe9ba20 100644 (file)
@@ -498,7 +498,9 @@ bool fstype_is_network(const char *fstype) {
                 "nfs4\0"
                 "gfs\0"
                 "gfs2\0"
-                "glusterfs\0";
+                "glusterfs\0"
+                "pvfs2\0" /* OrangeFS */
+                ;
 
         const char *x;
 
index df565a3593eda12b1e9fa56a248d1042ed9323c4..bf7c4854fc1d18f4f902429d0f5f5ca026f25364 100644 (file)
@@ -154,3 +154,46 @@ enum nss_status _nss_##module##_getgrgid_r(             \
                 struct group *gr,                       \
                 char *buffer, size_t buflen,            \
                 int *errnop) _public_
+
+typedef enum nss_status (*_nss_gethostbyname4_r_t)(
+                const char *name,
+                struct gaih_addrtuple **pat,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop,
+                int32_t *ttlp);
+
+typedef enum nss_status (*_nss_gethostbyname3_r_t)(
+                const char *name,
+                int af,
+                struct hostent *result,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop,
+                int32_t *ttlp,
+                char **canonp);
+
+typedef enum nss_status (*_nss_gethostbyname2_r_t)(
+                const char *name,
+                int af,
+                struct hostent *result,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop);
+
+typedef enum nss_status (*_nss_gethostbyname_r_t)(
+                const char *name,
+                struct hostent *result,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop);
+
+typedef enum nss_status (*_nss_gethostbyaddr2_r_t)(
+                const void* addr, socklen_t len,
+                int af,
+                struct hostent *result,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop,
+                int32_t *ttlp);
+typedef enum nss_status (*_nss_gethostbyaddr_r_t)(
+                const void* addr, socklen_t len,
+                int af,
+                struct hostent *host,
+                char *buffer, size_t buflen,
+                int *errnop, int *h_errnop);
index d8dc26a36e97625804cdf926d00ca5117dc0dc22..7dc579a159fed8353280d6ed32571841744a196f 100644 (file)
@@ -90,6 +90,18 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
 }
 #endif
 
+#if SIZE_MAX == UINT_MAX
+static inline int safe_atozu(const char *s, size_t *ret_u) {
+        assert_cc(sizeof(size_t) == sizeof(unsigned));
+        return safe_atou(s, (unsigned *) ret_u);
+}
+#else
+static inline int safe_atozu(const char *s, size_t *ret_u) {
+        assert_cc(sizeof(size_t) == sizeof(long unsigned));
+        return safe_atolu(s, ret_u);
+}
+#endif
+
 int safe_atod(const char *s, double *ret_d);
 
 int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
index 822c09bfba7ce33a7e49f199a942a057ea3e8289..b2fa81a294c46cf2e3898a2c47c195fef0902356 100644 (file)
@@ -569,10 +569,10 @@ static int binary_is_good(const char *binary) {
         if (r < 0)
                 return r;
 
-        return !path_equal(d, "true") &&
-               !path_equal(d, "/bin/true") &&
-               !path_equal(d, "/usr/bin/true") &&
-               !path_equal(d, "/dev/null");
+        return !PATH_IN_SET(d, "true"
+                               "/bin/true",
+                               "/usr/bin/true",
+                               "/dev/null");
 }
 
 int fsck_exists(const char *fstype) {
@@ -756,34 +756,53 @@ char *file_in_same_dir(const char *path, const char *filename) {
         return ret;
 }
 
-bool hidden_file_allow_backup(const char *filename) {
-        assert(filename);
-
-        return
-                filename[0] == '.' ||
-                streq(filename, "lost+found") ||
-                streq(filename, "aquota.user") ||
-                streq(filename, "aquota.group") ||
-                endswith(filename, ".rpmnew") ||
-                endswith(filename, ".rpmsave") ||
-                endswith(filename, ".rpmorig") ||
-                endswith(filename, ".dpkg-old") ||
-                endswith(filename, ".dpkg-new") ||
-                endswith(filename, ".dpkg-tmp") ||
-                endswith(filename, ".dpkg-dist") ||
-                endswith(filename, ".dpkg-bak") ||
-                endswith(filename, ".dpkg-backup") ||
-                endswith(filename, ".dpkg-remove") ||
-                endswith(filename, ".swp");
-}
+bool hidden_or_backup_file(const char *filename) {
+        const char *p;
 
-bool hidden_file(const char *filename) {
         assert(filename);
 
-        if (endswith(filename, "~"))
+        if (filename[0] == '.' ||
+            streq(filename, "lost+found") ||
+            streq(filename, "aquota.user") ||
+            streq(filename, "aquota.group") ||
+            endswith(filename, "~"))
                 return true;
 
-        return hidden_file_allow_backup(filename);
+        p = strrchr(filename, '.');
+        if (!p)
+                return false;
+
+        /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
+         * with always new suffixes and that everybody else should just adjust to that, then it really should be on
+         * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
+         * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
+         * string. Specifically: there's now:
+         *
+         *    The generic suffixes "~" and ".bak" for backup files
+         *    The generic prefix "." for hidden files
+         *
+         * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
+         * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
+         */
+
+        return STR_IN_SET(p + 1,
+                          "rpmnew",
+                          "rpmsave",
+                          "rpmorig",
+                          "dpkg-old",
+                          "dpkg-new",
+                          "dpkg-tmp",
+                          "dpkg-dist",
+                          "dpkg-bak",
+                          "dpkg-backup",
+                          "dpkg-remove",
+                          "ucf-new",
+                          "ucf-old",
+                          "ucf-dist",
+                          "swp",
+                          "bak",
+                          "old",
+                          "new");
 }
 
 bool is_device_path(const char *path) {
index 2c2f87a9f28b39275f9c3373f767fe889894f4e5..a27c13fcc3a94cd0ae525d63dee7d1c6ec31fa86 100644 (file)
@@ -48,6 +48,23 @@ bool path_equal(const char *a, const char *b) _pure_;
 bool path_equal_or_files_same(const char *a, const char *b);
 char* path_join(const char *root, const char *path, const char *rest);
 
+static inline bool path_equal_ptr(const char *a, const char *b) {
+        return !!a == !!b && (!a || path_equal(a, b));
+}
+
+/* Note: the search terminates on the first NULL item. */
+#define PATH_IN_SET(p, ...)                                     \
+        ({                                                      \
+                char **s;                                       \
+                bool _found = false;                            \
+                STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__))         \
+                        if (path_equal(p, *s)) {                \
+                               _found = true;                   \
+                               break;                           \
+                        }                                       \
+                _found;                                         \
+        })
+
 int path_strv_make_absolute_cwd(char **l);
 char** path_strv_resolve(char **l, const char *prefix);
 char** path_strv_resolve_uniq(char **l, const char *prefix);
@@ -105,7 +122,6 @@ bool path_is_safe(const char *p) _pure_;
 
 char *file_in_same_dir(const char *path, const char *filename);
 
-bool hidden_file_allow_backup(const char *filename);
-bool hidden_file(const char *filename) _pure_;
+bool hidden_or_backup_file(const char *filename) _pure_;
 
 bool is_device_path(const char *path);
index ae3f6109addbd2b2c71454f3e3b6092452118a93..4a7367cc929dde2f4ad6121b6189fa1ea66a8d3c 100644 (file)
@@ -528,14 +528,20 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
         return -EPROTO;
 }
 
-void sigkill_wait(pid_t *pid) {
+void sigkill_wait(pid_t pid) {
+        assert(pid > 1);
+
+        if (kill(pid, SIGKILL) > 0)
+                (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
         if (!pid)
                 return;
         if (*pid <= 1)
                 return;
 
-        if (kill(*pid, SIGKILL) > 0)
-                (void) wait_for_terminate(*pid, NULL);
+        sigkill_wait(*pid);
 }
 
 int kill_and_sigcont(pid_t pid, int sig) {
@@ -731,6 +737,18 @@ void valgrind_summary_hack(void) {
 #endif
 }
 
+int pid_compare_func(const void *a, const void *b) {
+        const pid_t *p = a, *q = b;
+
+        /* Suitable for usage in qsort() */
+
+        if (*p < *q)
+                return -1;
+        if (*p > *q)
+                return 1;
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index f5d193e76215e2c2dd5b6cc6f92d0ecb5e97c1e4..9f7508879645cb55c49b0184fb15c416c5dc3794 100644 (file)
@@ -58,8 +58,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid);
 int wait_for_terminate(pid_t pid, siginfo_t *status);
 int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
 
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
 
 int kill_and_sigcont(pid_t pid, int sig);
 
@@ -101,3 +101,5 @@ int sched_policy_from_string(const char *s);
 #define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
 
 void valgrind_summary_hack(void);
+
+int pid_compare_func(const void *a, const void *b);
index 7540b43215a567e22514764e47d58d7430c0cbed..ee063720edb15abc9c9694ea247f3b0c8515e1a8 100644 (file)
@@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) {
         return 0;
 }
 
+static int rlimit_parse_nice(const char *val, rlim_t *ret) {
+        uint64_t rl;
+        int r;
+
+        /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
+         * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
+         * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
+         * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
+         * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
+         *
+         * Yeah, Linux is quality engineering sometimes... */
+
+        if (val[0] == '+') {
+
+                /* Prefixed with "+": Parse as positive user-friendly nice value */
+                r = safe_atou64(val + 1, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl >= PRIO_MAX)
+                        return -ERANGE;
+
+                rl = 20 - rl;
+
+        } else if (val[0] == '-') {
+
+                /* Prefixed with "-": Parse as negative user-friendly nice value */
+                r = safe_atou64(val + 1, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl > (uint64_t) (-PRIO_MIN))
+                        return -ERANGE;
+
+                rl = 20 + rl;
+        } else {
+
+                /* Not prefixed: parse as raw resource limit value */
+                r = safe_atou64(val, &rl);
+                if (r < 0)
+                        return r;
+
+                if (rl > (uint64_t) (20 - PRIO_MIN))
+                        return -ERANGE;
+        }
+
+        *ret = (rlim_t) rl;
+        return 0;
+}
+
 static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
         [RLIMIT_CPU] = rlimit_parse_sec,
         [RLIMIT_FSIZE] = rlimit_parse_size,
@@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret
         [RLIMIT_LOCKS] = rlimit_parse_u64,
         [RLIMIT_SIGPENDING] = rlimit_parse_u64,
         [RLIMIT_MSGQUEUE] = rlimit_parse_size,
-        [RLIMIT_NICE] = rlimit_parse_u64,
+        [RLIMIT_NICE] = rlimit_parse_nice,
         [RLIMIT_RTPRIO] = rlimit_parse_u64,
         [RLIMIT_RTTIME] = rlimit_parse_usec,
 };
index 6d032689190266f9f6429d42f0deb9558c8fc631..40b5b527d57265e98f7994dbdbea8eae82ab5f78 100644 (file)
@@ -30,3 +30,12 @@ typedef enum RemoveFlags {
 
 int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
 int rm_rf(const char *path, RemoveFlags flags);
+
+/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
+static inline void rm_rf_and_free(char *p) {
+        if (!p)
+                return;
+        (void) rm_rf(p, REMOVE_ROOT);
+        free(p);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_and_free);
index e3047b209b65bb05af4c001e32e88bad78d070c5..280b5c3251ecc53f84baf906be816522e3f7a72c 100644 (file)
@@ -255,7 +255,7 @@ int signal_from_string(const char *s) {
         }
         if (safe_atou(s, &u) >= 0) {
                 signo = (int) u + offset;
-                if (signo > 0 && signo < _NSIG)
+                if (SIGNAL_VALID(signo))
                         return signo;
         }
         return -EINVAL;
index a7322ff26a9e4fa03bae9d655e6bba23f5bad6f7..dfd6eb564dff4b8f478fb94304daf54dff3b7c9e 100644 (file)
@@ -50,3 +50,7 @@ static inline void block_signals_reset(sigset_t *ss) {
                 assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
                 t;                                                                \
         })
+
+static inline bool SIGNAL_VALID(int signo) {
+        return signo > 0 && signo < _NSIG;
+}
index b180488fe86d950a78c6aef29892bb921a88b0ad..d88625fca73664537766be2734798233a48678f5 100644 (file)
@@ -56,26 +56,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                 return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
         }
 
-#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope)                    \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)        \
-        struct __useless_struct_to_allow_trailing_semicolon__
-
-#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope)   \
-        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
-        struct __useless_struct_to_allow_trailing_semicolon__
-
-#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
-
-#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
-
-/* For string conversions where numbers are also acceptable */
-#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max)         \
-        int name##_to_string_alloc(type i, char **str) {                \
+#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \
+        scope int name##_to_string_alloc(type i, char **str) {          \
                 char *s;                                                \
                 if (i < 0 || i > max)                                   \
                         return -ERANGE;                                 \
@@ -89,7 +71,9 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                 }                                                       \
                 *str = s;                                               \
                 return 0;                                               \
-        }                                                               \
+        }
+
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
         type name##_from_string(const char *s) {                        \
                 type i;                                                 \
                 unsigned u = 0;                                         \
@@ -102,4 +86,32 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
                         return (type) u;                                \
                 return (type) -1;                                       \
         }                                                               \
+
+
+#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope)                    \
+        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
+        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)        \
+        struct __useless_struct_to_allow_trailing_semicolon__
+
+#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope)   \
+        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
+        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
+        struct __useless_struct_to_allow_trailing_semicolon__
+
+#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
+
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
+
+/* For string conversions where numbers are also acceptable */
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max)         \
+        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,)  \
+        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \
         struct __useless_struct_to_allow_trailing_semicolon__
+
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \
+        _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \
+        _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static)
index 8282298dcaf93db2d750c8a04c0a373d593bb9e5..97a96e57625602b5d2c06938bfbcaff6866e6e5f 100644 (file)
@@ -558,6 +558,42 @@ int strv_extend(char ***l, const char *value) {
         return strv_consume(l, v);
 }
 
+int strv_extend_front(char ***l, const char *value) {
+        size_t n, m;
+        char *v, **c;
+
+        assert(l);
+
+        /* Like strv_extend(), but prepends rather than appends the new entry */
+
+        if (!value)
+                return 0;
+
+        n = strv_length(*l);
+
+        /* Increase and overflow check. */
+        m = n + 2;
+        if (m < n)
+                return -ENOMEM;
+
+        v = strdup(value);
+        if (!v)
+                return -ENOMEM;
+
+        c = realloc_multiply(*l, sizeof(char*), m);
+        if (!c) {
+                free(v);
+                return -ENOMEM;
+        }
+
+        memmove(c+1, c, n * sizeof(char*));
+        c[0] = v;
+        c[n+1] = NULL;
+
+        *l = c;
+        return 0;
+}
+
 char **strv_uniq(char **l) {
         char **i;
 
index 7bfa54408d25c5fa320e56e143536438985d92d3..f61bbb53869c5ece6ca19d387ef0bd7c103c55e5 100644 (file)
@@ -50,6 +50,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
 int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
 int strv_extend(char ***l, const char *value);
 int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
+int strv_extend_front(char ***l, const char *value);
 int strv_push(char ***l, char *value);
 int strv_push_pair(char ***l, char *a, char *b);
 int strv_push_prepend(char ***l, char *value);
index 0a9d2bbdef7b86f26d2bb722631d833b94ab914d..9521b79daa1530580980e4a5b6bdb6f06a13391f 100644 (file)
@@ -1135,14 +1135,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
 }
 
 bool colors_enabled(void) {
-        const char *colors;
+        static int enabled = -1;
 
-        colors = getenv("SYSTEMD_COLORS");
-        if (!colors) {
-                if (streq_ptr(getenv("TERM"), "dumb"))
-                        return false;
-                return on_tty();
+        if (_unlikely_(enabled < 0)) {
+                const char *colors;
+
+                colors = getenv("SYSTEMD_COLORS");
+                if (colors)
+                        enabled = parse_boolean(colors) != 0;
+                else if (streq_ptr(getenv("TERM"), "dumb"))
+                        enabled = false;
+                else
+                        enabled = on_tty();
         }
 
-        return parse_boolean(colors) != 0;
+        return enabled;
 }
index c16460a198e5ceb13c6676212cb6dda98575c076..edd9179cb8259042a6ac8d4762aeb4559467b193 100644 (file)
@@ -47,15 +47,12 @@ 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
          * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
          * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
-         * those archs.
-         *
-         * Also, older kernels don't support CLOCK_BOOTTIME: fall back to CLOCK_MONOTONIC. */
+         * those archs. */
 
         switch (c) {
 
-        case CLOCK_BOOTTIME:
         case CLOCK_BOOTTIME_ALARM:
-                return clock_boottime_or_monotonic ();
+                return CLOCK_BOOTTIME;
 
         case CLOCK_REALTIME_ALARM:
                 return CLOCK_REALTIME;
@@ -1083,22 +1080,31 @@ bool timezone_is_valid(const char *name) {
         return true;
 }
 
-clockid_t clock_boottime_or_monotonic(void) {
-        static clockid_t clock = -1;
-        int fd;
-
-        if (clock != -1)
-                return clock;
-
-        fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
-        if (fd < 0)
-                clock = CLOCK_MONOTONIC;
-        else {
-                safe_close(fd);
-                clock = CLOCK_BOOTTIME;
+bool clock_boottime_supported(void) {
+        static int supported = -1;
+
+        /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
+
+        if (supported < 0) {
+                int fd;
+
+                fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+                if (fd < 0)
+                        supported = false;
+                else {
+                        safe_close(fd);
+                        supported = true;
+                }
         }
 
-        return clock;
+        return supported;
+}
+
+clockid_t clock_boottime_or_monotonic(void) {
+        if (clock_boottime_supported())
+                return CLOCK_BOOTTIME;
+        else
+                return CLOCK_MONOTONIC;
 }
 
 int get_timezone(char **tz) {
index 77e3cd08d4307f6a840ba4884793afc95906a7e9..a5e3f567ec534fad1de41cd55e642ccacd423722 100644 (file)
@@ -112,6 +112,7 @@ bool ntp_synced(void);
 int get_timezones(char ***l);
 bool timezone_is_valid(const char *name);
 
+bool clock_boottime_supported(void);
 clockid_t clock_boottime_or_monotonic(void);
 
 #define xstrftime(buf, fmt, tm) \
index 19155bce5364df556c4b08aabb03041eb9556220..f65ca3edaa281e581cf67d8543d05ac15fabf560 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "missing.h"
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "formats-util.h"
index c23f1d485d5fd42c2ad4f237ab0b3921ac76e97e..8026eca3f4783c41cdfe5c8fbfc03069439ce8c9 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <stdbool.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 bool uid_is_valid(uid_t uid);
 
@@ -63,3 +64,7 @@ int take_etc_passwd_lock(const char *root);
 
 #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
 #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+static inline bool userns_supported(void) {
+        return access("/proc/self/uid_map", F_OK) >= 0;
+}
index ea1bed7ceb9f8ebcf82c38600ac5fe8e99512fc3..756c663be409cf7acace63b20fec3d38ef645688 100644 (file)
@@ -55,6 +55,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
+#include "umask-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -419,13 +420,17 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
                         _exit(EXIT_FAILURE);
                 }
 
-                if (!stdout_is_tty)
-                        dup2(fd, STDOUT_FILENO);
+                if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
+                        log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+                        _exit(EXIT_FAILURE);
+                }
 
-                if (!stderr_is_tty)
-                        dup2(fd, STDERR_FILENO);
+                if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
+                        log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+                        _exit(EXIT_FAILURE);
+                }
 
-                if (fd > 2)
+                if (fd > STDERR_FILENO)
                         close(fd);
         }
 
@@ -517,7 +522,7 @@ int on_ac_power(void) {
                 if (!de)
                         break;
 
-                if (hidden_file(de->d_name))
+                if (hidden_or_backup_file(de->d_name))
                         continue;
 
                 device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -773,15 +778,25 @@ uint64_t physical_memory(void) {
         return (uint64_t) mem * (uint64_t) page_size();
 }
 
-int update_reboot_param_file(const char *param) {
-        int r = 0;
+int update_reboot_parameter_and_warn(const char *param) {
+        int r;
+
+        if (isempty(param)) {
+                if (unlink("/run/systemd/reboot-param") < 0) {
+                        if (errno == ENOENT)
+                                return 0;
+
+                        return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
+                }
 
-        if (param) {
-                r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
+                return 0;
+        }
+
+        RUN_WITH_UMASK(0022) {
+                r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
-        } else
-                (void) unlink(REBOOT_PARAM_FILE);
+                        return log_warning_errno(r, "Failed to write reboot parameter file: %m");
+        }
 
         return 0;
 }
index 286db051599679ec9d2b0b191e47dc744d1c45da..1c032c15c91260668cbcd563bc8b943b1586dc36 100644 (file)
@@ -184,6 +184,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
 
 uint64_t physical_memory(void);
 
-int update_reboot_param_file(const char *param);
+int update_reboot_parameter_and_warn(const char *param);
 
 int version(void);
index d6fb10cac550e39174bfce0bd731fa7648dedc0b..dcb5912b83fe06526767be251a6ab14ac4e638c0 100644 (file)
@@ -191,7 +191,8 @@ int main(int argc, char *argv[]) {
 
         output_flags =
                 arg_all * OUTPUT_SHOW_ALL |
-                (arg_full > 0) * OUTPUT_FULL_WIDTH;
+                (arg_full > 0) * OUTPUT_FULL_WIDTH |
+                arg_kernel_threads * OUTPUT_KERNEL_THREADS;
 
         if (optind < argc) {
                 _cleanup_free_ char *root = NULL;
@@ -209,7 +210,7 @@ int main(int argc, char *argv[]) {
                                 printf("Directory %s:\n", argv[i]);
                                 fflush(stdout);
 
-                                q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags);
+                                q = show_cgroup_by_path(argv[i], NULL, 0, output_flags);
                         } else {
                                 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
                                 const char *controller, *path;
@@ -235,7 +236,7 @@ int main(int argc, char *argv[]) {
 
                                 show_cg_info(controller, path);
 
-                                q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
+                                q = show_cgroup(controller, path, NULL, 0, output_flags);
                         }
 
                         if (q < 0)
@@ -258,7 +259,7 @@ int main(int argc, char *argv[]) {
                                 printf("Working directory %s:\n", cwd);
                                 fflush(stdout);
 
-                                r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags);
+                                r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
                                 done = true;
                         }
                 }
@@ -273,7 +274,7 @@ int main(int argc, char *argv[]) {
                         show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
 
                         printf("-.slice\n");
-                        r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
+                        r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
                 }
         }
 
index 9c0e82ebb3e675c20f6bcdd64978e4b9ab664aab..14eb46c8dbd459e83cfb97af806545e1f88184af 100644 (file)
@@ -362,7 +362,7 @@ static int refresh_one(
                 Group **ret) {
 
         _cleanup_closedir_ DIR *d = NULL;
-        Group *ours;
+        Group *ours = NULL;
         int r;
 
         assert(controller);
index 5dc6fd98e7e3ad396ce9158fef4d519090b28255..1239a0efc692bac530bf9f82f45d038a63a2ba10 100644 (file)
@@ -149,7 +149,7 @@ static int automount_add_default_dependencies(Automount *a) {
         if (!UNIT(a)->default_dependencies)
                 return 0;
 
-        if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
                 return 0;
 
         r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
@@ -1050,9 +1050,6 @@ const UnitVTable automount_vtable = {
                 "Automount\0"
                 "Install\0",
 
-        .no_alias = true,
-        .no_instances = true,
-
         .init = automount_init,
         .load = automount_load,
         .done = automount_done,
index de2a21ccdec56bf0b36159bcade684059c635f6c..e7b7b5c0125c75fecca501d0e40fca1bfd9ddee4 100644 (file)
@@ -149,7 +149,7 @@ static int busname_add_default_default_dependencies(BusName *n) {
         if (r < 0)
                 return r;
 
-        if (UNIT(n)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(n)->manager)) {
                 r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
                 if (r < 0)
                         return r;
@@ -318,7 +318,7 @@ static int busname_open_fd(BusName *n) {
         if (n->starter_fd >= 0)
                 return 0;
 
-        mode = UNIT(n)->manager->running_as == MANAGER_SYSTEM ? "system" : "user";
+        mode = MANAGER_IS_SYSTEM(UNIT(n)->manager) ? "system" : "user";
         n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
         if (n->starter_fd < 0)
                 return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
@@ -999,6 +999,14 @@ static bool busname_supported(void) {
         return supported;
 }
 
+static int busname_control_pid(Unit *u) {
+        BusName *n = BUSNAME(u);
+
+        assert(n);
+
+        return n->control_pid;
+}
+
 static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
         [BUSNAME_SUCCESS] = "success",
         [BUSNAME_FAILURE_RESOURCES] = "resources",
@@ -1020,9 +1028,6 @@ const UnitVTable busname_vtable = {
                 "Install\0",
         .private_section = "BusName",
 
-        .no_alias = true,
-        .no_instances = true,
-
         .init = busname_init,
         .done = busname_done,
         .load = busname_load,
@@ -1052,6 +1057,8 @@ const UnitVTable busname_vtable = {
 
         .supported = busname_supported,
 
+        .control_pid = busname_control_pid,
+
         .bus_vtable = bus_busname_vtable,
 
         .status_message_formats = {
index 9c34928052bcc0f4f61c3b9c3ad23797c1f6f5a4..25cc6962f9be52451cc1ca59309ea46e1978e114 100644 (file)
@@ -1265,7 +1265,7 @@ int manager_setup_cgroup(Manager *m) {
          * it. This is to support live upgrades from older systemd
          * versions where PID 1 was moved there. Also see
          * cg_get_root_path(). */
-        if (!e && m->running_as == MANAGER_SYSTEM) {
+        if (!e && MANAGER_IS_SYSTEM(m)) {
                 e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
                 if (!e)
                         e = endswith(m->cgroup_root, "/system"); /* even more legacy */
@@ -1318,7 +1318,7 @@ int manager_setup_cgroup(Manager *m) {
 
                         (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
 
-                } else if (m->running_as == MANAGER_SYSTEM) {
+                } else if (MANAGER_IS_SYSTEM(m)) {
 
                         /* On the legacy hierarchy we only get
                          * notifications via cgroup agents. (Which
index 973a60187d4f7cda41ca5f2cc716c32a79aa8353..9dfca14914cecfda8317bdd6dc69cce058ca0d48 100644 (file)
@@ -837,9 +837,9 @@ int bus_exec_context_set_transient_property(
 
                 if (mode != UNIT_CHECK) {
 
-                        if (isempty(uu)) {
+                        if (isempty(uu))
                                 c->user = mfree(c->user);
-                        else {
+                        else {
                                 char *t;
 
                                 t = strdup(uu);
@@ -864,9 +864,9 @@ int bus_exec_context_set_transient_property(
 
                 if (mode != UNIT_CHECK) {
 
-                        if (isempty(gg)) {
+                        if (isempty(gg))
                                 c->group = mfree(c->group);
-                        else {
+                        else {
                                 char *t;
 
                                 t = strdup(gg);
index fc50fafaad272e48c787a76b1ff7166d4055aeaf..0f54c6b84b4c383d6e017bf60654bad354f73c97 100644 (file)
@@ -58,7 +58,7 @@ int bus_kill_context_set_transient_property(
 
                 k = kill_mode_from_string(m);
                 if (k < 0)
-                        return -EINVAL;
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Kill mode '%s' not known.", m);
 
                 if (mode != UNIT_CHECK) {
                         c->kill_mode = k;
@@ -75,7 +75,7 @@ int bus_kill_context_set_transient_property(
                 if (r < 0)
                         return r;
 
-                if (sig <= 0 || sig >= _NSIG)
+                if (!SIGNAL_VALID(sig))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig);
 
                 if (mode != UNIT_CHECK) {
index 00372b92b4bb9cee0e66da95f429bc2ee8e50827..d45f5114892bf15b1784b6e58ceb6419f6161139 100644 (file)
@@ -642,6 +642,30 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
         return bus_unit_method_set_properties(message, u, error);
 }
 
+static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        r = manager_load_unit(m, name, NULL, error, &u);
+        if (r < 0)
+                return r;
+
+        r = bus_unit_check_load_state(u, error);
+        if (r < 0)
+                return r;
+
+        return bus_unit_method_get_processes(message, u, error);
+}
+
 static int transient_unit_from_message(
                 Manager *m,
                 sd_bus_message *message,
@@ -865,7 +889,7 @@ static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_e
         return sd_bus_reply_method_return(message, NULL);
 }
 
-static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
+static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         Manager *m = userdata;
         const char *k;
@@ -905,6 +929,10 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
                     !strv_contains(states, unit_sub_state_to_string(u)))
                         continue;
 
+                if (!strv_isempty(patterns) &&
+                    !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
+                        continue;
+
                 unit_path = unit_dbus_path(u);
                 if (!unit_path)
                         return -ENOMEM;
@@ -939,7 +967,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
 }
 
 static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return list_units_filtered(message, userdata, error, NULL);
+        return list_units_filtered(message, userdata, error, NULL, NULL);
 }
 
 static int method_list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -950,7 +978,23 @@ static int method_list_units_filtered(sd_bus_message *message, void *userdata, s
         if (r < 0)
                 return r;
 
-        return list_units_filtered(message, userdata, error, states);
+        return list_units_filtered(message, userdata, error, states, NULL);
+}
+
+static int method_list_units_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **states = NULL;
+        _cleanup_strv_free_ char **patterns = NULL;
+        int r;
+
+        r = sd_bus_message_read_strv(message, &states);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_strv(message, &patterns);
+        if (r < 0)
+                return r;
+
+        return list_units_filtered(message, userdata, error, states, patterns);
 }
 
 static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1187,7 +1231,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
         if (r < 0)
                 return r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
 
         m->exit_code = MANAGER_REBOOT;
@@ -1206,7 +1250,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
         if (r < 0)
                 return r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
 
         m->exit_code = MANAGER_POWEROFF;
@@ -1225,7 +1269,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
         if (r < 0)
                 return r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
 
         m->exit_code = MANAGER_HALT;
@@ -1244,7 +1288,7 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
         if (r < 0)
                 return r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
 
         m->exit_code = MANAGER_KEXEC;
@@ -1265,7 +1309,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
         if (r < 0)
                 return r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
 
         r = sd_bus_message_read(message, "ss", &root, &init);
@@ -1433,7 +1477,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
         if (r < 0)
                 return r;
 
-        if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
+        if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
 
         m->return_value = code;
@@ -1441,7 +1485,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
         return sd_bus_reply_method_return(message, NULL);
 }
 
-static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         Manager *m = userdata;
         UnitFileList *item;
@@ -1466,7 +1510,7 @@ static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bu
         if (!h)
                 return -ENOMEM;
 
-        r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
+        r = unit_file_get_list(m->unit_file_scope, NULL, h, states, patterns);
         if (r < 0)
                 goto fail;
 
@@ -1494,11 +1538,30 @@ fail:
         return r;
 }
 
+static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return list_unit_files_by_patterns(message, userdata, error, NULL, NULL);
+}
+
+static int method_list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **states = NULL;
+        _cleanup_strv_free_ char **patterns = NULL;
+        int r;
+
+        r = sd_bus_message_read_strv(message, &states);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_strv(message, &patterns);
+        if (r < 0)
+                return r;
+
+        return list_unit_files_by_patterns(message, userdata, error, states, patterns);
+}
+
 static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         const char *name;
         UnitFileState state;
-        UnitFileScope scope;
         int r;
 
         assert(message);
@@ -1514,9 +1577,7 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
         if (r < 0)
                 return r;
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_get_state(scope, NULL, name, &state);
+        r = unit_file_get_state(m->unit_file_scope, NULL, name, &state);
         if (r < 0)
                 return r;
 
@@ -1526,7 +1587,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
 static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *default_target = NULL;
         Manager *m = userdata;
-        UnitFileScope scope;
         int r;
 
         assert(message);
@@ -1538,9 +1598,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd
         if (r < 0)
                 return r;
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_get_default(scope, NULL, &default_target);
+        r = unit_file_get_default(m->unit_file_scope, NULL, &default_target);
         if (r < 0)
                 return r;
 
@@ -1571,7 +1629,7 @@ static int reply_unit_file_changes_and_free(
         unsigned i;
         int r;
 
-        if (n_changes > 0) {
+        if (unit_file_changes_have_modification(changes, n_changes)) {
                 r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
                 if (r < 0)
                         log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
@@ -1591,15 +1649,19 @@ static int reply_unit_file_changes_and_free(
         if (r < 0)
                 goto fail;
 
-        for (i = 0; i < n_changes; i++) {
-                r = sd_bus_message_append(
-                                reply, "(sss)",
-                                unit_file_change_type_to_string(changes[i].type),
-                                changes[i].path,
-                                changes[i].source);
-                if (r < 0)
-                        goto fail;
-        }
+        for (i = 0; i < n_changes; i++)
+                if (changes[i].type >= 0) {
+                        const char *change = unit_file_change_type_to_string(changes[i].type);
+                        assert(change != NULL);
+
+                        r = sd_bus_message_append(
+                                        reply, "(sss)",
+                                        change,
+                                        changes[i].path,
+                                        changes[i].source);
+                        if (r < 0)
+                                goto fail;
+                }
 
         r = sd_bus_message_close_container(reply);
         if (r < 0)
@@ -1613,10 +1675,61 @@ fail:
         return r;
 }
 
+/* Create an error reply, using the error information from changes[]
+ * if possible, and fall back to generating an error from error code c.
+ * The error message only describes the first error.
+ *
+ * Coordinate with unit_file_dump_changes() in install.c.
+ */
+static int install_error(
+                sd_bus_error *error,
+                int c,
+                UnitFileChange *changes,
+                unsigned n_changes) {
+        int r;
+        unsigned i;
+        assert(c < 0);
+
+        for (i = 0; i < n_changes; i++)
+                switch(changes[i].type) {
+                case 0 ... INT_MAX:
+                        continue;
+                case -EEXIST:
+                        if (changes[i].source)
+                                r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+                                                      "File %s already exists and is a symlink to %s.",
+                                                      changes[i].path, changes[i].source);
+                        else
+                                r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+                                                      "File %s already exists.",
+                                                      changes[i].path);
+                        goto found;
+                case -ERFKILL:
+                        r = sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED,
+                                              "Unit file %s is masked.", changes[i].path);
+                        goto found;
+                case -EADDRNOTAVAIL:
+                        r = sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED,
+                                              "Unit %s is transient or generated.", changes[i].path);
+                        goto found;
+                case -ELOOP:
+                        r = sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED,
+                                              "Refusing to operate on linked unit file %s", changes[i].path);
+                        goto found;
+                default:
+                        r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path);
+                        goto found;
+                }
+
+        r = c;
+ found:
+        unit_file_changes_free(changes, n_changes);
+        return r;
+}
+
 static int method_enable_unit_files_generic(
                 sd_bus_message *message,
                 Manager *m,
-                const char *verb,
                 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
                 bool carries_install_info,
                 sd_bus_error *error) {
@@ -1624,7 +1737,6 @@ static int method_enable_unit_files_generic(
         _cleanup_strv_free_ char **l = NULL;
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
-        UnitFileScope scope;
         int runtime, force, r;
 
         assert(message);
@@ -1644,27 +1756,23 @@ static int method_enable_unit_files_generic(
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
-        if (r == -ESHUTDOWN)
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
+        r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes);
         if (r < 0)
-                return r;
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
 }
 
 static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_enable_unit_files_generic(message, userdata, "enable", unit_file_enable, true, error);
+        return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, error);
 }
 
 static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_enable_unit_files_generic(message, userdata, "enable", unit_file_reenable, true, error);
+        return method_enable_unit_files_generic(message, userdata, unit_file_reenable, true, error);
 }
 
 static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_enable_unit_files_generic(message, userdata, "enable", unit_file_link, false, error);
+        return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error);
 }
 
 static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
@@ -1672,11 +1780,11 @@ static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, cons
 }
 
 static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_enable_unit_files_generic(message, userdata, "enable", unit_file_preset_without_mode, true, error);
+        return method_enable_unit_files_generic(message, userdata, unit_file_preset_without_mode, true, error);
 }
 
 static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_enable_unit_files_generic(message, userdata, "disable", unit_file_mask, false, error);
+        return method_enable_unit_files_generic(message, userdata, unit_file_mask, false, error);
 }
 
 static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1686,7 +1794,6 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
         unsigned n_changes = 0;
         Manager *m = userdata;
         UnitFilePresetMode mm;
-        UnitFileScope scope;
         int runtime, force, r;
         const char *mode;
 
@@ -1715,26 +1822,22 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
+        r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes);
         if (r < 0)
-                return r;
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
 }
 
 static int method_disable_unit_files_generic(
                 sd_bus_message *message,
-                Manager *m, const
-                char *verb,
+                Manager *m,
                 int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
                 sd_bus_error *error) {
 
         _cleanup_strv_free_ char **l = NULL;
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
-        UnitFileScope scope;
         int r, runtime;
 
         assert(message);
@@ -1748,34 +1851,58 @@ static int method_disable_unit_files_generic(
         if (r < 0)
                 return r;
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
         r = bus_verify_manage_unit_files_async(m, message, error);
         if (r < 0)
                 return r;
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        r = call(scope, runtime, NULL, l, &changes, &n_changes);
+        r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes);
         if (r < 0)
-                return r;
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
 }
 
 static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_disable_unit_files_generic(message, userdata, "disable", unit_file_disable, error);
+        return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
 }
 
 static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
+        return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error);
+}
+
+static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **l = NULL;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read_strv(message, &l);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_manage_unit_files_async(m, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes);
+        if (r < 0)
+                return install_error(error, r, changes, n_changes);
+
+        return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
 }
 
 static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
         Manager *m = userdata;
-        UnitFileScope scope;
         const char *name;
         int force, r;
 
@@ -1796,11 +1923,9 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
+        r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes);
         if (r < 0)
-                return r;
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
 }
@@ -1810,7 +1935,6 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
         unsigned n_changes = 0;
         Manager *m = userdata;
         UnitFilePresetMode mm;
-        UnitFileScope scope;
         const char *mode;
         int force, runtime, r;
 
@@ -1839,13 +1963,9 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
-        if (r < 0) {
-                unit_file_changes_free(changes, n_changes);
-                return r;
-        }
+        r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes);
+        if (r < 0)
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
 }
@@ -1855,10 +1975,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
         Manager *m = userdata;
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
-        UnitFileScope scope;
         int runtime, force, r;
-        char *target;
-        char *type;
+        char *target, *type;
         UnitDependency dep;
 
         assert(message);
@@ -1882,13 +2000,9 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
         if (dep < 0)
                 return -EINVAL;
 
-        scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
-        r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
-        if (r == -ESHUTDOWN)
-                return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
+        r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
         if (r < 0)
-                return r;
+                return install_error(error, r, changes, n_changes);
 
         return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
 }
@@ -1924,7 +2038,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
         SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
@@ -1936,7 +2050,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
         SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1992,12 +2107,14 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ListUnitsByPatterns", "asas", "a(ssssssouso)", method_list_units_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2016,6 +2133,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ListUnitFilesByPatterns", "asas", "a(ss)", method_list_unit_files_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2025,6 +2143,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RevertUnitFiles", "as", "a(sss)", method_revert_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
index d33e494f6bab066e67d94edb8dbd38cbf460042a..bb09a515f88c8afd1c20163585a769d2d39d805c 100644 (file)
@@ -149,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = {
         SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
         SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
         SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
index bc121b83a27ac4143c864090e7481c067c8cd5bb..a0e61b023ecd1938970b4396f84ebe33a8c447f1 100644 (file)
@@ -156,7 +156,7 @@ static int property_get_next_elapse_monotonic(
                 usec_t a, b;
 
                 a = now(CLOCK_MONOTONIC);
-                b = now(CLOCK_BOOTTIME);
+                b = now(clock_boottime_or_monotonic());
 
                 if (t->next_elapse_monotonic_or_boottime + a > b)
                         x = t->next_elapse_monotonic_or_boottime + a - b;
index b351f6a2c20394468aebc71d93e8edd17a9bcded..e912fe2192871538fc7663835bb679759a5d933f 100644 (file)
 #include "cgroup-util.h"
 #include "dbus-unit.h"
 #include "dbus.h"
+#include "fd-util.h"
 #include "locale-util.h"
 #include "log.h"
+#include "process-util.h"
 #include "selinux-access.h"
+#include "signal-util.h"
 #include "special.h"
 #include "string-util.h"
 #include "strv.h"
@@ -547,7 +550,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
         }
 
-        if (signo <= 0 || signo >= _NSIG)
+        if (!SIGNAL_VALID(signo))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
 
         r = bus_verify_manage_units_async_full(
@@ -701,7 +704,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
         SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
         SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -840,6 +844,145 @@ static int property_get_cgroup(
         return sd_bus_message_append(reply, "s", t);
 }
 
+static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) {
+        _cleanup_free_ char *buf = NULL, *cmdline = NULL;
+        int r;
+
+        assert(reply);
+        assert(pid > 0);
+
+        r = set_put(pids, PID_TO_PTR(pid));
+        if (r == -EEXIST || r == 0)
+                return 0;
+        if (r < 0)
+                return r;
+
+        if (!p) {
+                r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf);
+                if (r == -ESRCH)
+                        return 0;
+                if (r < 0)
+                        return r;
+
+                p = buf;
+        }
+
+        (void) get_process_cmdline(pid, 0, true, &cmdline);
+
+        return sd_bus_message_append(reply,
+                                     "(sus)",
+                                     p,
+                                     (uint32_t) pid,
+                                     cmdline);
+}
+
+static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
+        _cleanup_closedir_ DIR *d = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(reply);
+        assert(p);
+
+        r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
+        if (r == ENOENT)
+                return 0;
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                pid_t pid;
+
+                r = cg_read_pid(f, &pid);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                if (is_kernel_thread(pid) > 0)
+                        continue;
+
+                r = append_process(reply, p, pid, pids);
+                if (r < 0)
+                        return r;
+        }
+
+        r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d);
+        if (r == -ENOENT)
+                return 0;
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                _cleanup_free_ char *g = NULL, *j = NULL;
+
+                r = cg_read_subgroup(d, &g);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                j = strjoin(p, "/", g, NULL);
+                if (!j)
+                        return -ENOMEM;
+
+                r = append_cgroup(reply, j, pids);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(set_freep) Set *pids = NULL;
+        Unit *u = userdata;
+        pid_t pid;
+        int r;
+
+        assert(message);
+
+        pids = set_new(NULL);
+        if (!pids)
+                return -ENOMEM;
+
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(sus)");
+        if (r < 0)
+                return r;
+
+        if (u->cgroup_path) {
+                r = append_cgroup(reply, u->cgroup_path, pids);
+                if (r < 0)
+                        return r;
+        }
+
+        /* The main and control pids might live outside of the cgroup, hence fetch them separately */
+        pid = unit_main_pid(u);
+        if (pid > 0) {
+                r = append_process(reply, NULL, pid, pids);
+                if (r < 0)
+                        return r;
+        }
+
+        pid = unit_control_pid(u);
+        if (pid > 0) {
+                r = append_process(reply, NULL, pid, pids);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
+}
+
 const sd_bus_vtable bus_unit_cgroup_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
@@ -847,6 +990,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
         SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
         SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
         SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
+        SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END
 };
 
@@ -1002,7 +1146,6 @@ int bus_unit_queue_job(
                         type = JOB_TRY_RELOAD;
         }
 
-
         if (type == JOB_STOP &&
             (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
             unit_active_state(u) == UNIT_INACTIVE)
@@ -1099,7 +1242,10 @@ static int bus_unit_set_transient_property(
                 if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
 
-                r = manager_load_unit(u->manager, s, NULL, error, &slice);
+                /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
+                 * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare()
+                 * instead of manager_load_unit() on purpose, here. */
+                r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice);
                 if (r < 0)
                         return r;
 
@@ -1259,6 +1405,7 @@ int bus_unit_set_properties(
 }
 
 int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
+        assert(u);
 
         if (u->load_state == UNIT_LOADED)
                 return 0;
index 07948b9cd05c9c23ca19b56539d2b7066874d4ce..4db88dbebc17e402792699b75519bcf335d22e33 100644 (file)
@@ -36,5 +36,6 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
 int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
 int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
 int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
 int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
index 413489373fd5994cc44e9db21b039a4054c426b9..263955d874652065ce8832597461110a6e77995b 100644 (file)
@@ -112,7 +112,7 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus
         manager_notify_cgroup_empty(m, cgroup);
 
         /* if running as system-instance, forward under our name */
-        if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
+        if (MANAGER_IS_SYSTEM(m) && m->system_bus) {
                 r = sd_bus_message_rewind(message, 1);
                 if (r >= 0)
                         r = sd_bus_send(m->system_bus, message, NULL);
@@ -690,7 +690,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
                 return 0;
         }
 
-        if (m->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(m)) {
                 /* When we run as system instance we get the Released
                  * signal via a direct connection */
 
@@ -864,10 +864,10 @@ static int bus_init_api(Manager *m) {
                 return 0;
 
         /* The API and system bus is the same if we are running in system mode */
-        if (m->running_as == MANAGER_SYSTEM && m->system_bus)
+        if (MANAGER_IS_SYSTEM(m) && m->system_bus)
                 bus = sd_bus_ref(m->system_bus);
         else {
-                if (m->running_as == MANAGER_SYSTEM)
+                if (MANAGER_IS_SYSTEM(m))
                         r = sd_bus_open_system(&bus);
                 else
                         r = sd_bus_open_user(&bus);
@@ -907,7 +907,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
         assert(bus);
 
         /* On kdbus or if we are a user instance we get the Released message via the system bus */
-        if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
+        if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) {
                 r = sd_bus_add_match(
                                 bus,
                                 NULL,
@@ -932,7 +932,7 @@ static int bus_init_system(Manager *m) {
                 return 0;
 
         /* The API and system bus is the same if we are running in system mode */
-        if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
+        if (MANAGER_IS_SYSTEM(m) && m->api_bus) {
                 m->system_bus = sd_bus_ref(m->api_bus);
                 return 0;
         }
@@ -983,7 +983,7 @@ static int bus_init_private(Manager *m) {
         if (m->kdbus_fd >= 0)
                 return 0;
 
-        if (m->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(m)) {
 
                 /* We want the private bus only when running as init */
                 if (getpid() != 1)
@@ -1082,7 +1082,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
 
         /* Possibly flush unwritten data, but only if we are
          * unprivileged, since we don't want to sync here */
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 sd_bus_flush(*bus);
 
         /* And destroy the object */
index 28e4039da20084dd77e2ec38685257e3029aa435..16e56efcc3373c58a7ffb4255f0080a077287663 100644 (file)
@@ -265,7 +265,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
         assert(u);
         assert(dev);
 
-        property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
+        property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
         wants = udev_device_get_property_value(dev, property);
         if (!wants)
                 return 0;
@@ -322,7 +322,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
                 /* This unit is in plugged state: we're sure it's
                  * attached to a device. */
                 if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
-                        log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s",
+                        log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
                                        e, DEVICE(u)->sysfs, sysfs);
                         return -EEXIST;
                 }
@@ -841,8 +841,6 @@ const UnitVTable device_vtable = {
                 "Device\0"
                 "Install\0",
 
-        .no_instances = true,
-
         .init = device_init,
         .done = device_done,
         .load = unit_load_fragment_and_dropin_optional,
index bb2bc3f399fc5c4cc0db4f9f03c995fa7398e51f..ddae46190f46b6cc5ace84ed5a7c3c68b4879aa7 100644 (file)
@@ -47,7 +47,7 @@ int failure_action(
         if (action == FAILURE_ACTION_NONE)
                 return -ECANCELED;
 
-        if (m->running_as == MANAGER_USER) {
+        if (!MANAGER_IS_SYSTEM(m)) {
                 /* Downgrade all options to simply exiting if we run
                  * in user mode */
 
@@ -61,17 +61,17 @@ int failure_action(
         case FAILURE_ACTION_REBOOT:
                 log_and_status(m, "Rebooting as result of failure.");
 
-                update_reboot_param_file(reboot_arg);
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET,
-                                                        JOB_REPLACE_IRREVERSIBLY, NULL);
+                (void) update_reboot_parameter_and_warn(reboot_arg);
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
 
                 break;
 
         case FAILURE_ACTION_REBOOT_FORCE:
                 log_and_status(m, "Forcibly rebooting as result of failure.");
 
-                update_reboot_param_file(reboot_arg);
+                (void) update_reboot_parameter_and_warn(reboot_arg);
                 m->exit_code = MANAGER_REBOOT;
+
                 break;
 
         case FAILURE_ACTION_REBOOT_IMMEDIATE:
@@ -79,9 +79,10 @@ int failure_action(
 
                 sync();
 
-                if (reboot_arg) {
+                if (!isempty(reboot_arg)) {
                         log_info("Rebooting with argument '%s'.", reboot_arg);
                         syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg);
+                        log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
                 }
 
                 log_info("Rebooting.");
@@ -90,8 +91,7 @@ int failure_action(
 
         case FAILURE_ACTION_POWEROFF:
                 log_and_status(m, "Powering off as result of failure.");
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET,
-                                                        JOB_REPLACE_IRREVERSIBLY, NULL);
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
                 break;
 
         case FAILURE_ACTION_POWEROFF_FORCE:
index ff7558d500b1dfe9dc2478fb41f51ee1f93910ca..d1b0ce76ef155596ff72d093c75675b5d35aa8d2 100644 (file)
@@ -3,7 +3,7 @@
 
   Copyright 2010 Lennart Poettering
   Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
-                                     TORSEC group -- http://security.polito.it
+                                     TORSEC group  http://security.polito.it
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
index 3bad74b24631f8229be89dbf7ec9459e2c8353fb..472b58cb00e76df22653e0f6344a5f27575e2a59 100644 (file)
@@ -5,7 +5,7 @@
 
   Copyright 2010 Lennart Poettering
   Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
-                                     TORSEC group -- http://security.polito.it
+                                     TORSEC group  http://security.polito.it
 
   systemd is free software; you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
index 5557a6a9423d65e3cdd86422d4a9a47982abc961..d9c5669c9fbb65f813dcdaeff5f8a2f238b05784 100644 (file)
@@ -137,7 +137,7 @@ void job_uninstall(Job *j) {
         /* Detach from next 'bigger' objects */
 
         /* daemon-reload should be transparent to job observers */
-        if (j->manager->n_reloading <= 0)
+        if (!MANAGER_IS_RELOADING(j->manager))
                 bus_job_send_removed_signal(j);
 
         *pj = NULL;
@@ -1156,7 +1156,7 @@ void job_shutdown_magic(Job *j) {
         if (j->type != JOB_START)
                 return;
 
-        if (j->unit->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(j->unit->manager))
                 return;
 
         if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
index 22b71b6f5e5c04837fe7e8708e18f5c6a662c254..f83fa09301530892144f42d6d517b988c64a12b8 100644 (file)
@@ -44,6 +44,7 @@ static int add_dependency_consumer(
 }
 
 int unit_load_dropin(Unit *u) {
+        _cleanup_strv_free_ char **l = NULL;
         Iterator i;
         char *t, **f;
         int r;
@@ -55,7 +56,7 @@ int unit_load_dropin(Unit *u) {
         SET_FOREACH(t, u->names, i) {
                 char **p;
 
-                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+                STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
                         unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS,
                                               add_dependency_consumer, u, NULL);
                         unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES,
@@ -63,11 +64,19 @@ int unit_load_dropin(Unit *u) {
                 }
         }
 
-        u->dropin_paths = strv_free(u->dropin_paths);
-        r = unit_find_dropin_paths(u, &u->dropin_paths);
+        r = unit_find_dropin_paths(u, &l);
         if (r <= 0)
                 return 0;
 
+        if (!u->dropin_paths) {
+                u->dropin_paths = l;
+                l = NULL;
+        } else {
+                r = strv_extend_strv(&u->dropin_paths, l, true);
+                if (r < 0)
+                        return log_oom();
+        }
+
         STRV_FOREACH(f, u->dropin_paths) {
                 config_parse(u->id, *f, NULL,
                              UNIT_VTABLE(u)->sections,
index d8a4aefbb3805a8118943f6f3e37bab46ac475ed..942d26724ed356cd80bae118d0b2ac6ba2b5dcc4 100644 (file)
@@ -25,7 +25,7 @@
 /* Read service data supplementary drop-in directories */
 
 static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
-        return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path,
+        return unit_file_find_dropin_paths(u->manager->lookup_paths.search_path,
                                            u->manager->unit_path_cache,
                                            u->names,
                                            paths);
index 5568b4696fe0f8a78a3d100b9dc70e8897b17ab5..928b913c7b88b7e3028acc191db364da96f187a0 100644 (file)
@@ -164,6 +164,8 @@ Unit.IgnoreOnSnapshot,           config_parse_warn_compat,           DISABLED_LE
 Unit.JobTimeoutSec,              config_parse_sec_fix_0,             0,                             offsetof(Unit, job_timeout)
 Unit.JobTimeoutAction,           config_parse_failure_action,        0,                             offsetof(Unit, job_timeout_action)
 Unit.JobTimeoutRebootArgument,   config_parse_string,                0,                             offsetof(Unit, job_timeout_reboot_arg)
+Unit.StartLimitIntervalSec,      config_parse_sec,                   0,                             offsetof(Unit, start_limit.interval)
+m4_dnl The following is a legacy alias name for compatibility
 Unit.StartLimitInterval,         config_parse_sec,                   0,                             offsetof(Unit, start_limit.interval)
 Unit.StartLimitBurst,            config_parse_unsigned,              0,                             offsetof(Unit, start_limit.burst)
 Unit.StartLimitAction,           config_parse_failure_action,        0,                             offsetof(Unit, start_limit_action)
@@ -220,6 +222,7 @@ Service.TimeoutStartSec,         config_parse_service_timeout,       0,
 Service.TimeoutStopSec,          config_parse_service_timeout,       0,                             0
 Service.RuntimeMaxSec,           config_parse_sec,                   0,                             offsetof(Service, runtime_max_usec)
 Service.WatchdogSec,             config_parse_sec,                   0,                             offsetof(Service, watchdog_usec)
+m4_dnl The following three only exist for compatibility, they moved into Unit, see above
 Service.StartLimitInterval,      config_parse_sec,                   0,                             offsetof(Unit, start_limit.interval)
 Service.StartLimitBurst,         config_parse_unsigned,              0,                             offsetof(Unit, start_limit.burst)
 Service.StartLimitAction,        config_parse_failure_action,        0,                             offsetof(Unit, start_limit_action)
@@ -297,6 +300,8 @@ Socket.RemoveOnStop,             config_parse_bool,                  0,
 Socket.Symlinks,                 config_parse_unit_path_strv_printf, 0,                             offsetof(Socket, symlinks)
 Socket.FileDescriptorName,       config_parse_fdname,                0,                             0
 Socket.Service,                  config_parse_socket_service,        0,                             0
+Socket.TriggerLimitIntervalSec,  config_parse_sec,                   0,                             offsetof(Socket, trigger_limit.interval)
+Socket.TriggerLimitBurst,        config_parse_unsigned,              0,                             offsetof(Socket, trigger_limit.burst)
 m4_ifdef(`HAVE_SMACK',
 `Socket.SmackLabel,              config_parse_string,                0,                             offsetof(Socket, smack)
 Socket.SmackLabelIPIn,           config_parse_string,                0,                             offsetof(Socket, smack_ip_in)
index f1a874cfdfbfe9e39180f54e2e46bb5063aa16b8..1a8c03904cd1d799bca119b3ebf4d36ecd3d0c90 100644 (file)
@@ -2495,7 +2495,7 @@ int config_parse_syscall_filter(
 
         /* Turn on NNP, but only if it wasn't configured explicitly
          * before, and only if we are in user mode. */
-        if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
+        if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager))
                 c->no_new_privileges = true;
 
         return 0;
@@ -2847,11 +2847,12 @@ int config_parse_device_allow(
                 void *data,
                 void *userdata) {
 
-        _cleanup_free_ char *path = NULL;
+        _cleanup_free_ char *path = NULL, *t = NULL;
         CGroupContext *c = data;
         CGroupDeviceAllow *a;
-        const char *m;
+        const char *m = NULL;
         size_t n;
+        int r;
 
         if (isempty(rvalue)) {
                 while (c->device_allow)
@@ -2860,8 +2861,16 @@ int config_parse_device_allow(
                 return 0;
         }
 
-        n = strcspn(rvalue, WHITESPACE);
-        path = strndup(rvalue, n);
+        r = unit_full_printf(userdata, rvalue, &t);
+        if(r < 0) {
+                log_syntax(unit, LOG_WARNING, filename, line, r,
+                           "Failed to resolve specifiers in %s, ignoring: %m",
+                           rvalue);
+        }
+
+        n = strcspn(t, WHITESPACE);
+
+        path = strndup(t, n);
         if (!path)
                 return log_oom();
 
@@ -2872,7 +2881,7 @@ int config_parse_device_allow(
                 return 0;
         }
 
-        m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+        m = t + n + strspn(t + n, WHITESPACE);
         if (isempty(m))
                 m = "rwm";
 
@@ -3418,10 +3427,10 @@ int config_parse_protect_system(
 #define FOLLOW_MAX 8
 
 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
+        char *id = NULL;
         unsigned c = 0;
         int fd, r;
         FILE *f;
-        char *id = NULL;
 
         assert(filename);
         assert(*filename);
@@ -3443,7 +3452,6 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                  * the names of this unit, but only if it is a valid
                  * unit name. */
                 name = basename(*filename);
-
                 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
 
                         id = set_get(names, name);
@@ -3483,6 +3491,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
 
         *_f = f;
         *_final = id;
+
         return 0;
 }
 
@@ -3543,13 +3552,13 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
 }
 
 static int load_from_path(Unit *u, const char *path) {
-        int r;
         _cleanup_set_free_free_ Set *symlink_names = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_free_ char *filename = NULL;
         char *id = NULL;
         Unit *merged;
         struct stat st;
+        int r;
 
         assert(u);
         assert(path);
@@ -3574,7 +3583,7 @@ static int load_from_path(Unit *u, const char *path) {
         } else  {
                 char **p;
 
-                STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+                STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
 
                         /* Instead of opening the path right away, we manually
                          * follow all symlinks and add their name to our unit
@@ -3588,18 +3597,14 @@ static int load_from_path(Unit *u, const char *path) {
                                 r = -ENOENT;
                         else
                                 r = open_follow(&filename, &f, symlink_names, &id);
+                        if (r >= 0)
+                                break;
+                        filename = mfree(filename);
+                        if (r != -ENOENT)
+                                return r;
 
-                        if (r < 0) {
-                                filename = mfree(filename);
-                                if (r != -ENOENT)
-                                        return r;
-
-                                /* Empty the symlink names for the next run */
-                                set_clear_free(symlink_names);
-                                continue;
-                        }
-
-                        break;
+                        /* Empty the symlink names for the next run */
+                        set_clear_free(symlink_names);
                 }
         }
 
@@ -3607,6 +3612,11 @@ static int load_from_path(Unit *u, const char *path) {
                 /* Hmm, no suitable file found? */
                 return 0;
 
+        if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
+                log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
+                return -ELOOP;
+        }
+
         merged = u;
         r = merge_by_names(&merged, symlink_names, id);
         if (r < 0)
index 9e6b3d3292c6ee6f9c9650d42befc86be7e5d2aa..0145fe28940de5cd37d0da5b89392d0be7d78b52 100644 (file)
@@ -101,14 +101,23 @@ static int read_machine_id(int fd, char id[34]) {
         return 0;
 }
 
-static int write_machine_id(int fd, char id[34]) {
+static int write_machine_id(int fd, const char id[34]) {
+        int r;
+
         assert(fd >= 0);
         assert(id);
 
         if (lseek(fd, 0, SEEK_SET) < 0)
                 return -errno;
 
-        return loop_write(fd, id, 33, false);
+        r = loop_write(fd, id, 33, false);
+        if (r < 0)
+                return r;
+
+        if (fsync(fd) < 0)
+                return -errno;
+
+        return 0;
 }
 
 static int generate_machine_id(char id[34], const char *root) {
@@ -120,10 +129,7 @@ static int generate_machine_id(char id[34], const char *root) {
 
         assert(id);
 
-        if (isempty(root))
-                dbus_machine_id = "/var/lib/dbus/machine-id";
-        else
-                dbus_machine_id = strjoina(root, "/var/lib/dbus/machine-id");
+        dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
 
         /* First, try reading the D-Bus machine id, unless it is a symlink */
         fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
@@ -203,18 +209,8 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
         char id[34]; /* 32 + \n + \0 */
         int r;
 
-        if (isempty(root))  {
-                etc_machine_id = "/etc/machine-id";
-                run_machine_id = "/run/machine-id";
-        } else {
-                char *x;
-
-                x = strjoina(root, "/etc/machine-id");
-                etc_machine_id = path_kill_slashes(x);
-
-                x = strjoina(root, "/run/machine-id");
-                run_machine_id = path_kill_slashes(x);
-        }
+        etc_machine_id = prefix_roota(root, "/etc/machine-id");
+        run_machine_id = prefix_roota(root, "/run/machine-id");
 
         RUN_WITH_UMASK(0000) {
                 /* We create this 0444, to indicate that this isn't really
@@ -274,10 +270,10 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
 
         RUN_WITH_UMASK(0022) {
                 r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
-        }
-        if (r < 0) {
-                (void) unlink(run_machine_id);
-                return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+                if (r < 0) {
+                        (void) unlink(run_machine_id);
+                        return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+                }
         }
 
         /* And now, let's mount it over */
@@ -301,14 +297,7 @@ int machine_id_commit(const char *root) {
         char id[34]; /* 32 + \n + \0 */
         int r;
 
-        if (isempty(root))
-                etc_machine_id = "/etc/machine-id";
-        else {
-                char *x;
-
-                x = strjoina(root, "/etc/machine-id");
-                etc_machine_id = path_kill_slashes(x);
-        }
+        etc_machine_id = prefix_roota(root, "/etc/machine-id");
 
         r = path_is_mount_point(etc_machine_id, 0);
         if (r < 0)
index 56df32426a9c121d07575af1ffbb9364fc5bb753..ed4d42c8ccd90a17b7c0c5835c9f96441fbcf52f 100644 (file)
@@ -81,6 +81,7 @@
 #include "strv.h"
 #include "switch-root.h"
 #include "terminal-util.h"
+#include "umask-util.h"
 #include "user-util.h"
 #include "virt.h"
 #include "watchdog.h"
@@ -94,7 +95,7 @@ static enum {
         ACTION_DONE
 } arg_action = ACTION_RUN;
 static char *arg_default_unit = NULL;
-static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
+static bool arg_system = false;
 static bool arg_dump_core = true;
 static int arg_crash_chvt = -1;
 static bool arg_crash_shell = false;
@@ -288,6 +289,7 @@ static int parse_crash_chvt(const char *value) {
 }
 
 static int set_machine_id(const char *m) {
+        assert(m);
 
         if (sd_id128_from_string(m, &arg_machine_id) < 0)
                 return -EINVAL;
@@ -412,6 +414,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                 target = runlevel_to_target(key);
                 if (target)
                         return free_and_strdup(&arg_default_unit, target);
+
+        } else if (streq(key, "systemd.default_timeout_start_sec") && value) {
+
+                r = parse_sec(value, &arg_default_timeout_start_usec);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
+
+                if (arg_default_timeout_start_usec <= 0)
+                        arg_default_timeout_start_usec = USEC_INFINITY;
         }
 
         return 0;
@@ -659,7 +670,8 @@ static int parse_config_file(void) {
                 { "Manager", "DefaultTimeoutStartSec",    config_parse_sec,              0, &arg_default_timeout_start_usec        },
                 { "Manager", "DefaultTimeoutStopSec",     config_parse_sec,              0, &arg_default_timeout_stop_usec         },
                 { "Manager", "DefaultRestartSec",         config_parse_sec,              0, &arg_default_restart_usec              },
-                { "Manager", "DefaultStartLimitInterval", config_parse_sec,              0, &arg_default_start_limit_interval      },
+                { "Manager", "DefaultStartLimitInterval", config_parse_sec,              0, &arg_default_start_limit_interval      }, /* obsolete alias */
+                { "Manager", "DefaultStartLimitIntervalSec",config_parse_sec,            0, &arg_default_start_limit_interval      },
                 { "Manager", "DefaultStartLimitBurst",    config_parse_unsigned,         0, &arg_default_start_limit_burst         },
                 { "Manager", "DefaultEnvironment",        config_parse_environ,          0, &arg_default_environment               },
                 { "Manager", "DefaultLimitCPU",           config_parse_limit,            RLIMIT_CPU, arg_default_rlimit            },
@@ -688,11 +700,11 @@ static int parse_config_file(void) {
 
         const char *fn, *conf_dirs_nulstr;
 
-        fn = arg_running_as == MANAGER_SYSTEM ?
+        fn = arg_system ?
                 PKGSYSCONFDIR "/system.conf" :
                 PKGSYSCONFDIR "/user.conf";
 
-        conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
+        conf_dirs_nulstr = arg_system ?
                 CONF_PATHS_NULSTR("systemd/system.conf.d") :
                 CONF_PATHS_NULSTR("systemd/user.conf.d");
 
@@ -866,11 +878,11 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_SYSTEM:
-                        arg_running_as = MANAGER_SYSTEM;
+                        arg_system = true;
                         break;
 
                 case ARG_USER:
-                        arg_running_as = MANAGER_USER;
+                        arg_system = false;
                         break;
 
                 case ARG_TEST:
@@ -1237,7 +1249,8 @@ static int write_container_id(void) {
         if (isempty(c))
                 return 0;
 
-        r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+        RUN_WITH_UMASK(0022)
+                r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
         if (r < 0)
                 return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
 
@@ -1336,7 +1349,7 @@ int main(int argc, char *argv[]) {
         saved_argv = argv;
         saved_argc = argc;
 
-        log_show_color(isatty(STDERR_FILENO) > 0);
+        log_show_color(colors_enabled());
         log_set_upgrade_syslog_to_journal(true);
 
         /* Disable the umask logic */
@@ -1346,7 +1359,7 @@ int main(int argc, char *argv[]) {
         if (getpid() == 1 && detect_container() <= 0) {
 
                 /* Running outside of a container as PID 1 */
-                arg_running_as = MANAGER_SYSTEM;
+                arg_system = true;
                 make_null_stdio();
                 log_set_target(LOG_TARGET_KMSG);
                 log_open();
@@ -1430,7 +1443,7 @@ int main(int argc, char *argv[]) {
 
         } else if (getpid() == 1) {
                 /* Running inside a container, as PID 1 */
-                arg_running_as = MANAGER_SYSTEM;
+                arg_system = true;
                 log_set_target(LOG_TARGET_CONSOLE);
                 log_close_console(); /* force reopen of /dev/console */
                 log_open();
@@ -1443,7 +1456,7 @@ int main(int argc, char *argv[]) {
                 kernel_timestamp = DUAL_TIMESTAMP_NULL;
         } else {
                 /* Running as user instance */
-                arg_running_as = MANAGER_USER;
+                arg_system = false;
                 log_set_target(LOG_TARGET_AUTO);
                 log_open();
 
@@ -1501,7 +1514,7 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_running_as == MANAGER_SYSTEM) {
+        if (arg_system) {
                 r = parse_proc_cmdline(parse_proc_cmdline_item);
                 if (r < 0)
                         log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@@ -1522,14 +1535,14 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_running_as == MANAGER_USER &&
+        if (!arg_system &&
             arg_action == ACTION_RUN &&
             sd_booted() <= 0) {
                 log_error("Trying to run as user instance, but the system has not been booted with systemd.");
                 goto finish;
         }
 
-        if (arg_running_as == MANAGER_SYSTEM &&
+        if (arg_system &&
             arg_action == ACTION_RUN &&
             running_in_chroot() > 0) {
                 log_error("Cannot be run in a chroot() environment.");
@@ -1557,7 +1570,7 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_running_as == MANAGER_USER &&
+        if (!arg_system &&
             !getenv("XDG_RUNTIME_DIR")) {
                 log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
                 goto finish;
@@ -1580,7 +1593,7 @@ int main(int argc, char *argv[]) {
         if (arg_serialization)
                 assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
 
-        if (arg_running_as == MANAGER_SYSTEM)
+        if (arg_system)
                 /* Become a session leader if we aren't one yet. */
                 setsid();
 
@@ -1589,7 +1602,7 @@ int main(int argc, char *argv[]) {
 
         /* Reset the console, but only if this is really init and we
          * are freshly booted */
-        if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) {
+        if (arg_system && arg_action == ACTION_RUN) {
 
                 /* If we are init, we connect stdin/stdout/stderr to
                  * /dev/null and make sure we don't have a controlling
@@ -1616,7 +1629,7 @@ int main(int argc, char *argv[]) {
                         goto finish;
         }
 
-        if (arg_running_as == MANAGER_SYSTEM) {
+        if (arg_system) {
                 int v;
 
                 log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
@@ -1652,7 +1665,7 @@ int main(int argc, char *argv[]) {
                           arg_action == ACTION_TEST ? " test" : "", getuid(), t);
         }
 
-        if (arg_running_as == MANAGER_SYSTEM && !skip_setup) {
+        if (arg_system && !skip_setup) {
                 if (arg_show_status > 0)
                         status_welcome();
 
@@ -1664,7 +1677,7 @@ int main(int argc, char *argv[]) {
                 test_usr();
         }
 
-        if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
+        if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
                 watchdog_set_timeout(&arg_runtime_watchdog);
 
         if (arg_timer_slack_nsec != NSEC_INFINITY)
@@ -1694,12 +1707,12 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        if (arg_running_as == MANAGER_USER)
+        if (!arg_system)
                 /* Become reaper of our children */
                 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
                         log_warning_errno(errno, "Failed to make us a subreaper: %m");
 
-        if (arg_running_as == MANAGER_SYSTEM) {
+        if (arg_system) {
                 bump_rlimit_nofile(&saved_rlimit_nofile);
 
                 if (empty_etc) {
@@ -1711,7 +1724,7 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m);
+        r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, arg_action == ACTION_TEST, &m);
         if (r < 0) {
                 log_emergency_errno(r, "Failed to allocate manager object: %m");
                 error_message = "Failed to allocate manager object";
@@ -1874,7 +1887,7 @@ int main(int argc, char *argv[]) {
                 case MANAGER_EXIT:
                         retval = m->return_value;
 
-                        if (m->running_as == MANAGER_USER) {
+                        if (MANAGER_IS_USER(m)) {
                                 log_debug("Exit.");
                                 goto finish;
                         }
@@ -1970,7 +1983,7 @@ finish:
                         args[i++] = SYSTEMD_BINARY_PATH;
                         if (switch_root_dir)
                                 args[i++] = "--switched-root";
-                        args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user";
+                        args[i++] = arg_system ? "--system" : "--user";
                         args[i++] = "--deserialize";
                         args[i++] = sfd;
                         args[i++] = NULL;
index e739795e7079b2be789a805b853e0e5a1bb3462e..bd00c224f4a49af956353fc1bbd7d1c461200f20 100644 (file)
@@ -49,6 +49,7 @@
 #include "dbus-manager.h"
 #include "dbus-unit.h"
 #include "dbus.h"
+#include "dirent-util.h"
 #include "env-util.h"
 #include "escape.h"
 #include "exit-status.h"
@@ -63,6 +64,7 @@
 #include "manager.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "mkdir.h"
 #include "parse-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
@@ -98,7 +100,6 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32
 static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
 static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
 static int manager_run_generators(Manager *m);
-static void manager_undo_generators(Manager *m);
 
 static void manager_watch_jobs_in_progress(Manager *m) {
         usec_t next;
@@ -491,7 +492,7 @@ static int manager_setup_signals(Manager *m) {
         if (r < 0)
                 return r;
 
-        if (m->running_as == MANAGER_SYSTEM)
+        if (MANAGER_IS_SYSTEM(m))
                 return enable_special_signals(m);
 
         return 0;
@@ -518,7 +519,7 @@ static void manager_clean_environment(Manager *m) {
 static int manager_default_environment(Manager *m) {
         assert(m);
 
-        if (m->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(m)) {
                 /* The system manager always starts with a clean
                  * environment for its children. It does not import
                  * the kernel or the parents exported variables.
@@ -547,43 +548,36 @@ static int manager_default_environment(Manager *m) {
 }
 
 
-int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
-
-        static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
-                [MANAGER_SYSTEM] = "UNIT=",
-                [MANAGER_USER] = "USER_UNIT=",
-        };
-
-        static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
-                [MANAGER_SYSTEM] = "UNIT=%s",
-                [MANAGER_USER] = "USER_UNIT=%s",
-        };
-
+int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
         Manager *m;
         int r;
 
         assert(_m);
-        assert(running_as >= 0);
-        assert(running_as < _MANAGER_RUNNING_AS_MAX);
+        assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
 
         m = new0(Manager, 1);
         if (!m)
                 return -ENOMEM;
 
-#ifdef ENABLE_EFI
-        if (running_as == MANAGER_SYSTEM && detect_container() <= 0)
-                boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
-#endif
-
-        m->running_as = running_as;
+        m->unit_file_scope = scope;
         m->exit_code = _MANAGER_EXIT_CODE_INVALID;
         m->default_timer_accuracy_usec = USEC_PER_MINUTE;
         m->default_tasks_accounting = true;
         m->default_tasks_max = UINT64_C(512);
 
+#ifdef ENABLE_EFI
+        if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
+                boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
+#endif
+
         /* Prepare log fields we can use for structured logging */
-        m->unit_log_field = unit_log_fields[running_as];
-        m->unit_log_format_string = unit_log_format_strings[running_as];
+        if (MANAGER_IS_SYSTEM(m)) {
+                m->unit_log_field = "UNIT=";
+                m->unit_log_format_string = "UNIT=%s";
+        } else {
+                m->unit_log_field = "USER_UNIT=";
+                m->unit_log_format_string = "USER_UNIT=%s";
+        }
 
         m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
 
@@ -683,6 +677,7 @@ static int manager_setup_notify(Manager *m) {
                         .sa.sa_family = AF_UNIX,
                 };
                 static const int one = 1;
+                const char *e;
 
                 /* First free all secondary fields */
                 m->notify_socket = mfree(m->notify_socket);
@@ -694,19 +689,13 @@ static int manager_setup_notify(Manager *m) {
 
                 fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
 
-                if (m->running_as == MANAGER_SYSTEM)
-                        m->notify_socket = strdup("/run/systemd/notify");
-                else {
-                        const char *e;
-
-                        e = getenv("XDG_RUNTIME_DIR");
-                        if (!e) {
-                                log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
-                                return -EINVAL;
-                        }
-
-                        m->notify_socket = strappend(e, "/systemd/notify");
+                e = manager_get_runtime_prefix(m);
+                if (!e) {
+                        log_error("Failed to determine runtime prefix.");
+                        return -EINVAL;
                 }
+
+                m->notify_socket = strappend(e, "/systemd/notify");
                 if (!m->notify_socket)
                         return log_oom();
 
@@ -756,8 +745,8 @@ static int manager_setup_kdbus(Manager *m) {
                 return -ESOCKTNOSUPPORT;
 
         m->kdbus_fd = bus_kernel_create_bus(
-                        m->running_as == MANAGER_SYSTEM ? "system" : "user",
-                        m->running_as == MANAGER_SYSTEM, &p);
+                        MANAGER_IS_SYSTEM(m) ? "system" : "user",
+                        MANAGER_IS_SYSTEM(m), &p);
 
         if (m->kdbus_fd < 0)
                 return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
@@ -778,7 +767,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
         try_bus_connect =
                 m->kdbus_fd >= 0 ||
                 reexecuting ||
-                (m->running_as == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
+                (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"));
 
         /* Try to connect to the buses, if possible. */
         return bus_init(m, try_bus_connect);
@@ -940,7 +929,7 @@ Manager* manager_free(Manager *m) {
          * around */
         manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
 
-        manager_undo_generators(m);
+        lookup_paths_flush_generator(&m->lookup_paths);
 
         bus_done(m);
 
@@ -1037,7 +1026,6 @@ static void manager_coldplug(Manager *m) {
 
 static void manager_build_unit_path_cache(Manager *m) {
         char **i;
-        _cleanup_closedir_ DIR *d = NULL;
         int r;
 
         assert(m);
@@ -1046,29 +1034,27 @@ static void manager_build_unit_path_cache(Manager *m) {
 
         m->unit_path_cache = set_new(&string_hash_ops);
         if (!m->unit_path_cache) {
-                log_error("Failed to allocate unit path cache.");
-                return;
+                r = -ENOMEM;
+                goto fail;
         }
 
         /* This simply builds a list of files we know exist, so that
          * we don't always have to go to disk */
 
-        STRV_FOREACH(i, m->lookup_paths.unit_path) {
+        STRV_FOREACH(i, m->lookup_paths.search_path) {
+                _cleanup_closedir_ DIR *d = NULL;
                 struct dirent *de;
 
                 d = opendir(*i);
                 if (!d) {
                         if (errno != ENOENT)
-                                log_error_errno(errno, "Failed to open directory %s: %m", *i);
+                                log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i);
                         continue;
                 }
 
-                while ((de = readdir(d))) {
+                FOREACH_DIRENT(de, d, r = -errno; goto fail) {
                         char *p;
 
-                        if (hidden_file(de->d_name))
-                                continue;
-
                         p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
                         if (!p) {
                                 r = -ENOMEM;
@@ -1079,20 +1065,15 @@ static void manager_build_unit_path_cache(Manager *m) {
                         if (r < 0)
                                 goto fail;
                 }
-
-                d = safe_closedir(d);
         }
 
         return;
 
 fail:
-        log_error_errno(r, "Failed to build unit path cache: %m");
-
-        set_free_free(m->unit_path_cache);
-        m->unit_path_cache = NULL;
+        log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m");
+        m->unit_path_cache = set_free_free(m->unit_path_cache);
 }
 
-
 static void manager_distribute_fds(Manager *m, FDSet *fds) {
         Iterator i;
         Unit *u;
@@ -1116,21 +1097,22 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
 
         assert(m);
 
-        dual_timestamp_get(&m->generators_start_timestamp);
-        r = manager_run_generators(m);
-        dual_timestamp_get(&m->generators_finish_timestamp);
+        r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
+        if (r < 0)
+                return r;
+
+        /* Make sure the transient directory always exists, so that it remains in the search path */
+        r = mkdir_p_label(m->lookup_paths.transient, 0755);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init(
-                        &m->lookup_paths, m->running_as, true,
-                        NULL,
-                        m->generator_unit_path,
-                        m->generator_unit_path_early,
-                        m->generator_unit_path_late);
+        dual_timestamp_get(&m->generators_start_timestamp);
+        r = manager_run_generators(m);
+        dual_timestamp_get(&m->generators_finish_timestamp);
         if (r < 0)
                 return r;
 
+        lookup_paths_reduce(&m->lookup_paths);
         manager_build_unit_path_cache(m);
 
         /* If we will deserialize make sure that during enumeration
@@ -1744,7 +1726,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                 }
 
                 log_received_signal(sfsi.ssi_signo == SIGCHLD ||
-                                    (sfsi.ssi_signo == SIGTERM && m->running_as == MANAGER_USER)
+                                    (sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m))
                                     ? LOG_DEBUG : LOG_INFO,
                                     &sfsi);
 
@@ -1755,7 +1737,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                         break;
 
                 case SIGTERM:
-                        if (m->running_as == MANAGER_SYSTEM) {
+                        if (MANAGER_IS_SYSTEM(m)) {
                                 /* This is for compatibility with the
                                  * original sysvinit */
                                 m->exit_code = MANAGER_REEXECUTE;
@@ -1765,7 +1747,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                         /* Fall through */
 
                 case SIGINT:
-                        if (m->running_as == MANAGER_SYSTEM) {
+                        if (MANAGER_IS_SYSTEM(m)) {
 
                                 /* If the user presses C-A-D more than
                                  * 7 times within 2s, we reboot
@@ -1791,14 +1773,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                         break;
 
                 case SIGWINCH:
-                        if (m->running_as == MANAGER_SYSTEM)
+                        if (MANAGER_IS_SYSTEM(m))
                                 manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
 
                         /* This is a nop on non-init */
                         break;
 
                 case SIGPWR:
-                        if (m->running_as == MANAGER_SYSTEM)
+                        if (MANAGER_IS_SYSTEM(m))
                                 manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
 
                         /* This is a nop on non-init */
@@ -1906,7 +1888,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
                                 break;
 
                         case 24:
-                                if (m->running_as == MANAGER_USER) {
+                                if (MANAGER_IS_USER(m)) {
                                         m->exit_code = MANAGER_EXIT;
                                         return 0;
                                 }
@@ -2022,7 +2004,7 @@ int manager_loop(Manager *m) {
         while (m->exit_code == MANAGER_OK) {
                 usec_t wait_usec;
 
-                if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM)
+                if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m))
                         watchdog_ping();
 
                 if (!ratelimit_test(&rl)) {
@@ -2047,7 +2029,7 @@ int manager_loop(Manager *m) {
                         continue;
 
                 /* Sleep for half the watchdog time */
-                if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && m->running_as == MANAGER_SYSTEM) {
+                if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m)) {
                         wait_usec = m->runtime_watchdog / 2;
                         if (wait_usec <= 0)
                                 wait_usec = 1;
@@ -2118,7 +2100,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         const char *msg;
         int audit_fd, r;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return;
 
         audit_fd = get_audit_fd();
@@ -2127,7 +2109,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
 
         /* Don't generate audit events if the service was already
          * started and we're just deserializing */
-        if (m->n_reloading > 0)
+        if (MANAGER_IS_RELOADING(m))
                 return;
 
         if (u->type != UNIT_SERVICE)
@@ -2161,10 +2143,10 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
 
         /* Don't generate plymouth events if the service was already
          * started and we're just deserializing */
-        if (m->n_reloading > 0)
+        if (MANAGER_IS_RELOADING(m))
                 return;
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return;
 
         if (detect_container() > 0)
@@ -2208,8 +2190,8 @@ int manager_open_serialization(Manager *m, FILE **_f) {
 
         assert(_f);
 
-        path = m->running_as == MANAGER_SYSTEM ? "/run/systemd" : "/tmp";
-        fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
+        path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp";
+        fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
         if (fd < 0)
                 return -errno;
 
@@ -2539,23 +2521,19 @@ int manager_reload(Manager *m) {
 
         /* From here on there is no way back. */
         manager_clear_jobs_and_units(m);
-        manager_undo_generators(m);
+        lookup_paths_flush_generator(&m->lookup_paths);
         lookup_paths_free(&m->lookup_paths);
 
-        /* Find new unit paths */
-        q = manager_run_generators(m);
+        q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
         if (q < 0 && r >= 0)
                 r = q;
 
-        q = lookup_paths_init(
-                        &m->lookup_paths, m->running_as, true,
-                        NULL,
-                        m->generator_unit_path,
-                        m->generator_unit_path_early,
-                        m->generator_unit_path_late);
+        /* Find new unit paths */
+        q = manager_run_generators(m);
         if (q < 0 && r >= 0)
                 r = q;
 
+        lookup_paths_reduce(&m->lookup_paths);
         manager_build_unit_path_cache(m);
 
         /* First, enumerate what we can from all config files */
@@ -2589,12 +2567,6 @@ int manager_reload(Manager *m) {
         return r;
 }
 
-bool manager_is_reloading_or_reexecuting(Manager *m) {
-        assert(m);
-
-        return m->n_reloading != 0;
-}
-
 void manager_reset_failed(Manager *m) {
         Unit *u;
         Iterator i;
@@ -2626,7 +2598,7 @@ static void manager_notify_finished(Manager *m) {
         if (m->test_run)
                 return;
 
-        if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) {
+        if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
 
                 /* Note that m->kernel_usec.monotonic is always at 0,
                  * and m->firmware_usec.monotonic and
@@ -2691,7 +2663,7 @@ static void manager_notify_finished(Manager *m) {
 void manager_check_finished(Manager *m) {
         assert(m);
 
-        if (m->n_reloading > 0)
+        if (MANAGER_IS_RELOADING(m))
                 return;
 
         /* Verify that we are actually running currently. Initially
@@ -2732,77 +2704,6 @@ void manager_check_finished(Manager *m) {
         manager_invalidate_startup_units(m);
 }
 
-static int create_generator_dir(Manager *m, char **generator, const char *name) {
-        char *p;
-        int r;
-
-        assert(m);
-        assert(generator);
-        assert(name);
-
-        if (*generator)
-                return 0;
-
-        if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
-                /* systemd --system, not running --test */
-
-                p = strappend("/run/systemd/", name);
-                if (!p)
-                        return log_oom();
-
-                r = mkdir_p_label(p, 0755);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to create generator directory %s: %m", p);
-                        free(p);
-                        return r;
-                }
-        } else if (m->running_as == MANAGER_USER) {
-                const char *s = NULL;
-
-                s = getenv("XDG_RUNTIME_DIR");
-                if (!s)
-                        return -EINVAL;
-                p = strjoin(s, "/systemd/", name, NULL);
-                if (!p)
-                        return log_oom();
-
-                r = mkdir_p_label(p, 0755);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to create generator directory %s: %m", p);
-                        free(p);
-                        return r;
-                }
-        } else {
-                /* systemd --system --test */
-
-                p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
-                if (!p)
-                        return log_oom();
-
-                if (!mkdtemp(p)) {
-                        log_error_errno(errno, "Failed to create generator directory %s: %m", p);
-                        free(p);
-                        return -errno;
-                }
-        }
-
-        *generator = p;
-        return 0;
-}
-
-static void trim_generator_dir(Manager *m, char **generator) {
-        assert(m);
-        assert(generator);
-
-        if (!*generator)
-                return;
-
-        if (rmdir(*generator) >= 0)
-                *generator = mfree(*generator);
-
-        return;
-}
-
 static int manager_run_generators(Manager *m) {
         _cleanup_strv_free_ char **paths = NULL;
         const char *argv[5];
@@ -2814,71 +2715,40 @@ static int manager_run_generators(Manager *m) {
         if (m->test_run)
                 return 0;
 
-        paths = generator_paths(m->running_as);
+        paths = generator_binary_paths(m->unit_file_scope);
         if (!paths)
                 return log_oom();
 
         /* Optimize by skipping the whole process by not creating output directories
          * if no generators are found. */
         STRV_FOREACH(path, paths) {
-                r = access(*path, F_OK);
-                if (r == 0)
+                if (access(*path, F_OK) >= 0)
                         goto found;
                 if (errno != ENOENT)
                         log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
         }
+
         return 0;
 
  found:
-        r = create_generator_dir(m, &m->generator_unit_path, "generator");
-        if (r < 0)
-                goto finish;
-
-        r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
-        if (r < 0)
-                goto finish;
-
-        r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
+        r = lookup_paths_mkdir_generator(&m->lookup_paths);
         if (r < 0)
                 goto finish;
 
         argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
-        argv[1] = m->generator_unit_path;
-        argv[2] = m->generator_unit_path_early;
-        argv[3] = m->generator_unit_path_late;
+        argv[1] = m->lookup_paths.generator;
+        argv[2] = m->lookup_paths.generator_early;
+        argv[3] = m->lookup_paths.generator_late;
         argv[4] = NULL;
 
         RUN_WITH_UMASK(0022)
                 execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
 
 finish:
-        trim_generator_dir(m, &m->generator_unit_path);
-        trim_generator_dir(m, &m->generator_unit_path_early);
-        trim_generator_dir(m, &m->generator_unit_path_late);
+        lookup_paths_trim_generator(&m->lookup_paths);
         return r;
 }
 
-static void remove_generator_dir(Manager *m, char **generator) {
-        assert(m);
-        assert(generator);
-
-        if (!*generator)
-                return;
-
-        strv_remove(m->lookup_paths.unit_path, *generator);
-        (void) rm_rf(*generator, REMOVE_ROOT);
-
-        *generator = mfree(*generator);
-}
-
-static void manager_undo_generators(Manager *m) {
-        assert(m);
-
-        remove_generator_dir(m, &m->generator_unit_path);
-        remove_generator_dir(m, &m->generator_unit_path_early);
-        remove_generator_dir(m, &m->generator_unit_path_late);
-}
-
 int manager_environment_add(Manager *m, char **minus, char **plus) {
         char **a = NULL, **b = NULL, **l;
         assert(m);
@@ -2941,7 +2811,7 @@ void manager_recheck_journal(Manager *m) {
 
         assert(m);
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return;
 
         u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
@@ -2965,7 +2835,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
         assert(m);
         assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return;
 
         if (m->show_status != mode)
@@ -2982,7 +2852,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
 static bool manager_get_show_status(Manager *m, StatusType type) {
         assert(m);
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return false;
 
         if (m->no_console_output)
@@ -3004,7 +2874,7 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
 void manager_set_first_boot(Manager *m, bool b) {
         assert(m);
 
-        if (m->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(m))
                 return;
 
         if (m->first_boot != (int) b) {
@@ -3050,7 +2920,7 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
 const char *manager_get_runtime_prefix(Manager *m) {
         assert(m);
 
-        return m->running_as == MANAGER_SYSTEM ?
+        return MANAGER_IS_SYSTEM(m) ?
                "/run" :
                getenv("XDG_RUNTIME_DIR");
 }
index 9803f731295b9759eccebb30e0d2a987492160b9..17f84e6963068b392ab96e1e5a69122e29fc6cbf 100644 (file)
@@ -140,6 +140,7 @@ struct Manager {
 
         sd_event_source *jobs_in_progress_event_source;
 
+        UnitFileScope unit_file_scope;
         LookupPaths lookup_paths;
         Set *unit_path_cache;
 
@@ -162,10 +163,6 @@ struct Manager {
         dual_timestamp units_load_start_timestamp;
         dual_timestamp units_load_finish_timestamp;
 
-        char *generator_unit_path;
-        char *generator_unit_path_early;
-        char *generator_unit_path_late;
-
         struct udev* udev;
 
         /* Data specific to the device subsystem */
@@ -228,7 +225,6 @@ struct Manager {
         unsigned n_in_gc_queue;
 
         /* Flags */
-        ManagerRunningAs running_as;
         ManagerExitCode exit_code:5;
 
         bool dispatching_load_queue:1;
@@ -304,10 +300,15 @@ struct Manager {
         const char *unit_log_field;
         const char *unit_log_format_string;
 
-        int first_boot;
+        int first_boot; /* tri-state */
 };
 
-int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
+#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
+#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
+
+#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
+
+int manager_new(UnitFileScope scope, bool test_run, Manager **m);
 Manager* manager_free(Manager *m);
 
 void manager_enumerate(Manager *m);
@@ -345,8 +346,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
 
 int manager_reload(Manager *m);
 
-bool manager_is_reloading_or_reexecuting(Manager *m) _pure_;
-
 void manager_reset_failed(Manager *m);
 
 void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
index 32fe51c67ea349026790d2ae9be7f9cd0488aaff..40fc548b42fb3c610a010afa2272aad706cee2ac 100644 (file)
@@ -375,6 +375,7 @@ int mount_setup(bool loaded_policy) {
                 before_relabel = now(CLOCK_MONOTONIC);
 
                 nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+                nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
                 nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
 
                 after_relabel = now(CLOCK_MONOTONIC);
index 0fd880df5dae67f45c7dbe67acd352f46e56df9b..c8a898e4dcd6f486ebdc5410d349bd511c4aecb9 100644 (file)
@@ -86,6 +86,15 @@ static bool mount_is_network(const MountParameters *p) {
         return mount_needs_network(p->options, p->fstype);
 }
 
+static bool mount_is_loop(const MountParameters *p) {
+        assert(p);
+
+        if (fstab_test_option(p->options, "loop\0"))
+                return true;
+
+        return false;
+}
+
 static bool mount_is_bind(const MountParameters *p) {
         assert(p);
 
@@ -269,12 +278,12 @@ static int mount_add_mount_links(Mount *m) {
         }
 
         /* Adds in links to other mount points that might be needed
-         * for the source path (if this is a bind mount) to be
+         * for the source path (if this is a bind mount or a loop mount) to be
          * available. */
         pm = get_mount_parameters_fragment(m);
         if (pm && pm->what &&
             path_is_absolute(pm->what) &&
-            !mount_is_network(pm)) {
+            (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) {
 
                 r = unit_require_mounts_for(UNIT(m), pm->what);
                 if (r < 0)
@@ -336,8 +345,7 @@ static int mount_add_device_links(Mount *m) {
         if (path_equal(m->where, "/"))
                 return 0;
 
-        if (mount_is_auto(p) && !mount_is_automount(p) &&
-            UNIT(m)->manager->running_as == MANAGER_SYSTEM)
+        if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
                 device_wants_mount = true;
 
         r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
@@ -353,7 +361,7 @@ static int mount_add_quota_links(Mount *m) {
 
         assert(m);
 
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
                 return 0;
 
         p = get_mount_parameters_fragment(m);
@@ -377,8 +385,7 @@ static int mount_add_quota_links(Mount *m) {
 static bool should_umount(Mount *m) {
         MountParameters *p;
 
-        if (path_equal(m->where, "/") ||
-            path_equal(m->where, "/usr") ||
+        if (PATH_IN_SET(m->where, "/", "/usr") ||
             path_startswith(m->where, "/run/initramfs"))
                 return false;
 
@@ -400,7 +407,7 @@ static int mount_add_default_dependencies(Mount *m) {
         if (!UNIT(m)->default_dependencies)
                 return 0;
 
-        if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
                 return 0;
 
         /* We do not add any default dependencies to /, /usr or
@@ -409,8 +416,7 @@ static int mount_add_default_dependencies(Mount *m) {
          * Also, don't bother with anything mounted below virtual
          * file systems, it's also going to be virtual, and hence
          * not worth the effort. */
-        if (path_equal(m->where, "/") ||
-            path_equal(m->where, "/usr") ||
+        if (PATH_IN_SET(m->where, "/", "/usr") ||
             path_startswith(m->where, "/run/initramfs") ||
             path_startswith(m->where, "/proc") ||
             path_startswith(m->where, "/sys") ||
@@ -1396,7 +1402,7 @@ static int mount_setup_unit(
                         goto fail;
                 }
 
-                if (m->running_as == MANAGER_SYSTEM) {
+                if (MANAGER_IS_SYSTEM(m)) {
                         const char* target;
 
                         target = mount_needs_network(options, fstype) ?  SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
@@ -1424,7 +1430,7 @@ static int mount_setup_unit(
                         }
                 }
 
-                if (m->running_as == MANAGER_SYSTEM &&
+                if (MANAGER_IS_SYSTEM(m) &&
                     mount_needs_network(options, fstype)) {
                         /* _netdev option may have shown up late, or on a
                          * remount. Add remote-fs dependencies, even though
@@ -1793,6 +1799,14 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
         return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
 }
 
+static int mount_control_pid(Unit *u) {
+        Mount *m = MOUNT(u);
+
+        assert(m);
+
+        return m->control_pid;
+}
+
 static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
         [MOUNT_EXEC_MOUNT] = "ExecMount",
         [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
@@ -1825,9 +1839,6 @@ const UnitVTable mount_vtable = {
                 "Install\0",
         .private_section = "Mount",
 
-        .no_alias = true,
-        .no_instances = true,
-
         .init = mount_init,
         .load = mount_load,
         .done = mount_done,
@@ -1854,6 +1865,8 @@ const UnitVTable mount_vtable = {
 
         .reset_failed = mount_reset_failed,
 
+        .control_pid = mount_control_pid,
+
         .bus_vtable = bus_mount_vtable,
         .bus_set_property = bus_mount_set_property,
         .bus_commit_properties = bus_mount_commit_properties,
index 6a7a37ee924f57d11fa92739ad84c98580cb6888..6c504a5e696a77211068ca485d7b753742a5b9a8 100644 (file)
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="ListUnitsFiltered"/>
 
+                <allow send_destination="org.freedesktop.systemd1"
+                       send_interface="org.freedesktop.systemd1.Manager"
+                       send_member="ListUnitsByPatterns"/>
+
                 <allow send_destination="org.freedesktop.systemd1"
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="ListUnitFiles"/>
 
+                <allow send_destination="org.freedesktop.systemd1"
+                       send_interface="org.freedesktop.systemd1.Manager"
+                       send_member="ListUnitFilesByPatterns"/>
+
                 <allow send_destination="org.freedesktop.systemd1"
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="GetUnitFileState"/>
 
+                <allow send_destination="org.freedesktop.systemd1"
+                       send_interface="org.freedesktop.systemd1.Manager"
+                       send_member="GetUnitProcesses"/>
+
                 <allow send_destination="org.freedesktop.systemd1"
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="ListJobs"/>
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="LinkUnitFiles"/>
 
+                <allow send_destination="org.freedesktop.systemd1"
+                       send_interface="org.freedesktop.systemd1.Manager"
+                       send_member="RevertUnitFiles"/>
+
                 <allow send_destination="org.freedesktop.systemd1"
                        send_interface="org.freedesktop.systemd1.Manager"
                        send_member="PresetUnitFiles"/>
index 6ac9b8b90dd89bb468ca69b2dad12b5c9056a0b8..5e7b3eb2342f1990980a7bd1352ed9266197decc 100644 (file)
@@ -110,16 +110,14 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
                 } else {
                         exists = true;
 
-                        /* Path exists, we don't need to watch parent
-                           too closely. */
+                        /* Path exists, we don't need to watch parent too closely. */
                         if (oldslash) {
                                 char *cut2 = oldslash + (oldslash == s->path);
                                 char tmp2 = *cut2;
                                 *cut2 = '\0';
 
-                                inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
-                                /* Error is ignored, the worst can happen is
-                                   we get spurious events. */
+                                (void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
+                                /* Error is ignored, the worst can happen is we get spurious events. */
 
                                 *cut2 = tmp2;
                         }
@@ -320,7 +318,7 @@ static int path_add_default_dependencies(Path *p) {
         if (r < 0)
                 return r;
 
-        if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
                 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
                 if (r < 0)
                         return r;
index 361695c3f9a6399bc4e9696859c315d7b736c13c..238f63a7299c0030f18b8116e535beb8b5c0cba1 100644 (file)
@@ -138,7 +138,7 @@ static int scope_verify(Scope *s) {
                 return 0;
 
         if (set_isempty(UNIT(s)->pids) &&
-            !manager_is_reloading_or_reexecuting(UNIT(s)->manager) &&
+            !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
             !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
                 log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
                 return -EINVAL;
@@ -154,26 +154,27 @@ static int scope_load(Unit *u) {
         assert(s);
         assert(u->load_state == UNIT_STUB);
 
-        if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
+        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
+                /* Refuse to load non-transient scope units, but allow them while reloading. */
                 return -ENOENT;
 
-        u->load_state = UNIT_LOADED;
-
-        r = unit_load_dropin(u);
+        r = unit_load_fragment_and_dropin_optional(u);
         if (r < 0)
                 return r;
 
-        r = unit_patch_contexts(u);
-        if (r < 0)
-                return r;
+        if (u->load_state == UNIT_LOADED) {
+                r = unit_patch_contexts(u);
+                if (r < 0)
+                        return r;
 
-        r = unit_set_default_slice(u);
-        if (r < 0)
-                return r;
+                r = unit_set_default_slice(u);
+                if (r < 0)
+                        return r;
 
-        r = scope_add_default_dependencies(s);
-        if (r < 0)
-                return r;
+                r = scope_add_default_dependencies(s);
+                if (r < 0)
+                        return r;
+        }
 
         return scope_verify(s);
 }
@@ -292,7 +293,7 @@ static int scope_start(Unit *u) {
 
         assert(s->state == SCOPE_DEAD);
 
-        if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
+        if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
                 return -ENOENT;
 
         (void) unit_realize_cgroup(u);
@@ -568,8 +569,6 @@ const UnitVTable scope_vtable = {
                 "Install\0",
         .private_section = "Scope",
 
-        .no_alias = true,
-        .no_instances = true,
         .can_transient = true,
 
         .init = scope_init,
index 2cdfcf7b5d1ab3ef52308b979f1fe37b8e769305..cc287d602d48d812fa6d68d7379db272c609af5e 100644 (file)
@@ -110,6 +110,7 @@ static int callback_type_to_priority(int type) {
 */
 _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
         va_list ap;
+        const char *fmt2;
 
 #ifdef HAVE_AUDIT
         int fd;
@@ -131,8 +132,10 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
         }
 #endif
 
+        fmt2 = strjoina("selinux: ", fmt);
+
         va_start(ap, fmt);
-        log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
+        log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt2, ap);
         va_end(ap);
 
         return 0;
index 5d58b0b752a5925f8ab409fbd6d47f2812331c74..f7a3fcf2b99c646ecac343ea743d4b4eb975bb32 100644 (file)
@@ -180,20 +180,17 @@ static int service_set_main_pid(Service *s, pid_t pid) {
         return 0;
 }
 
-static void service_close_socket_fd(Service *s) {
+void service_close_socket_fd(Service *s) {
         assert(s);
 
-        s->socket_fd = asynchronous_close(s->socket_fd);
-}
-
-static void service_connection_unref(Service *s) {
-        assert(s);
+        /* Undo the effect of service_set_socket_fd(). */
 
-        if (!UNIT_ISSET(s->accept_socket))
-                return;
+        s->socket_fd = asynchronous_close(s->socket_fd);
 
-        socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
-        unit_ref_unset(&s->accept_socket);
+        if (UNIT_ISSET(s->accept_socket)) {
+                socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
+                unit_ref_unset(&s->accept_socket);
+        }
 }
 
 static void service_stop_watchdog(Service *s) {
@@ -321,7 +318,6 @@ static void service_done(Unit *u) {
         s->bus_name_owner = mfree(s->bus_name_owner);
 
         service_close_socket_fd(s);
-        service_connection_unref(s);
 
         unit_ref_unset(&s->accept_socket);
 
@@ -523,7 +519,7 @@ static int service_add_default_dependencies(Service *s) {
         /* Add a number of automatic dependencies useful for the
          * majority of services. */
 
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
                 /* First, pull in the really early boot stuff, and
                  * require it, so that we fail if we can't acquire
                  * it. */
@@ -832,7 +828,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         return 0;
 }
 
-static int service_search_main_pid(Service *s) {
+static void service_search_main_pid(Service *s) {
         pid_t pid = 0;
         int r;
 
@@ -841,30 +837,24 @@ static int service_search_main_pid(Service *s) {
         /* If we know it anyway, don't ever fallback to unreliable
          * heuristics */
         if (s->main_pid_known)
-                return 0;
+                return;
 
         if (!s->guess_main_pid)
-                return 0;
+                return;
 
         assert(s->main_pid <= 0);
 
-        r = unit_search_main_pid(UNIT(s), &pid);
-        if (r < 0)
-                return r;
+        if (unit_search_main_pid(UNIT(s), &pid) < 0)
+                return;
 
         log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
-        r = service_set_main_pid(s, pid);
-        if (r < 0)
-                return r;
+        if (service_set_main_pid(s, pid) < 0)
+                return;
 
         r = unit_watch_pid(UNIT(s), pid);
-        if (r < 0) {
+        if (r < 0)
                 /* FIXME: we need to do something here */
                 log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
-                return r;
-        }
-
-        return 0;
 }
 
 static void service_set_state(Service *s, ServiceState state) {
@@ -916,17 +906,15 @@ static void service_set_state(Service *s, ServiceState state) {
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                     SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
-            !(state == SERVICE_DEAD && UNIT(s)->job)) {
+            !(state == SERVICE_DEAD && UNIT(s)->job))
                 service_close_socket_fd(s);
-                service_connection_unref(s);
-        }
 
         if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
                 service_stop_watchdog(s);
 
         /* For the inactive states unit_notify() will trim the cgroup,
          * but for exit we have to do that ourselves... */
-        if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
+        if (state == SERVICE_EXITED && !MANAGER_IS_RELOADING(UNIT(s)->manager))
                 unit_prune_cgroup(UNIT(s));
 
         /* For remain_after_exit services, let's see if we can "release" the
@@ -1217,7 +1205,7 @@ static int service_spawn(
                 if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
                         return -ENOMEM;
 
-        if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
                 if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
                         return -ENOMEM;
 
@@ -2729,7 +2717,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                                 break;
                                         }
                                 } else
-                                        (void) service_search_main_pid(s);
+                                        service_search_main_pid(s);
 
                                 service_enter_start_post(s);
                                 break;
@@ -2751,16 +2739,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                                 break;
                                         }
                                 } else
-                                        (void) service_search_main_pid(s);
+                                        service_search_main_pid(s);
 
                                 service_enter_running(s, SERVICE_SUCCESS);
                                 break;
 
                         case SERVICE_RELOAD:
-                                if (f == SERVICE_SUCCESS) {
-                                        service_load_pid_file(s, true);
-                                        (void) service_search_main_pid(s);
-                                }
+                                if (f == SERVICE_SUCCESS)
+                                        if (service_load_pid_file(s, true) < 0)
+                                                service_search_main_pid(s);
 
                                 s->reload_result = f;
                                 service_enter_running(s, SERVICE_SUCCESS);
@@ -3146,9 +3133,8 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
         assert(s);
         assert(fd >= 0);
 
-        /* This is called by the socket code when instantiating a new
-         * service for a stream socket and the socket needs to be
-         * configured. */
+        /* This is called by the socket code when instantiating a new service for a stream socket and the socket needs
+         * to be configured. We take ownership of the passed fd on success. */
 
         if (UNIT(s)->load_state != UNIT_LOADED)
                 return -EINVAL;
@@ -3176,12 +3162,15 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
                         return r;
         }
 
+        r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+        if (r < 0)
+                return r;
+
         s->socket_fd = fd;
         s->socket_fd_selinux_context_net = selinux_context_net;
 
         unit_ref_set(&s->accept_socket, UNIT(sock));
-
-        return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+        return 0;
 }
 
 static void service_reset_failed(Unit *u) {
@@ -3202,6 +3191,22 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
         return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
 }
 
+static int service_main_pid(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return s->main_pid;
+}
+
+static int service_control_pid(Unit *u) {
+        Service *s = SERVICE(u);
+
+        assert(s);
+
+        return s->control_pid;
+}
+
 static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
         [SERVICE_RESTART_NO] = "no",
         [SERVICE_RESTART_ON_SUCCESS] = "on-success",
@@ -3310,6 +3315,9 @@ const UnitVTable service_vtable = {
         .notify_cgroup_empty = service_notify_cgroup_empty_event,
         .notify_message = service_notify_message,
 
+        .main_pid = service_main_pid,
+        .control_pid = service_control_pid,
+
         .bus_name_owner_change = service_bus_name_owner_change,
 
         .bus_vtable = bus_service_vtable,
index a5ced215e45b433b982296b72106e1ddb984f7af..c7f1e81bdb743e7c61c37d1e4215a8fc8446e32a 100644 (file)
@@ -80,7 +80,7 @@ typedef enum NotifyState {
 
 typedef enum ServiceResult {
         SERVICE_SUCCESS,
-        SERVICE_FAILURE_RESOURCES,
+        SERVICE_FAILURE_RESOURCES, /* a bit of a misnomer, just our catch-all error for errnos we didn't expect */
         SERVICE_FAILURE_TIMEOUT,
         SERVICE_FAILURE_EXIT_CODE,
         SERVICE_FAILURE_SIGNAL,
@@ -198,6 +198,7 @@ struct Service {
 extern const UnitVTable service_vtable;
 
 int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
+void service_close_socket_fd(Service *s);
 
 const char* service_restart_to_string(ServiceRestart i) _const_;
 ServiceRestart service_restart_from_string(const char *s) _pure_;
index 6296b4c94a16999ad1a8e6e063d4b849fcc7732f..e14755d84e7179e06aa98265249f38423a9ac020 100644 (file)
@@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
                 goto error;
         }
 
-        cg_get_root_path(&cgroup);
+        (void) cg_get_root_path(&cgroup);
 
         use_watchdog = !!getenv("WATCHDOG_USEC");
 
@@ -397,9 +397,14 @@ int main(int argc, char *argv[]) {
                 if (!in_container) {
                         _cleanup_free_ char *param = NULL;
 
-                        if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+                        r = read_one_line_file("/run/systemd/reboot-param", &param);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to read reboot parameter file: %m");
+
+                        if (!isempty(param)) {
                                 log_info("Rebooting with argument '%s'.", param);
                                 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
+                                log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
                         }
                 }
 
index 667f61bde591a194051bd94ce7e52284f1c23678..c7700b8857da8f48f22cfde61dc399fc39a90a76 100644 (file)
@@ -135,6 +135,7 @@ static int slice_load(Unit *u) {
         int r;
 
         assert(s);
+        assert(u->load_state == UNIT_STUB);
 
         r = unit_load_fragment_and_dropin_optional(u);
         if (r < 0)
@@ -308,8 +309,6 @@ const UnitVTable slice_vtable = {
                 "Install\0",
         .private_section = "Slice",
 
-        .no_alias = true,
-        .no_instances = true,
         .can_transient = true,
 
         .init = slice_init,
index dd515a17a57b7f475efdbd449a7c60302dc8abf6..7eeed068bd87064669358e265f1366e8f27016db 100644 (file)
@@ -99,6 +99,8 @@ static void socket_init(Unit *u) {
         s->exec_context.std_error = u->manager->default_std_error;
 
         s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+
+        RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500);
 }
 
 static void socket_unwatch_control_pid(Socket *s) {
@@ -227,7 +229,6 @@ int socket_instantiate_service(Socket *s) {
         if (r < 0)
                 return r;
 
-        u->no_gc = true;
         unit_ref_set(&s->service, u);
 
         return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
@@ -301,7 +302,7 @@ static int socket_add_default_dependencies(Socket *s) {
         if (r < 0)
                 return r;
 
-        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
                 r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
                 if (r < 0)
                         return r;
@@ -792,47 +793,45 @@ static void socket_close_fds(Socket *s) {
         assert(s);
 
         LIST_FOREACH(port, p, s->ports) {
+                bool was_open;
 
-                p->event_source = sd_event_source_unref(p->event_source);
-
-                if (p->fd < 0)
-                        continue;
+                was_open = p->fd >= 0;
 
+                p->event_source = sd_event_source_unref(p->event_source);
                 p->fd = safe_close(p->fd);
                 socket_cleanup_fd_list(p);
 
-                /* One little note: we should normally not delete any
-                 * sockets in the file system here! After all some
-                 * other process we spawned might still have a
-                 * reference of this fd and wants to continue to use
-                 * it. Therefore we delete sockets in the file system
-                 * before we create a new one, not after we stopped
-                 * using one! */
+                /* One little note: we should normally not delete any sockets in the file system here! After all some
+                 * other process we spawned might still have a reference of this fd and wants to continue to use
+                 * it. Therefore we normally delete sockets in the file system before we create a new one, not after we
+                 * stopped using one! That all said, if the user explicitly requested this, we'll delete them here
+                 * anyway, but only then. */
 
-                if (s->remove_on_stop) {
-                        switch (p->type) {
+                if (!was_open || !s->remove_on_stop)
+                        continue;
 
-                        case SOCKET_FIFO:
-                                unlink(p->path);
-                                break;
+                switch (p->type) {
 
-                        case SOCKET_MQUEUE:
-                                mq_unlink(p->path);
-                                break;
+                case SOCKET_FIFO:
+                        (void) unlink(p->path);
+                        break;
 
-                        case SOCKET_SOCKET:
-                                socket_address_unlink(&p->address);
-                                break;
+                case SOCKET_MQUEUE:
+                        (void) mq_unlink(p->path);
+                        break;
 
-                        default:
-                                break;
-                        }
+                case SOCKET_SOCKET:
+                        (void) socket_address_unlink(&p->address);
+                        break;
+
+                default:
+                        break;
                 }
         }
 
         if (s->remove_on_stop)
                 STRV_FOREACH(i, s->symlinks)
-                        unlink(*i);
+                        (void) unlink(*i);
 }
 
 static void socket_apply_socket_options(Socket *s, int fd) {
@@ -1887,6 +1886,9 @@ static void socket_enter_running(Socket *s, int cfd) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
+        /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or
+         * close it. */
+
         assert(s);
 
         /* We don't take connections anymore if we are supposed to
@@ -1896,7 +1898,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                 log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
 
                 if (cfd >= 0)
-                        safe_close(cfd);
+                        cfd = safe_close(cfd);
                 else  {
                         /* Flush all sockets by closing and reopening them */
                         socket_close_fds(s);
@@ -1918,6 +1920,13 @@ static void socket_enter_running(Socket *s, int cfd) {
                 return;
         }
 
+        if (!ratelimit_test(&s->trigger_limit)) {
+                safe_close(cfd);
+                log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation.");
+                socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT);
+                return;
+        }
+
         if (cfd < 0) {
                 Iterator i;
                 Unit *other;
@@ -1949,7 +1958,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                 Service *service;
 
                 if (s->n_connections >= s->max_connections) {
-                        log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections);
+                        log_unit_warning(UNIT(s), "Too many incoming connections (%u), refusing connection attempt.", s->n_connections);
                         safe_close(cfd);
                         return;
                 }
@@ -1965,6 +1974,7 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                         /* ENOTCONN is legitimate if TCP RST was received.
                          * This connection is over, but the socket unit lives on. */
+                        log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
                         safe_close(cfd);
                         return;
                 }
@@ -1983,22 +1993,24 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 service = SERVICE(UNIT_DEREF(s->service));
                 unit_ref_unset(&s->service);
-                s->n_accepted++;
-
-                UNIT(service)->no_gc = false;
 
+                s->n_accepted++;
                 unit_choose_id(UNIT(service), name);
 
                 r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
                 if (r < 0)
                         goto fail;
 
-                cfd = -1;
+                cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */
                 s->n_connections++;
 
                 r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
-                if (r < 0)
+                if (r < 0) {
+                        /* We failed to activate the new service, but it still exists. Let's make sure the service
+                         * closes and forgets the connection fd again, immediately. */
+                        service_close_socket_fd(service);
                         goto fail;
+                }
 
                 /* Notify clients about changed counters */
                 unit_add_to_dbus_queue(UNIT(s));
@@ -2781,6 +2793,14 @@ char *socket_fdname(Socket *s) {
         return UNIT(s)->id;
 }
 
+static int socket_control_pid(Unit *u) {
+        Socket *s = SOCKET(u);
+
+        assert(s);
+
+        return s->control_pid;
+}
+
 static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
         [SOCKET_EXEC_START_PRE] = "StartPre",
         [SOCKET_EXEC_START_CHOWN] = "StartChown",
@@ -2798,6 +2818,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
         [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
         [SOCKET_FAILURE_SIGNAL] = "signal",
         [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+        [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
         [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
 };
 
@@ -2846,6 +2867,8 @@ const UnitVTable socket_vtable = {
 
         .reset_failed = socket_reset_failed,
 
+        .control_pid = socket_control_pid,
+
         .bus_vtable = bus_socket_vtable,
         .bus_set_property = bus_socket_set_property,
         .bus_commit_properties = bus_socket_commit_properties,
index b537b026a7b41e3d73c281677e62800d031e5004..2a4b1bb6741a6117a3b0dda7db4c88cb41bc253c 100644 (file)
@@ -52,6 +52,7 @@ typedef enum SocketResult {
         SOCKET_FAILURE_EXIT_CODE,
         SOCKET_FAILURE_SIGNAL,
         SOCKET_FAILURE_CORE_DUMP,
+        SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
         SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
         _SOCKET_RESULT_MAX,
         _SOCKET_RESULT_INVALID = -1
@@ -156,6 +157,8 @@ struct Socket {
         bool reset_cpu_usage:1;
 
         char *fdname;
+
+        RateLimit trigger_limit;
 };
 
 /* Called from the service code when collecting fds */
index 11506d9ecb092eaa4f949e7d2057f7b59143d7c0..c018648d87b07e5030c683e0b1812b7ee495f073 100644 (file)
@@ -198,7 +198,7 @@ static int swap_add_device_links(Swap *s) {
                 return 0;
 
         if (is_device_path(s->what))
-                return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO);
+                return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO);
         else
                 /* File based swap devices need to be ordered after
                  * systemd-remount-fs.service, since they might need a
@@ -214,7 +214,7 @@ static int swap_add_default_dependencies(Swap *s) {
         if (!UNIT(s)->default_dependencies)
                 return 0;
 
-        if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
                 return 0;
 
         if (detect_container() > 0)
@@ -1426,6 +1426,14 @@ static bool swap_supported(void) {
         return supported;
 }
 
+static int swap_control_pid(Unit *u) {
+        Swap *s = SWAP(u);
+
+        assert(s);
+
+        return s->control_pid;
+}
+
 static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
         [SWAP_EXEC_ACTIVATE] = "ExecActivate",
         [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
@@ -1457,9 +1465,6 @@ const UnitVTable swap_vtable = {
                 "Install\0",
         .private_section = "Swap",
 
-        .no_alias = true,
-        .no_instances = true,
-
         .init = swap_init,
         .load = swap_load,
         .done = swap_done,
@@ -1487,6 +1492,8 @@ const UnitVTable swap_vtable = {
 
         .reset_failed = swap_reset_failed,
 
+        .control_pid = swap_control_pid,
+
         .bus_vtable = bus_swap_vtable,
         .bus_set_property = bus_swap_set_property,
         .bus_commit_properties = bus_swap_commit_properties,
index e2ded27333759b4663c44154db6e51e68c18c255..eacd7ee2822af102ea77faa8f44adf9d4b0ecd5a 100644 (file)
@@ -34,7 +34,7 @@
 #DefaultTimeoutStartSec=90s
 #DefaultTimeoutStopSec=90s
 #DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
 #DefaultStartLimitBurst=5
 #DefaultEnvironment=
 #DefaultCPUAccounting=no
index 3d0bae16e5daeb4f21e951f0f9bf3099ddb7f057..f8f5f4b2e48d00192c15398684df5a2b85e399cc 100644 (file)
@@ -109,7 +109,7 @@ static int timer_add_default_dependencies(Timer *t) {
         if (r < 0)
                 return r;
 
-        if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
                 r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
                 if (r < 0)
                         return r;
@@ -135,7 +135,7 @@ static int timer_setup_persistent(Timer *t) {
         if (!t->persistent)
                 return 0;
 
-        if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
+        if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
 
                 r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
                 if (r < 0)
@@ -320,7 +320,7 @@ static usec_t monotonic_to_boottime(usec_t t) {
         if (t <= 0)
                 return 0;
 
-        a = now(CLOCK_BOOTTIME);
+        a = now(clock_boottime_or_monotonic());
         b = now(CLOCK_MONOTONIC);
 
         if (t + a > b)
@@ -373,7 +373,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
          * rather than the monotonic clock. */
 
         ts_realtime = now(CLOCK_REALTIME);
-        ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
+        ts_monotonic = now(t->wake_system ? clock_boottime_or_monotonic() : CLOCK_MONOTONIC);
         t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
 
         LIST_FOREACH(value, v, t->values) {
index c894001cf94eb1b894a17eb3662fb4c01f09bdf2..d5370b2a1451018894f5d412ead31752e8482ec9 100644 (file)
@@ -855,7 +855,7 @@ int transaction_add_job_and_dependencies(
          * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
          * This way, we "recursively" coldplug units, ensuring that we do not look at state of
          * not-yet-coldplugged units. */
-        if (unit->manager->n_reloading > 0)
+        if (MANAGER_IS_RELOADING(unit->manager))
                 unit_coldplug(unit);
 
         /* log_debug("Pulling in %s/%s from %s/%s", */
@@ -939,7 +939,7 @@ int transaction_add_job_and_dependencies(
                                 if (r < 0) {
                                         /* unit masked, job type not applicable and unit not found are not considered as errors. */
                                         log_unit_full(dep,
-                                                      IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
+                                                      IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
                                                       r, "Cannot add dependency job, ignoring: %s",
                                                       bus_error_message(e, r));
                                         sd_bus_error_free(e);
index 9e18a39a674877ec52f001f46e4db24a69589e84..0d8c3031360e7dc3f4e3b2528df176cdef866082 100644 (file)
@@ -18,6 +18,8 @@
 #  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 
 # The contents of this are an example to be copied into systemd.spec.
+#
+# Minimum rpm version supported: 4.13.0
 
 %transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
 -- This script will run after any package is initially installed or
index fc057d965c636ce52d0cf49d895434c1c2607ef5..f11df42af389ff9a415b626592941e65f179b6bd 100644 (file)
@@ -140,14 +140,9 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
 
         assert(u);
 
-        if (u->manager->running_as == MANAGER_SYSTEM)
-                e = "/run";
-        else {
-                e = getenv("XDG_RUNTIME_DIR");
-                if (!e)
-                        return -EOPNOTSUPP;
-        }
-
+        e = manager_get_runtime_prefix(u->manager);
+        if (!e)
+                return -EOPNOTSUPP;
         n = strdup(e);
         if (!n)
                 return -ENOMEM;
index 70175557f74db5aa1781a3d606aa1c38909b5211..4ace6b075ba48afc871266987e09f9d83b07cfcd 100644 (file)
 #include "path-util.h"
 #include "process-util.h"
 #include "set.h"
+#include "signal-util.h"
 #include "special.h"
 #include "stat-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "umask-util.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "user-util.h"
@@ -191,7 +193,7 @@ int unit_add_name(Unit *u, const char *text) {
         if (r < 0)
                 return r;
 
-        if (i && unit_vtable[t]->no_instances)
+        if (i && !unit_type_may_template(t))
                 return -EINVAL;
 
         /* Ensure that this unit is either instanced or not instanced,
@@ -200,7 +202,7 @@ int unit_add_name(Unit *u, const char *text) {
         if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
                 return -EINVAL;
 
-        if (unit_vtable[t]->no_alias && !set_isempty(u->names))
+        if (!unit_type_may_alias(t) && !set_isempty(u->names))
                 return -EEXIST;
 
         if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
@@ -418,13 +420,22 @@ static void unit_remove_transient(Unit *u) {
                 (void) unlink(u->fragment_path);
 
         STRV_FOREACH(i, u->dropin_paths) {
-                _cleanup_free_ char *p = NULL;
+                _cleanup_free_ char *p = NULL, *pp = NULL;
 
-                (void) unlink(*i);
+                p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */
+                if (!p)
+                        continue;
+
+                pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */
+                if (!pp)
+                        continue;
+
+                /* Only drop transient drop-ins */
+                if (!path_equal(u->manager->lookup_paths.transient, pp))
+                        continue;
 
-                p = dirname_malloc(*i);
-                if (p)
-                        (void) rmdir(p);
+                (void) unlink(*i);
+                (void) rmdir(p);
         }
 }
 
@@ -483,7 +494,10 @@ void unit_free(Unit *u) {
 
         assert(u);
 
-        if (u->manager->n_reloading <= 0)
+        if (u->transient_file)
+                fclose(u->transient_file);
+
+        if (!MANAGER_IS_RELOADING(u->manager))
                 unit_remove_transient(u);
 
         bus_unit_send_removed_signal(u);
@@ -706,6 +720,9 @@ int unit_merge(Unit *u, Unit *other) {
         if (!u->instance != !other->instance)
                 return -EINVAL;
 
+        if (!unit_type_may_alias(u->type)) /* Merging only applies to unit names that support aliases */
+                return -EEXIST;
+
         if (other->load_state != UNIT_STUB &&
             other->load_state != UNIT_NOT_FOUND)
                 return -EEXIST;
@@ -762,9 +779,9 @@ int unit_merge(Unit *u, Unit *other) {
 }
 
 int unit_merge_by_name(Unit *u, const char *name) {
+        _cleanup_free_ char *s = NULL;
         Unit *other;
         int r;
-        _cleanup_free_ char *s = NULL;
 
         assert(u);
         assert(name);
@@ -814,7 +831,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
                         return r;
         }
 
-        if (u->manager->running_as != MANAGER_SYSTEM)
+        if (!MANAGER_IS_SYSTEM(u->manager))
                 return 0;
 
         if (c->private_tmp) {
@@ -1222,6 +1239,17 @@ int unit_load(Unit *u) {
         if (u->load_state != UNIT_STUB)
                 return 0;
 
+        if (u->transient_file) {
+                r = fflush_and_check(u->transient_file);
+                if (r < 0)
+                        goto fail;
+
+                fclose(u->transient_file);
+                u->transient_file = NULL;
+
+                u->dropin_mtime = now(CLOCK_REALTIME);
+        }
+
         if (UNIT_VTABLE(u)->load) {
                 r = UNIT_VTABLE(u)->load(u);
                 if (r < 0)
@@ -1472,11 +1500,6 @@ int unit_start(Unit *u) {
         if (UNIT_IS_ACTIVE_OR_RELOADING(state))
                 return -EALREADY;
 
-        /* Make sure we don't enter a busy loop of some kind. */
-        r = unit_start_limit_test(u);
-        if (r < 0)
-                return r;
-
         /* Units that aren't loaded cannot be started */
         if (u->load_state != UNIT_LOADED)
                 return -EINVAL;
@@ -1518,6 +1541,11 @@ int unit_start(Unit *u) {
         if (!UNIT_VTABLE(u)->start)
                 return -EBADR;
 
+        /* Make sure we don't enter a busy loop of some kind. */
+        r = unit_start_limit_test(u);
+        if (r < 0)
+                return r;
+
         /* We don't suppress calls to ->start() here when we are
          * already starting, to allow this request to be used as a
          * "hurry up" call, for example when the unit is in some "auto
@@ -1834,7 +1862,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         m = u->manager;
 
         /* Update timestamps for state changes */
-        if (m->n_reloading <= 0) {
+        if (!MANAGER_IS_RELOADING(m)) {
                 dual_timestamp_get(&u->state_change_timestamp);
 
                 if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -1941,7 +1969,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         } else
                 unexpected = true;
 
-        if (m->n_reloading <= 0) {
+        if (!MANAGER_IS_RELOADING(m)) {
 
                 /* If this state change happened without being
                  * requested by a job, then let's retroactively start
@@ -1978,7 +2006,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
 
                 if (u->type == UNIT_SERVICE &&
                     !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
-                    m->n_reloading <= 0) {
+                    !MANAGER_IS_RELOADING(m)) {
                         /* Write audit record if we have just finished starting up */
                         manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
                         u->in_audit = true;
@@ -1995,7 +2023,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 if (u->type == UNIT_SERVICE &&
                     UNIT_IS_INACTIVE_OR_FAILED(ns) &&
                     !UNIT_IS_INACTIVE_OR_FAILED(os) &&
-                    m->n_reloading <= 0) {
+                    !MANAGER_IS_RELOADING(m)) {
 
                         /* Hmm, if there was no start record written
                          * write it now, so that we always have a nice
@@ -2016,7 +2044,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
         manager_recheck_journal(m);
         unit_trigger_notify(u);
 
-        if (u->manager->n_reloading <= 0) {
+        if (!MANAGER_IS_RELOADING(u->manager)) {
                 /* Maybe we finished startup and are now ready for
                  * being stopped because unneeded? */
                 unit_check_unneeded(u);
@@ -2413,7 +2441,7 @@ int unit_set_default_slice(Unit *u) {
                 if (!escaped)
                         return -ENOMEM;
 
-                if (u->manager->running_as == MANAGER_SYSTEM)
+                if (MANAGER_IS_SYSTEM(u->manager))
                         b = strjoin("system-", escaped, ".slice", NULL);
                 else
                         b = strappend(escaped, ".slice");
@@ -2423,7 +2451,7 @@ int unit_set_default_slice(Unit *u) {
                 slice_name = b;
         } else
                 slice_name =
-                        u->manager->running_as == MANAGER_SYSTEM && !unit_has_name(u, SPECIAL_INIT_SCOPE)
+                        MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE)
                         ? SPECIAL_SYSTEM_SLICE
                         : SPECIAL_ROOT_SLICE;
 
@@ -2493,12 +2521,11 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
                 return -EBUSY;
 
         match = strjoina("type='signal',"
-                        "sender='org.freedesktop.DBus',"
-                        "path='/org/freedesktop/DBus',"
-                        "interface='org.freedesktop.DBus',"
-                        "member='NameOwnerChanged',"
-                        "arg0='", name, "'",
-                        NULL);
+                         "sender='org.freedesktop.DBus',"
+                         "path='/org/freedesktop/DBus',"
+                         "interface='org.freedesktop.DBus',"
+                         "member='NameOwnerChanged',"
+                         "arg0='", name, "'");
 
         return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
 }
@@ -2884,7 +2911,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
                 return r;
 
         r = unit_add_two_dependencies(u, UNIT_AFTER,
-                                      u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS,
+                                      MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS,
                                       device, true);
         if (r < 0)
                 return r;
@@ -3040,8 +3067,7 @@ bool unit_active_or_pending(Unit *u) {
 int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
         assert(u);
         assert(w >= 0 && w < _KILL_WHO_MAX);
-        assert(signo > 0);
-        assert(signo < _NSIG);
+        assert(SIGNAL_VALID(signo));
 
         if (!UNIT_VTABLE(u)->kill)
                 return -EOPNOTSUPP;
@@ -3158,7 +3184,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
 
         if (u->unit_file_state < 0 && u->fragment_path) {
                 r = unit_file_get_state(
-                                u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+                                u->manager->unit_file_scope,
                                 NULL,
                                 basename(u->fragment_path),
                                 &u->unit_file_state);
@@ -3174,7 +3200,7 @@ int unit_get_unit_file_preset(Unit *u) {
 
         if (u->unit_file_preset < 0 && u->fragment_path)
                 u->unit_file_preset = unit_file_query_preset(
-                                u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+                                u->manager->unit_file_scope,
                                 NULL,
                                 basename(u->fragment_path));
 
@@ -3199,6 +3225,10 @@ void unit_ref_unset(UnitRef *ref) {
         if (!ref->unit)
                 return;
 
+        /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might
+         * be unreferenced now. */
+        unit_add_to_gc_queue(ref->unit);
+
         LIST_REMOVE(refs, ref->unit->refs, ref);
         ref->unit = NULL;
 }
@@ -3225,7 +3255,7 @@ int unit_patch_contexts(Unit *u) {
                                         return -ENOMEM;
                         }
 
-                if (u->manager->running_as == MANAGER_USER &&
+                if (MANAGER_IS_USER(u->manager) &&
                     !ec->working_directory) {
 
                         r = get_home_dir(&ec->working_directory);
@@ -3237,7 +3267,7 @@ int unit_patch_contexts(Unit *u) {
                         ec->working_directory_missing_ok = true;
                 }
 
-                if (u->manager->running_as == MANAGER_USER &&
+                if (MANAGER_IS_USER(u->manager) &&
                     (ec->syscall_whitelist ||
                      !set_isempty(ec->syscall_filter) ||
                      !set_isempty(ec->syscall_archs) ||
@@ -3315,59 +3345,62 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
         return *(ExecRuntime**) ((uint8_t*) u + offset);
 }
 
-static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
+static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
         assert(u);
 
-        if (u->manager->running_as == MANAGER_USER) {
-                int r;
+        if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
+                return NULL;
 
-                if (mode == UNIT_PERSISTENT && !transient)
-                        r = user_config_home(dir);
-                else
-                        r = user_runtime_dir(dir);
-                if (r == 0)
-                        return -ENOENT;
+        if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
+                return u->manager->lookup_paths.transient;
 
-                return r;
-        }
+        if (mode == UNIT_RUNTIME)
+                return u->manager->lookup_paths.runtime_control;
 
-        if (mode == UNIT_PERSISTENT && !transient)
-                *dir = strdup("/etc/systemd/system");
-        else
-                *dir = strdup("/run/systemd/system");
-        if (!*dir)
-                return -ENOMEM;
+        if (mode == UNIT_PERSISTENT)
+                return u->manager->lookup_paths.persistent_control;
 
-        return 0;
+        return NULL;
 }
 
 int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-
-        _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
+        _cleanup_free_ char *p = NULL, *q = NULL;
+        const char *dir, *prefixed;
         int r;
 
         assert(u);
 
+        if (u->transient_file) {
+                /* When this is a transient unit file in creation, then let's not create a new drop-in but instead
+                 * write to the transient unit file. */
+                fputs(data, u->transient_file);
+                return 0;
+        }
+
         if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
                 return 0;
 
-        r = unit_drop_in_dir(u, mode, u->transient, &dir);
-        if (r < 0)
-                return r;
+        dir = unit_drop_in_dir(u, mode);
+        if (!dir)
+                return -EINVAL;
 
-        r = write_drop_in(dir, u->id, 50, name, data);
+        prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n",
+                            data);
+
+        r = drop_in_file(dir, u->id, 50, name, &p, &q);
         if (r < 0)
                 return r;
 
-        r = drop_in_file(dir, u->id, 50, name, &p, &q);
+        (void) mkdir_p(p, 0755);
+        r = write_string_file_atomic_label(q, prefixed);
         if (r < 0)
                 return r;
 
-        r = strv_extend(&u->dropin_paths, q);
+        r = strv_push(&u->dropin_paths, q);
         if (r < 0)
                 return r;
+        q = NULL;
 
-        strv_sort(u->dropin_paths);
         strv_uniq(u->dropin_paths);
 
         u->dropin_mtime = now(CLOCK_REALTIME);
@@ -3398,7 +3431,7 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n
 }
 
 int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-        _cleanup_free_ char *ndata = NULL;
+        const char *ndata;
 
         assert(u);
         assert(name);
@@ -3410,9 +3443,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *
         if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
                 return 0;
 
-        ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
-        if (!ndata)
-                return -ENOMEM;
+        ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data);
 
         return unit_write_drop_in(u, mode, name, ndata);
 }
@@ -3440,24 +3471,51 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
 }
 
 int unit_make_transient(Unit *u) {
+        FILE *f;
+        char *path;
+
         assert(u);
 
         if (!UNIT_VTABLE(u)->can_transient)
                 return -EOPNOTSUPP;
 
-        u->load_state = UNIT_STUB;
-        u->load_error = 0;
-        u->transient = true;
+        path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL);
+        if (!path)
+                return -ENOMEM;
+
+        /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are
+         * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */
+
+        RUN_WITH_UMASK(0022) {
+                f = fopen(path, "we");
+                if (!f) {
+                        free(path);
+                        return -errno;
+                }
+        }
+
+        if (u->transient_file)
+                fclose(u->transient_file);
+        u->transient_file = f;
+
+        free(u->fragment_path);
+        u->fragment_path = path;
 
-        u->fragment_path = mfree(u->fragment_path);
         u->source_path = mfree(u->source_path);
         u->dropin_paths = strv_free(u->dropin_paths);
         u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
 
+        u->load_state = UNIT_STUB;
+        u->load_error = 0;
+        u->transient = true;
+
         unit_add_to_dbus_queue(u);
         unit_add_to_gc_queue(u);
         unit_add_to_load_queue(u);
 
+        fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
+              u->transient_file);
+
         return 0;
 }
 
@@ -3549,7 +3607,7 @@ int unit_kill_context(
                          * cases. It doesn't work at all in
                          * containers, and outside of containers it
                          * can be confused easily by left-over
-                         * directories in the cgroup -- which however
+                         * directories in the cgroup  which however
                          * should not exist in non-delegated units. On
                          * the unified hierarchy that's different,
                          * there we get proper events. Hence rely on
@@ -3750,3 +3808,21 @@ bool unit_is_pristine(Unit *u) {
                  u->job ||
                  u->merged_into);
 }
+
+pid_t unit_control_pid(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->control_pid)
+                return UNIT_VTABLE(u)->control_pid(u);
+
+        return 0;
+}
+
+pid_t unit_main_pid(Unit *u) {
+        assert(u);
+
+        if (UNIT_VTABLE(u)->main_pid)
+                return UNIT_VTABLE(u)->main_pid(u);
+
+        return 0;
+}
index 601e763ce2f8ea886293b43aa81a454c3d154f2a..be62e88421fff04514bb21239c46cfcc2fe8e63a 100644 (file)
@@ -95,6 +95,9 @@ struct Unit {
         usec_t source_mtime;
         usec_t dropin_mtime;
 
+        /* If this is a transient unit we are currently writing, this is where we are writing it to */
+        FILE *transient_file;
+
         /* If there is something to do with this unit, then this is the installed job for it */
         Job *job;
 
@@ -387,6 +390,12 @@ struct UnitVTable {
         /* Returns the next timeout of a unit */
         int (*get_timeout)(Unit *u, usec_t *timeout);
 
+        /* Returns the main PID if there is any defined, or 0. */
+        pid_t (*main_pid)(Unit *u);
+
+        /* Returns the main PID if there is any defined, or 0. */
+        pid_t (*control_pid)(Unit *u);
+
         /* This is called for each unit type and should be used to
          * enumerate existing devices and load them. However,
          * everything that is loaded here should still stay in
@@ -407,12 +416,6 @@ struct UnitVTable {
         /* The strings to print in status messages */
         UnitStatusMessageFormats status_message_formats;
 
-        /* Can units of this type have multiple names? */
-        bool no_alias:1;
-
-        /* Instances make no sense for this type */
-        bool no_instances:1;
-
         /* True if transient units of this type are OK */
         bool can_transient:1;
 };
@@ -598,6 +601,9 @@ bool unit_type_supported(UnitType t);
 
 bool unit_is_pristine(Unit *u);
 
+pid_t unit_control_pid(Unit *u);
+pid_t unit_main_pid(Unit *u);
+
 static inline bool unit_supported(Unit *u) {
         return unit_type_supported(u->type);
 }
index 87c8164378c7d587bba53ece84b900c2a69128cf..b427f1ef6d76c2af82601c1f0f9d2b0502f6f912 100644 (file)
@@ -23,7 +23,7 @@
 #DefaultTimeoutStartSec=90s
 #DefaultTimeoutStopSec=90s
 #DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
 #DefaultStartLimitBurst=5
 #DefaultEnvironment=
 #DefaultLimitCPU=
index 085909c20c20f4b8f84daf10633a09cb921668a9..41fc1993d5ef36f243a81373ae7e00ee3c16590e 100644 (file)
@@ -49,6 +49,7 @@
 #include "journald-native.h"
 #include "log.h"
 #include "macro.h"
+#include "missing.h"
 #include "mkdir.h"
 #include "parse-util.h"
 #include "process-util.h"
@@ -212,6 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
 
 #define filename_escape(s) xescape((s), "./ ")
 
+static inline const char *coredump_tmpfile_name(const char *s) {
+        return s ? s : "(unnamed temporary file)";
+}
+
 static int fix_permissions(
                 int fd,
                 const char *filename,
@@ -219,8 +224,9 @@ static int fix_permissions(
                 const char *context[_CONTEXT_MAX],
                 uid_t uid) {
 
+        int r;
+
         assert(fd >= 0);
-        assert(filename);
         assert(target);
         assert(context);
 
@@ -230,10 +236,11 @@ static int fix_permissions(
         (void) fix_xattr(fd, context);
 
         if (fsync(fd) < 0)
-                return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
+                return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
 
-        if (rename(filename, target) < 0)
-                return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
+        r = link_tmpfile(fd, filename, target);
+        if (r < 0)
+                return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
 
         return 0;
 }
@@ -335,15 +342,11 @@ static int save_external_coredump(
         if (r < 0)
                 return log_error_errno(r, "Failed to determine coredump file name: %m");
 
-        r = tempfn_random(fn, NULL, &tmp);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine temporary file name: %m");
-
         mkdir_p_label("/var/lib/systemd/coredump", 0755);
 
-        fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+        fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
         if (fd < 0)
-                return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
+                return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
 
         r = copy_bytes(input_fd, fd, max_size, false);
         if (r == -EFBIG) {
@@ -358,12 +361,12 @@ static int save_external_coredump(
         }
 
         if (fstat(fd, &st) < 0) {
-                log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
+                log_error_errno(errno, "Failed to fstat coredump %s: %m", coredump_tmpfile_name(tmp));
                 goto fail;
         }
 
         if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
-                log_error_errno(errno, "Failed to seek on %s: %m", tmp);
+                log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp));
                 goto fail;
         }
 
@@ -381,21 +384,15 @@ static int save_external_coredump(
                         goto uncompressed;
                 }
 
-                r = tempfn_random(fn_compressed, NULL, &tmp_compressed);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
-                        goto uncompressed;
-                }
-
-                fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+                fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed);
                 if (fd_compressed < 0) {
-                        log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
+                        log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed);
                         goto uncompressed;
                 }
 
                 r = compress_stream(fd, fd_compressed, -1);
                 if (r < 0) {
-                        log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
+                        log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
                         goto fail_compressed;
                 }
 
@@ -404,7 +401,8 @@ static int save_external_coredump(
                         goto fail_compressed;
 
                 /* OK, this worked, we can get rid of the uncompressed version now */
-                unlink_noerrno(tmp);
+                if (tmp)
+                        unlink_noerrno(tmp);
 
                 *ret_filename = fn_compressed;     /* compressed */
                 *ret_node_fd = fd_compressed;      /* compressed */
@@ -417,7 +415,8 @@ static int save_external_coredump(
                 return 0;
 
         fail_compressed:
-                (void) unlink(tmp_compressed);
+                if (tmp_compressed)
+                        (void) unlink(tmp_compressed);
         }
 
 uncompressed:
@@ -438,7 +437,8 @@ uncompressed:
         return 0;
 
 fail:
-        (void) unlink(tmp);
+        if (tmp)
+                (void) unlink(tmp);
         return r;
 }
 
@@ -1095,7 +1095,7 @@ static int process_kernel(int argc, char* argv[]) {
                         IOVEC_SET_STRING(iovec[n_iovec++], core_environ);
         }
 
-        core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL);
+        core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
         IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp);
 
         IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
index dac800ebef53904faf4695dbf6396f0f5d989a0b..27b1e0fb3f9d724198c371e6e50c6a7a66b9d6f1 100644 (file)
@@ -664,7 +664,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
 #endif
                 } else {
                         if (r == -ENOENT)
-                                log_error("Cannot retrieve coredump from journal nor disk.");
+                                log_error("Cannot retrieve coredump from journal or disk.");
                         else
                                 log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
                         goto error;
index 2ef966257a9d3e2615c06082d306688f765c3879..9927621ea0579452ba657fd337a0f0047833f8db 100644 (file)
@@ -719,8 +719,12 @@ int main(int argc, char *argv[]) {
                 int k;
 
                 k = crypt_init_by_name(&cd, argv[2]);
-                if (k) {
-                        log_error_errno(k, "crypt_init() failed: %m");
+                if (k == -ENODEV) {
+                        log_info("Volume %s already inactive.", argv[2]);
+                        r = EXIT_SUCCESS;
+                        goto finish;
+                } else if (k) {
+                        log_error_errno(k, "crypt_init_by_name() failed: %m");
                         goto finish;
                 }
 
index a04c8c49ff0b0f7954f236ed41118f4a3cf4f8dc..6990c47f482762768f24161c6ec667503330f346 100644 (file)
@@ -137,7 +137,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
                 if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
                         return -1;
 
-                sd_event_source_set_description(io, "curl-io");
+                (void) sd_event_source_set_description(io, "curl-io");
 
                 r = hashmap_put(g->ios, FD_TO_PTR(s), io);
                 if (r < 0) {
@@ -204,7 +204,7 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
                 if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
                         return -1;
 
-                sd_event_source_set_description(g->timer, "curl-timer");
+                (void) sd_event_source_set_description(g->timer, "curl-timer");
         }
 
         return 0;
index 18a30be36d86fee10a775ba83b425f4a78842d72..287a3382a1c260e6e2eecc3a4c8eb694b28cee06 100644 (file)
@@ -136,7 +136,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
+                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
@@ -210,7 +210,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "-C", path, "-c", ".", NULL);
+                execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
index d301d4d79e60bf4434e6d2e088eb346e2605de3a..dc4e4667a9107aeb7efee5eeb3600a27c0450521 100644 (file)
@@ -330,7 +330,7 @@ int pull_verify(PullJob *main_job,
         _cleanup_close_ int sig_file = -1;
         const char *p, *line;
         char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
-        _cleanup_sigkill_wait_ pid_t pid = 0;
+        _cleanup_(sigkill_waitp) pid_t pid = 0;
         bool gpg_home_created = false;
         int r;
 
index 998857035a5e26b3ca479bc22e090cf76c8a9f84..3a152a50e3e88b592ffdabecb326f17b729d33f2 100644 (file)
@@ -44,15 +44,6 @@ typedef enum PullJobState {
 
 #define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
 
-typedef enum PullJobCompression {
-        PULL_JOB_UNCOMPRESSED,
-        PULL_JOB_XZ,
-        PULL_JOB_GZIP,
-        PULL_JOB_BZIP2,
-        _PULL_JOB_COMPRESSION_MAX,
-        _PULL_JOB_COMPRESSION_INVALID = -1,
-} PullJobCompression;
-
 struct PullJob {
         PullJobState state;
         int error;
index 60d897758be8bcefd085327de9e3cef2afdb47a9..4ad9184993c6352a6adb3e4895f4135309da0446 100644 (file)
@@ -122,12 +122,14 @@ static int open_journal(RequestMeta *m) {
 }
 
 static int request_meta_ensure_tmp(RequestMeta *m) {
+        assert(m);
+
         if (m->tmp)
                 rewind(m->tmp);
         else {
                 int fd;
 
-                fd = open_tmpfile("/tmp", O_RDWR|O_CLOEXEC);
+                fd = open_tmpfile_unlinkable("/tmp", O_RDWR|O_CLOEXEC);
                 if (fd < 0)
                         return fd;
 
index 3864647eb7020e37e2581c955fd91b78d1b401b2..9ba9ee3fc041e01b843e43b2971a80fe61bb6734 100644 (file)
@@ -485,7 +485,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) {
         }
 
         target = source->size;
-        while (target > 16 * LINE_CHUNK && remain < target / 2)
+        while (target > 16 * LINE_CHUNK && source->filled < target / 2)
                 target /= 2;
         if (target < source->size) {
                 char *tmp;
index e61b6bc68f5ed12b8ab0282dcc44d21e64aff284..8ce8e1895e60200d249da685f9f71e0d7834ea7b 100644 (file)
@@ -25,6 +25,7 @@
 #include "log.h"
 #include "utf8.h"
 #include "util.h"
+#include "sd-daemon.h"
 
 /**
  * Write up to size bytes to buf. Return negative on error, and number of
@@ -242,6 +243,22 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
         assert_not_reached("WTF?");
 }
 
+static inline void check_update_watchdog(Uploader *u) {
+        usec_t after;
+        usec_t elapsed_time;
+
+        if (u->watchdog_usec <= 0)
+                return;
+
+        after = now(CLOCK_MONOTONIC);
+        elapsed_time = usec_sub(after, u->watchdog_timestamp);
+        if (elapsed_time > u->watchdog_usec / 2) {
+                log_debug("Update watchdog timer");
+                sd_notify(false, "WATCHDOG=1");
+                u->watchdog_timestamp = after;
+        }
+}
+
 static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void *userp) {
         Uploader *u = userp;
         int r;
@@ -252,6 +269,8 @@ static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void
         assert(u);
         assert(nmemb <= SSIZE_MAX / size);
 
+        check_update_watchdog(u);
+
         j = u->journal;
 
         while (j && filled < size * nmemb) {
index 6e1c3bb9ef45bb78adcdbdb3b79760d415582c40..4647cfdeb3aeae55c45017bdd57350b53806e8f9 100644 (file)
@@ -463,6 +463,8 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file)
         if (r < 0)
                 return log_error_errno(r, "Failed to set up signals: %m");
 
+        (void) sd_watchdog_enabled(false, &u->watchdog_usec);
+
         return load_cursor_state(u);
 }
 
@@ -494,6 +496,7 @@ static int perform_upload(Uploader *u) {
 
         assert(u);
 
+        u->watchdog_timestamp = now(CLOCK_MONOTONIC);
         code = curl_easy_perform(u->easy);
         if (code) {
                 if (u->error[0])
index b8cd04d5275f6e5b42572445a97ae157e8b18e47..5711905f86f2d9e72a600619f46200c35f5438b6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "sd-event.h"
 #include "sd-journal.h"
+#include "time-util.h"
 
 typedef enum {
         ENTRY_CURSOR = 0,           /* Nothing actually written yet. */
@@ -48,6 +49,8 @@ typedef struct Uploader {
 
         size_t entries_sent;
         char *last_cursor, *current_cursor;
+        usec_t watchdog_timestamp;
+        usec_t watchdog_usec;
 } Uploader;
 
 #define JOURNAL_UPLOAD_POLL_TIMEOUT (10 * USEC_PER_SEC)
index c43849c46a122ac898515fb56a1fb152862962aa..ba734b556119bb46772d0f50c2feb23ba691977f 100644 (file)
@@ -112,7 +112,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
         if (src_size < 9)
                 return -ENOBUFS;
 
-        r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8);
+        r = LZ4_compress_limitedOutput(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8);
         if (r <= 0)
                 return -ENOBUFS;
 
@@ -176,7 +176,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size,
                         return -ENOMEM;
 
                 s.avail_out = space - used;
-                s.next_out = *dst + used;
+                s.next_out = *(uint8_t**)dst + used;
         }
 
         *dst_size = space - s.avail_out;
@@ -215,7 +215,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size,
         } else
                 out = *dst;
 
-        r = LZ4_decompress_safe(src + 8, out, src_size - 8, size);
+        r = LZ4_decompress_safe((char*)src + 8, out, src_size - 8, size);
         if (r < 0 || r != size)
                 return -EBADMSG;
 
@@ -291,7 +291,7 @@ int decompress_startswith_xz(const void *src, uint64_t src_size,
                 if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1)))
                         return -ENOMEM;
 
-                s.next_out = *buffer + *buffer_size - s.avail_out;
+                s.next_out = *(uint8_t**)buffer + *buffer_size - s.avail_out;
         }
 
 #else
@@ -324,7 +324,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
         if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1)))
                 return -ENOMEM;
 
-        r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8,
+        r = LZ4_decompress_safe_partial((char*)src + 8, *buffer, src_size - 8,
                                         prefix_len + 1, *buffer_size);
         if (r >= 0)
                 size = (unsigned) r;
index 8956eb1d58a572d0a37dd60de3cdefba204d9cfc..612b10f3a9afea1d90614b825680cf6b32052a61 100644 (file)
@@ -58,7 +58,7 @@ static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
         gcry_mpi_t h;
         unsigned len;
 
-        gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL);
+        assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
         len = (gcry_mpi_get_nbits(h) + 7) / 8;
         assert(len <= buflen);
         assert(gcry_mpi_cmp_ui(h, 0) >= 0);
index bed825cdc39f8dad479c413ddce1688efc13326b..ec50333c2c3f70e36633db51a983f02460bde7b1 100644 (file)
@@ -37,6 +37,7 @@
 #include "journal-file.h"
 #include "lookup3.h"
 #include "parse-util.h"
+#include "path-util.h"
 #include "random-util.h"
 #include "sd-event.h"
 #include "set.h"
@@ -119,7 +120,7 @@ static void journal_file_set_offline_internal(JournalFile *f) {
                         if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_OFFLINING))
                                 continue;
 
-                        f->header->state = STATE_OFFLINE;
+                        f->header->state = f->archive ? STATE_ARCHIVED : STATE_OFFLINE;
                         (void) fsync(f->fd);
                         break;
 
@@ -217,8 +218,10 @@ int journal_file_set_offline(JournalFile *f, bool wait) {
         if (!(f->fd >= 0 && f->header))
                 return -EINVAL;
 
-        if (f->header->state != STATE_ONLINE)
-                return 0;
+        /* An offlining journal is implicitly online and may modify f->header->state,
+         * we must also join any potentially lingering offline thread when not online. */
+        if (!journal_file_is_offlining(f) && f->header->state != STATE_ONLINE)
+                return journal_file_set_offline_thread_join(f);
 
         /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */
         restarted = journal_file_set_offline_try_restart(f);
@@ -362,7 +365,8 @@ JournalFile* journal_file_close(JournalFile *f) {
                 (void) btrfs_defrag_fd(f->fd);
         }
 
-        safe_close(f->fd);
+        if (f->close_fd)
+                safe_close(f->fd);
         free(f->path);
 
         mmap_cache_unref(f->mmap);
@@ -435,6 +439,39 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) {
         return 0;
 }
 
+static int fsync_directory_of_file(int fd) {
+        _cleanup_free_ char *path = NULL, *dn = NULL;
+        _cleanup_close_ int dfd = -1;
+        struct stat st;
+        int r;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISREG(st.st_mode))
+                return -EBADFD;
+
+        r = fd_get_path(fd, &path);
+        if (r < 0)
+                return r;
+
+        if (!path_is_absolute(path))
+                return -EINVAL;
+
+        dn = dirname_malloc(path);
+        if (!dn)
+                return -ENOMEM;
+
+        dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+        if (dfd < 0)
+                return -errno;
+
+        if (fsync(dfd) < 0)
+                return -errno;
+
+        return 0;
+}
+
 static int journal_file_refresh_header(JournalFile *f) {
         sd_id128_t boot_id;
         int r;
@@ -460,6 +497,9 @@ static int journal_file_refresh_header(JournalFile *f) {
         /* Sync the online state to disk */
         (void) fsync(f->fd);
 
+        /* We likely just created a new file, also sync the directory this file is located in. */
+        (void) fsync_directory_of_file(f->fd);
+
         return r;
 }
 
@@ -703,7 +743,11 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
 
         /* Objects may only be located at multiple of 64 bit */
         if (!VALID64(offset))
-                return -EFAULT;
+                return -EBADMSG;
+
+        /* Object may not be located in the file header */
+        if (offset < le64toh(f->header->header_size))
+                return -EBADMSG;
 
         r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t);
         if (r < 0)
@@ -1976,9 +2020,14 @@ static int generic_array_bisect(
                 i = right - 1;
                 lp = p = le64toh(array->entry_array.items[i]);
                 if (p <= 0)
-                        return -EBADMSG;
-
-                r = test_object(f, p, needle);
+                        r = -EBADMSG;
+                else
+                        r = test_object(f, p, needle);
+                if (r == -EBADMSG) {
+                        log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)");
+                        n = i;
+                        continue;
+                }
                 if (r < 0)
                         return r;
 
@@ -2054,9 +2103,14 @@ static int generic_array_bisect(
 
                                 p = le64toh(array->entry_array.items[i]);
                                 if (p <= 0)
-                                        return -EBADMSG;
-
-                                r = test_object(f, p, needle);
+                                        r = -EBADMSG;
+                                else
+                                        r = test_object(f, p, needle);
+                                if (r == -EBADMSG) {
+                                        log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)");
+                                        right = n = i;
+                                        continue;
+                                }
                                 if (r < 0)
                                         return r;
 
@@ -2461,13 +2515,18 @@ int journal_file_next_entry(
                               le64toh(f->header->entry_array_offset),
                               i,
                               ret, &ofs);
+        if (r == -EBADMSG && direction == DIRECTION_DOWN) {
+                /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read,
+                 * consider this the end of the journal file. */
+                log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file.");
+                return 0;
+        }
         if (r <= 0)
                 return r;
 
         if (p > 0 &&
             (direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) {
-                log_debug("%s: entry array corrupted at entry %"PRIu64,
-                          f->path, i);
+                log_debug("%s: entry array corrupted at entry %" PRIu64, f->path, i);
                 return -EBADMSG;
         }
 
@@ -2806,11 +2865,11 @@ void journal_file_print_header(JournalFile *f) {
                "Data Hash Table Size: %"PRIu64"\n"
                "Field Hash Table Size: %"PRIu64"\n"
                "Rotate Suggested: %s\n"
-               "Head Sequential Number: %"PRIu64"\n"
-               "Tail Sequential Number: %"PRIu64"\n"
-               "Head Realtime Timestamp: %s\n"
-               "Tail Realtime Timestamp: %s\n"
-               "Tail Monotonic Timestamp: %s\n"
+               "Head Sequential Number: %"PRIu64" (%"PRIx64")\n"
+               "Tail Sequential Number: %"PRIu64" (%"PRIx64")\n"
+               "Head Realtime Timestamp: %s (%"PRIx64")\n"
+               "Tail Realtime Timestamp: %s (%"PRIx64")\n"
+               "Tail Monotonic Timestamp: %s (%"PRIx64")\n"
                "Objects: %"PRIu64"\n"
                "Entry Objects: %"PRIu64"\n",
                f->path,
@@ -2831,11 +2890,11 @@ void journal_file_print_header(JournalFile *f) {
                le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
                le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
                yes_no(journal_file_rotate_suggested(f, 0)),
-               le64toh(f->header->head_entry_seqnum),
-               le64toh(f->header->tail_entry_seqnum),
-               format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
-               format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)),
-               format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC),
+               le64toh(f->header->head_entry_seqnum), le64toh(f->header->head_entry_seqnum),
+               le64toh(f->header->tail_entry_seqnum), le64toh(f->header->tail_entry_seqnum),
+               format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), le64toh(f->header->head_entry_realtime),
+               format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), le64toh(f->header->tail_entry_realtime),
+               format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), le64toh(f->header->tail_entry_monotonic),
                le64toh(f->header->n_objects),
                le64toh(f->header->n_entries));
 
@@ -2898,6 +2957,7 @@ static int journal_file_warn_btrfs(JournalFile *f) {
 }
 
 int journal_file_open(
+                int fd,
                 const char *fname,
                 int flags,
                 mode_t mode,
@@ -2914,22 +2974,24 @@ int journal_file_open(
         void *h;
         int r;
 
-        assert(fname);
         assert(ret);
+        assert(fd >= 0 || fname);
 
         if ((flags & O_ACCMODE) != O_RDONLY &&
             (flags & O_ACCMODE) != O_RDWR)
                 return -EINVAL;
 
-        if (!endswith(fname, ".journal") &&
-            !endswith(fname, ".journal~"))
-                return -EINVAL;
+        if (fname) {
+                if (!endswith(fname, ".journal") &&
+                    !endswith(fname, ".journal~"))
+                        return -EINVAL;
+        }
 
         f = new0(JournalFile, 1);
         if (!f)
                 return -ENOMEM;
 
-        f->fd = -1;
+        f->fd = fd;
         f->mode = mode;
 
         f->flags = flags;
@@ -2954,7 +3016,10 @@ int journal_file_open(
                 }
         }
 
-        f->path = strdup(fname);
+        if (fname)
+                f->path = strdup(fname);
+        else /* If we don't know the path, fill in something explanatory and vaguely useful */
+                asprintf(&f->path, "/proc/self/%i", fd);
         if (!f->path) {
                 r = -ENOMEM;
                 goto fail;
@@ -2966,10 +3031,15 @@ int journal_file_open(
                 goto fail;
         }
 
-        f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
         if (f->fd < 0) {
-                r = -errno;
-                goto fail;
+                f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
+                if (f->fd < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                /* fds we opened here by us should also be closed by us. */
+                f->close_fd = true;
         }
 
         r = journal_file_fstat(f);
@@ -3090,6 +3160,9 @@ int journal_file_open(
                         goto fail;
         }
 
+        /* The file is opened now successfully, thus we take possesion of any passed in fd. */
+        f->close_fd = true;
+
         *ret = f;
         return 0;
 
@@ -3116,6 +3189,11 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred
         if (!old_file->writable)
                 return -EINVAL;
 
+        /* Is this a journal file that was passed to us as fd? If so, we synthesized a path name for it, and we refuse
+         * rotation, since we don't know the actual path, and couldn't rename the file hence.*/
+        if (path_startswith(old_file->path, "/proc/self/fd"))
+                return -EINVAL;
+
         if (!endswith(old_file->path, ".journal"))
                 return -EINVAL;
 
@@ -3135,14 +3213,23 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred
         if (r < 0 && errno != ENOENT)
                 return -errno;
 
-        old_file->header->state = STATE_ARCHIVED;
+        /* Sync the rename to disk */
+        (void) fsync_directory_of_file(old_file->fd);
+
+        /* Set as archive so offlining commits w/state=STATE_ARCHIVED.
+         * Previously we would set old_file->header->state to STATE_ARCHIVED directly here,
+         * but journal_file_set_offline() short-circuits when state != STATE_ONLINE, which
+         * would result in the rotated journal never getting fsync() called before closing.
+         * Now we simply queue the archive state by setting an archive bit, leaving the state
+         * as STATE_ONLINE so proper offlining occurs. */
+        old_file->archive = true;
 
         /* Currently, btrfs is not very good with out write patterns
          * and fragments heavily. Let's defrag our journal files when
          * we archive them */
         old_file->defrag_on_close = true;
 
-        r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file);
+        r = journal_file_open(-1, old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file);
 
         if (deferred_closes &&
             set_put(deferred_closes, old_file) >= 0)
@@ -3170,7 +3257,7 @@ int journal_file_open_reliably(
         size_t l;
         _cleanup_free_ char *p = NULL;
 
-        r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
+        r = journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
         if (!IN_SET(r,
                     -EBADMSG,           /* corrupted */
                     -ENODATA,           /* truncated */
@@ -3206,12 +3293,12 @@ int journal_file_open_reliably(
         /* btrfs doesn't cope well with our write pattern and
          * fragments heavily. Let's defrag all files we rotate */
 
-        (void) chattr_path(p, false, FS_NOCOW_FL);
+        (void) chattr_path(p, 0, FS_NOCOW_FL);
         (void) btrfs_defrag(p);
 
         log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
 
-        return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
+        return journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
 }
 
 int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
index 9ad601335928de88bbdd1f7178ed4115c2876222..564e1a8179b8c2bf2bbf049070d8fab0644b9b1d 100644 (file)
@@ -85,6 +85,8 @@ typedef struct JournalFile {
         bool compress_lz4:1;
         bool seal:1;
         bool defrag_on_close:1;
+        bool close_fd:1;
+        bool archive:1;
 
         bool tail_entry_monotonic_valid:1;
 
@@ -142,6 +144,7 @@ typedef struct JournalFile {
 } JournalFile;
 
 int journal_file_open(
+                int fd,
                 const char *fname,
                 int flags,
                 mode_t mode,
index 7639325acff413103d669268395ed5006dc4af85..34a48141f50f35357322d07570e832032345da0d 100644 (file)
@@ -82,6 +82,8 @@ struct Directory {
 };
 
 struct sd_journal {
+        int toplevel_fd;
+
         char *path;
         char *prefix;
 
@@ -117,6 +119,7 @@ struct sd_journal {
 
         bool on_network:1;
         bool no_new_files:1;
+        bool no_inotify:1;
         bool unique_file_lost:1; /* File we were iterating over got
                                     removed, and there were no more
                                     files, so sd_j_enumerate_unique
index a79846146a3c9175a972f7e94564e778dbad893d..f0959b623761e291dab3dcd4a063aa14d70ba390 100644 (file)
@@ -316,7 +316,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
         buffer_fd = memfd_new(NULL);
         if (buffer_fd < 0) {
                 if (buffer_fd == -ENOSYS) {
-                        buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
+                        buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
                         if (buffer_fd < 0)
                                 return buffer_fd;
 
index a1241c9bcf0a2efdf6a1303a7f7762161838384f..26572ddd76931319c0fe561f9d370d118f54b06e 100644 (file)
@@ -838,19 +838,19 @@ int journal_file_verify(
         } else if (f->seal)
                 return -ENOKEY;
 
-        data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        data_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
         if (data_fd < 0) {
                 r = log_error_errno(data_fd, "Failed to create data file: %m");
                 goto fail;
         }
 
-        entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        entry_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
         if (entry_fd < 0) {
                 r = log_error_errno(entry_fd, "Failed to create entry file: %m");
                 goto fail;
         }
 
-        entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        entry_array_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
         if (entry_array_fd < 0) {
                 r = log_error_errno(entry_array_fd,
                                     "Failed to create entry array file: %m");
index fd2cb99410b43492e06dfbf85526697f4da12319..f67c556783bbd2c1a20caa334f79974fe939499b 100644 (file)
@@ -95,11 +95,13 @@ static bool arg_boot = false;
 static sd_id128_t arg_boot_id = {};
 static int arg_boot_offset = 0;
 static bool arg_dmesg = false;
+static bool arg_no_hostname = false;
 static const char *arg_cursor = NULL;
 static const char *arg_after_cursor = NULL;
 static bool arg_show_cursor = false;
 static const char *arg_directory = NULL;
 static char **arg_file = NULL;
+static bool arg_file_stdin = false;
 static int arg_priorities = 0xFF;
 static const char *arg_verify_key = NULL;
 #ifdef HAVE_GCRYPT
@@ -304,6 +306,7 @@ static void help(void) {
                "  -a --all                 Show all fields, including long and unprintable\n"
                "  -q --quiet               Do not show info messages and privilege warning\n"
                "     --no-pager            Do not pipe output into a pager\n"
+               "     --no-hostname         Suppress output of hostname field\n"
                "  -m --merge               Show entries from all available journals\n"
                "  -D --directory=PATH      Show journal files from directory\n"
                "     --file=PATH           Show journal file\n"
@@ -370,6 +373,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VACUUM_SIZE,
                 ARG_VACUUM_FILES,
                 ARG_VACUUM_TIME,
+                ARG_NO_HOSTNAME,
         };
 
         static const struct option options[] = {
@@ -427,6 +431,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "vacuum-size",    required_argument, NULL, ARG_VACUUM_SIZE    },
                 { "vacuum-files",   required_argument, NULL, ARG_VACUUM_FILES   },
                 { "vacuum-time",    required_argument, NULL, ARG_VACUUM_TIME    },
+                { "no-hostname",    no_argument,       NULL, ARG_NO_HOSTNAME    },
                 {}
         };
 
@@ -588,9 +593,17 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_FILE:
-                        r = glob_extend(&arg_file, optarg);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to add paths: %m");
+                        if (streq(optarg, "-"))
+                                /* An undocumented feature: we can read journal files from STDIN. We don't document
+                                 * this though, since after all we only support this for mmap-able, seekable files, and
+                                 * not for example pipes which are probably the primary usecase for reading things from
+                                 * STDIN. To avoid confusion we hence don't document this feature. */
+                                arg_file_stdin = true;
+                        else {
+                                r = glob_extend(&arg_file, optarg);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to add paths: %m");
+                        }
                         break;
 
                 case ARG_ROOT:
@@ -780,6 +793,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_LIST_FIELD_NAMES;
                         break;
 
+                case ARG_NO_HOSTNAME:
+                        arg_no_hostname = true;
+                        break;
+
                 case 'x':
                         arg_catalog = true;
                         break;
@@ -856,6 +873,18 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
+        if (!strv_isempty(arg_system_units) && (arg_journal_type == SD_JOURNAL_CURRENT_USER)) {
+
+                /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
+                 * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
+                 * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
+                r = strv_extend_strv(&arg_user_units, arg_system_units, true);
+                if (r < 0)
+                        return -ENOMEM;
+
+                arg_system_units = strv_free(arg_system_units);
+        }
+
         return 1;
 }
 
@@ -980,18 +1009,18 @@ static void boot_id_free_all(BootId *l) {
         }
 }
 
-static int discover_next_boot(
-                sd_journal *j,
-                BootId **boot,
+static int discover_next_boot(sd_journal *j,
+                sd_id128_t previous_boot_id,
                 bool advance_older,
-                bool read_realtime) {
+                BootId **ret) {
 
-        int r;
-        char match[9+32+1] = "_BOOT_ID=";
         _cleanup_free_ BootId *next_boot = NULL;
+        char match[9+32+1] = "_BOOT_ID=";
+        sd_id128_t boot_id;
+        int r;
 
         assert(j);
-        assert(boot);
+        assert(ret);
 
         /* We expect the journal to be on the last position of a boot
          * (in relation to the direction we are going), so that the next
@@ -1004,29 +1033,40 @@ static int discover_next_boot(
          * we can actually advance to a *different* boot. */
         sd_journal_flush_matches(j);
 
-        if (advance_older)
-                r = sd_journal_previous(j);
-        else
-                r = sd_journal_next(j);
-        if (r < 0)
-                return r;
-        else if (r == 0)
-                return 0; /* End of journal, yay. */
+        do {
+                if (advance_older)
+                        r = sd_journal_previous(j);
+                else
+                        r = sd_journal_next(j);
+                if (r < 0)
+                        return r;
+                else if (r == 0)
+                        return 0; /* End of journal, yay. */
+
+                r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
+                if (r < 0)
+                        return r;
+
+                /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
+                 * normally, this will only require a single iteration, as we seeked to the last entry of the previous
+                 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
+                 * complete than the main entry array, and hence might reference an entry that's not actually the last
+                 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
+                 * speed things up, but let's not trust that it is complete, and hence, manually advance as
+                 * necessary. */
+
+        } while (sd_id128_equal(boot_id, previous_boot_id));
 
         next_boot = new0(BootId, 1);
         if (!next_boot)
                 return -ENOMEM;
 
-        r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id);
+        next_boot->id = boot_id;
+
+        r = sd_journal_get_realtime_usec(j, &next_boot->first);
         if (r < 0)
                 return r;
 
-        if (read_realtime) {
-                r = sd_journal_get_realtime_usec(j, &next_boot->first);
-                if (r < 0)
-                        return r;
-        }
-
         /* Now seek to the last occurrence of this boot ID. */
         sd_id128_to_string(next_boot->id, match + 9);
         r = sd_journal_add_match(j, match, sizeof(match) - 1);
@@ -1049,13 +1089,11 @@ static int discover_next_boot(
         else if (r == 0)
                 return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
 
-        if (read_realtime) {
-                r = sd_journal_get_realtime_usec(j, &next_boot->last);
-                if (r < 0)
-                        return r;
-        }
+        r = sd_journal_get_realtime_usec(j, &next_boot->last);
+        if (r < 0)
+                return r;
 
-        *boot = next_boot;
+        *ret = next_boot;
         next_boot = NULL;
 
         return 0;
@@ -1064,47 +1102,48 @@ static int discover_next_boot(
 static int get_boots(
                 sd_journal *j,
                 BootId **boots,
-                BootId *query_ref_boot,
+                sd_id128_t *query_ref_boot,
                 int ref_boot_offset) {
 
         bool skip_once;
         int r, count = 0;
         BootId *head = NULL, *tail = NULL;
         const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
+        sd_id128_t previous_boot_id;
 
         assert(j);
 
         /* Adjust for the asymmetry that offset 0 is
          * the last (and current) boot, while 1 is considered the
          * (chronological) first boot in the journal. */
-        skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0;
+        skip_once = query_ref_boot && sd_id128_is_null(*query_ref_boot) && ref_boot_offset < 0;
 
         /* Advance to the earliest/latest occurrence of our reference
          * boot ID (taking our lookup direction into account), so that
          * discover_next_boot() can do its job.
          * If no reference is given, the journal head/tail will do,
          * they're "virtual" boots after all. */
-        if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) {
+        if (query_ref_boot && !sd_id128_is_null(*query_ref_boot)) {
                 char match[9+32+1] = "_BOOT_ID=";
 
                 sd_journal_flush_matches(j);
 
-                sd_id128_to_string(query_ref_boot->id, match + 9);
+                sd_id128_to_string(*query_ref_boot, match + 9);
                 r = sd_journal_add_match(j, match, sizeof(match) - 1);
                 if (r < 0)
                         return r;
 
                 if (advance_older)
-                        r = sd_journal_seek_head(j);
+                        r = sd_journal_seek_head(j); /* seek to oldest */
                 else
-                        r = sd_journal_seek_tail(j);
+                        r = sd_journal_seek_tail(j); /* seek to newest */
                 if (r < 0)
                         return r;
 
                 if (advance_older)
-                        r = sd_journal_next(j);
+                        r = sd_journal_next(j);     /* read the oldest entry */
                 else
-                        r = sd_journal_previous(j);
+                        r = sd_journal_previous(j); /* read the most recently added entry */
                 if (r < 0)
                         return r;
                 else if (r == 0)
@@ -1113,21 +1152,31 @@ static int get_boots(
                         count = 1;
                         goto finish;
                 }
+
+                /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
+                 * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
+                 * the following entry, which must then have an older/newer boot ID */
         } else {
+
                 if (advance_older)
-                        r = sd_journal_seek_tail(j);
+                        r = sd_journal_seek_tail(j); /* seek to newest */
                 else
-                        r = sd_journal_seek_head(j);
+                        r = sd_journal_seek_head(j); /* seek to oldest */
                 if (r < 0)
                         return r;
 
-                /* No sd_journal_next/previous here. */
+                /* No sd_journal_next()/_previous() here.
+                 *
+                 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
+                 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
+                 * entry we have. */
         }
 
+        previous_boot_id = SD_ID128_NULL;
         for (;;) {
                 _cleanup_free_ BootId *current = NULL;
 
-                r = discover_next_boot(j, &current, advance_older, !query_ref_boot);
+                r = discover_next_boot(j, previous_boot_id, advance_older, &current);
                 if (r < 0) {
                         boot_id_free_all(head);
                         return r;
@@ -1136,6 +1185,8 @@ static int get_boots(
                 if (!current)
                         break;
 
+                previous_boot_id = current->id;
+
                 if (query_ref_boot) {
                         if (!skip_once)
                                 ref_boot_offset += advance_older ? 1 : -1;
@@ -1143,7 +1194,7 @@ static int get_boots(
 
                         if (ref_boot_offset == 0) {
                                 count = 1;
-                                query_ref_boot->id = current->id;
+                                *query_ref_boot = current->id;
                                 break;
                         }
                 } else {
@@ -1199,8 +1250,8 @@ static int list_boots(sd_journal *j) {
 
 static int add_boot(sd_journal *j) {
         char match[9+32+1] = "_BOOT_ID=";
+        sd_id128_t ref_boot_id;
         int r;
-        BootId ref_boot_id = {};
 
         assert(j);
 
@@ -1210,7 +1261,7 @@ static int add_boot(sd_journal *j) {
         if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
                 return add_match_this_boot(j, arg_machine);
 
-        ref_boot_id.id = arg_boot_id;
+        ref_boot_id = arg_boot_id;
         r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset);
         assert(r <= 1);
         if (r <= 0) {
@@ -1226,7 +1277,7 @@ static int add_boot(sd_journal *j) {
                 return r == 0 ? -ENODATA : r;
         }
 
-        sd_id128_to_string(ref_boot_id.id, match + 9);
+        sd_id128_to_string(ref_boot_id, match + 9);
 
         r = sd_journal_add_match(j, match, sizeof(match) - 1);
         if (r < 0)
@@ -1839,7 +1890,7 @@ static int access_check(sd_journal *j) {
                         break;
 
                 default:
-                        log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+                        log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path);
                         break;
                 }
         }
@@ -2095,11 +2146,61 @@ int main(int argc, char *argv[]) {
 
         if (arg_directory)
                 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
-        else if (arg_file)
+        else if (arg_file_stdin) {
+                int ifd = STDIN_FILENO;
+                r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
+        } else if (arg_file)
                 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
-        else if (arg_machine)
-                r = sd_journal_open_container(&j, arg_machine, 0);
-        else
+        else if (arg_machine) {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+                int fd;
+
+                if (geteuid() != 0) {
+                        /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
+                         * the container, thus we need root privileges to override them. */
+                        log_error("Using the --machine= switch requires root privileges.");
+                        r = -EPERM;
+                        goto finish;
+                }
+
+                r = sd_bus_open_system(&bus);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to open system bus: %m");
+                        goto finish;
+                }
+
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.machine1",
+                                "/org/freedesktop/machine1",
+                                "org.freedesktop.machine1.Manager",
+                                "OpenMachineRootDirectory",
+                                &error,
+                                &reply,
+                                "s", arg_machine);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
+                        goto finish;
+                }
+
+                r = sd_bus_message_read(reply, "h", &fd);
+                if (r < 0) {
+                        bus_log_parse_error(r);
+                        goto finish;
+                }
+
+                fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+                if (fd < 0) {
+                        r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
+                        goto finish;
+                }
+
+                r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
+                if (r < 0)
+                        safe_close(fd);
+        } else
                 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
         if (r < 0) {
                 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
@@ -2275,6 +2376,10 @@ int main(int argc, char *argv[]) {
         /* Opening the fd now means the first sd_journal_wait() will actually wait */
         if (arg_follow) {
                 r = sd_journal_get_fd(j);
+                if (r == -EMEDIUMTYPE) {
+                        log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.");
+                        goto finish;
+                }
                 if (r < 0) {
                         log_error_errno(r, "Failed to get journal fd: %m");
                         goto finish;
@@ -2444,7 +2549,8 @@ int main(int argc, char *argv[]) {
                                 arg_full * OUTPUT_FULL_WIDTH |
                                 colors_enabled() * OUTPUT_COLOR |
                                 arg_catalog * OUTPUT_CATALOG |
-                                arg_utc * OUTPUT_UTC;
+                                arg_utc * OUTPUT_UTC |
+                                arg_no_hostname * OUTPUT_NO_HOSTNAME;
 
                         r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
                         need_seek = true;
index c154610c542c9d70dd0c73343c01e95b20cbddc0..7fecd7a9649c356af4844d4d17fd7b72331bb14c 100644 (file)
@@ -19,7 +19,9 @@ Journal.Storage,            config_parse_storage,    0, offsetof(Server, storage
 Journal.Compress,           config_parse_bool,       0, offsetof(Server, compress)
 Journal.Seal,               config_parse_bool,       0, offsetof(Server, seal)
 Journal.SyncIntervalSec,    config_parse_sec,        0, offsetof(Server, sync_interval_usec)
+# The following is a legacy name for compatibility
 Journal.RateLimitInterval,  config_parse_sec,        0, offsetof(Server, rate_limit_interval)
+Journal.RateLimitIntervalSec,config_parse_sec,       0, offsetof(Server, rate_limit_interval)
 Journal.RateLimitBurst,     config_parse_unsigned,   0, offsetof(Server, rate_limit_burst)
 Journal.SystemMaxUse,       config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use)
 Journal.SystemMaxFileSize,  config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size)
index 3d8f05996b5280ea53bf4fae5de947a0f2d78bb4..a445291a5e397f849282500cac86d6d494c88a13 100644 (file)
@@ -206,7 +206,7 @@ void server_process_native_message(
                                            allow_object_pid(ucred)) {
                                         char buf[DECIMAL_STR_MAX(pid_t)];
                                         memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
-                                        char_array_0(buf);
+                                        buf[l-strlen("OBJECT_PID=")] = '\0';
 
                                         /* ignore error */
                                         parse_pid(buf, &object_pid);
index 2939322925f79244b0a61fa6f0d6e2b320642923..e14d0ad980a905f9ddd9bfe0e666947e15c72680 100644 (file)
@@ -253,7 +253,7 @@ static int open_journal(
         if (reliably)
                 r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
         else
-                r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
+                r = journal_file_open(-1, fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
         if (r < 0)
                 return r;
 
@@ -492,38 +492,36 @@ static void server_cache_hostname(Server *s) {
 }
 
 static bool shall_try_append_again(JournalFile *f, int r) {
-
-        /* -E2BIG            Hit configured limit
-           -EFBIG            Hit fs limit
-           -EDQUOT           Quota limit hit
-           -ENOSPC           Disk full
-           -EIO              I/O error of some kind (mmap)
-           -EHOSTDOWN        Other machine
-           -EBUSY            Unclean shutdown
-           -EPROTONOSUPPORT  Unsupported feature
-           -EBADMSG          Corrupted
-           -ENODATA          Truncated
-           -ESHUTDOWN        Already archived
-           -EIDRM            Journal file has been deleted */
-
-        if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
+        switch(r) {
+        case -E2BIG:           /* Hit configured limit          */
+        case -EFBIG:           /* Hit fs limit                  */
+        case -EDQUOT:          /* Quota limit hit               */
+        case -ENOSPC:          /* Disk full                     */
                 log_debug("%s: Allocation limit reached, rotating.", f->path);
-        else if (r == -EHOSTDOWN)
+                return true;
+        case -EIO:             /* I/O error of some kind (mmap) */
+                log_warning("%s: IO error, rotating.", f->path);
+                return true;
+        case -EHOSTDOWN:       /* Other machine                 */
                 log_info("%s: Journal file from other machine, rotating.", f->path);
-        else if (r == -EBUSY)
+                return true;
+        case -EBUSY:           /* Unclean shutdown              */
                 log_info("%s: Unclean shutdown, rotating.", f->path);
-        else if (r == -EPROTONOSUPPORT)
+                return true;
+        case -EPROTONOSUPPORT: /* Unsupported feature           */
                 log_info("%s: Unsupported feature, rotating.", f->path);
-        else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
+                return true;
+        case -EBADMSG:         /* Corrupted                     */
+        case -ENODATA:         /* Truncated                     */
+        case -ESHUTDOWN:       /* Already archived              */
                 log_warning("%s: Journal file corrupted, rotating.", f->path);
-        else if (r == -EIO)
-                log_warning("%s: IO error, rotating.", f->path);
-        else if (r == -EIDRM)
+                return true;
+        case -EIDRM:           /* Journal file has been deleted */
                 log_warning("%s: Journal file has been deleted, rotating.", f->path);
-        else
+                return true;
+        default:
                 return false;
-
-        return true;
+        }
 }
 
 static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) {
@@ -1662,7 +1660,7 @@ static int server_connect_notify(Server *s) {
           it. Specifically: given that PID 1 might block on
           dbus-daemon during IPC, and dbus-daemon is logging to us,
           and might hence block on us, we might end up in a deadlock
-          if we block on sending PID 1 notification messages -- by
+          if we block on sending PID 1 notification messages  by
           generating a full blocking circle. To avoid this, let's
           create a non-blocking socket, and connect it to the
           notification socket, and then wait for POLLOUT before we
index 7beb96c6719939f80c8f2d254a7476975411becf..2541b949be79f95a468d3a1a5df5fab282e54642 100644 (file)
@@ -17,7 +17,7 @@
 #Seal=yes
 #SplitMode=uid
 #SyncIntervalSec=5m
-#RateLimitInterval=30s
+#RateLimitIntervalSec=30s
 #RateLimitBurst=1000
 #SystemMaxUse=
 #SystemKeepFree=
index 3c21d4129e474518af3af33096a3e2fa9ab911ab..27c1dd346fdcff0211515a3ca91f5b64122d87bd 100644 (file)
@@ -1233,14 +1233,37 @@ static bool file_type_wanted(int flags, const char *filename) {
         return false;
 }
 
-static int add_any_file(sd_journal *j, const char *path) {
+static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) {
+        assert(j);
+        assert(path);
+        assert(prefix);
+
+        if (j->toplevel_fd >= 0)
+                return false;
+
+        return path_startswith(path, prefix);
+}
+
+static const char *skip_slash(const char *p) {
+
+        if (!p)
+                return NULL;
+
+        while (*p == '/')
+                p++;
+
+        return p;
+}
+
+static int add_any_file(sd_journal *j, int fd, const char *path) {
         JournalFile *f = NULL;
+        bool close_fd = false;
         int r, k;
 
         assert(j);
-        assert(path);
+        assert(fd >= 0 || path);
 
-        if (ordered_hashmap_get(j->files, path))
+        if (path && ordered_hashmap_get(j->files, path))
                 return 0;
 
         if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
@@ -1249,8 +1272,24 @@ static int add_any_file(sd_journal *j, const char *path) {
                 goto fail;
         }
 
-        r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f);
+        if (fd < 0 && j->toplevel_fd >= 0) {
+
+                /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
+                 * explicitly, since otherwise openat() ignores the first argument.) */
+
+                fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC);
+                if (fd < 0) {
+                        r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
+                        goto fail;
+                }
+
+                close_fd = true;
+        }
+
+        r = journal_file_open(fd, path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f);
         if (r < 0) {
+                if (close_fd)
+                        safe_close(fd);
                 log_debug_errno(r, "Failed to open journal file %s: %m", path);
                 goto fail;
         }
@@ -1259,10 +1298,16 @@ static int add_any_file(sd_journal *j, const char *path) {
 
         r = ordered_hashmap_put(j->files, f->path, f);
         if (r < 0) {
+                f->close_fd = close_fd;
                 (void) journal_file_close(f);
                 goto fail;
         }
 
+        if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
+                j->has_runtime_files = true;
+        else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
+                j->has_persistent_files = true;
+
         log_debug("File %s added.", f->path);
 
         check_network(j, f->fd);
@@ -1286,18 +1331,14 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
         assert(prefix);
         assert(filename);
 
-        if (j->no_new_files ||
-            !file_type_wanted(j->flags, filename))
+        if (j->no_new_files)
+                return 0;
+
+        if (!file_type_wanted(j->flags, filename))
                 return 0;
 
         path = strjoina(prefix, "/", filename);
-
-        if (!j->has_runtime_files && path_startswith(path, "/run/log/journal"))
-                j->has_runtime_files = true;
-        else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal"))
-                j->has_persistent_files = true;
-
-        return add_any_file(j, path);
+        return add_any_file(j, -1, path);
 }
 
 static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
@@ -1373,21 +1414,33 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
 
         assert(j);
         assert(prefix);
-        assert(dirname);
-
-        log_debug("Considering %s/%s.", prefix, dirname);
 
-        if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
-            !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
-            return 0;
+        /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
+         * and reenumerates directory contents */
 
-        path = strjoin(prefix, "/", dirname, NULL);
+        if (dirname)
+                path = strjoin(prefix, "/", dirname, NULL);
+        else
+                path = strdup(prefix);
         if (!path) {
                 r = -ENOMEM;
                 goto fail;
         }
 
-        d = opendir(path);
+        log_debug("Considering directory %s.", path);
+
+        /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
+        if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
+            !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
+            return 0;
+
+
+        if (j->toplevel_fd < 0)
+                d = opendir(path);
+        else
+                /* Open the specified directory relative to the the toplevel fd. Enforce that the path specified is
+                 * relative, by dropping the initial slash */
+                d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
         if (!d) {
                 r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
                 goto fail;
@@ -1419,17 +1472,18 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
                 return 0;
 
         if (m->wd <= 0 && j->inotify_fd >= 0) {
+                /* Watch this directory, if it not being watched yet. */
 
-                m->wd = inotify_add_watch(j->inotify_fd, m->path,
-                                          IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
-                                          IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
-                                          IN_ONLYDIR);
+                m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
+                                             IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
+                                             IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
+                                             IN_ONLYDIR);
 
                 if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
                         inotify_rm_watch(j->inotify_fd, m->wd);
         }
 
-        FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
+        FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
 
                 if (dirent_is_file_with_suffix(de, ".journal") ||
                     dirent_is_file_with_suffix(de, ".journal~"))
@@ -1441,7 +1495,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
         return 0;
 
 fail:
-        k = journal_put_error(j, r, path ?: dirname);
+        k = journal_put_error(j, r, path ?: prefix);
         if (k < 0)
                 return k;
 
@@ -1449,28 +1503,62 @@ fail:
 }
 
 static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
+
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
         Directory *m;
         int r, k;
 
         assert(j);
-        assert(p);
 
-        if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
-            !path_startswith(p, "/run"))
-                return -EINVAL;
+        /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
+         * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
+         * populate the set, as well as to update it later. */
 
-        if (j->prefix)
-                p = strjoina(j->prefix, p);
+        if (p) {
+                /* If there's a path specified, use it. */
 
-        d = opendir(p);
-        if (!d) {
-                if (errno == ENOENT && missing_ok)
-                        return 0;
+                if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
+                    !path_has_prefix(j, p, "/run"))
+                        return -EINVAL;
 
-                r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
-                goto fail;
+                if (j->prefix)
+                        p = strjoina(j->prefix, p);
+
+                if (j->toplevel_fd < 0)
+                        d = opendir(p);
+                else
+                        d = xopendirat(j->toplevel_fd, skip_slash(p), 0);
+
+                if (!d) {
+                        if (errno == ENOENT && missing_ok)
+                                return 0;
+
+                        r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+                        goto fail;
+                }
+        } else {
+                int dfd;
+
+                /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
+                 * opendir() will take possession of the fd, and close it, which we don't want. */
+
+                p = "."; /* store this as "." in the directories hashmap */
+
+                dfd = fcntl(j->toplevel_fd, F_DUPFD_CLOEXEC, 3);
+                if (dfd < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                d = fdopendir(dfd);
+                if (!d) {
+                        r = -errno;
+                        safe_close(dfd);
+                        goto fail;
+                }
+
+                rewinddir(d);
         }
 
         m = hashmap_get(j->directories_by_path, p);
@@ -1482,6 +1570,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
                 }
 
                 m->is_root = true;
+
                 m->path = strdup(p);
                 if (!m->path) {
                         free(m);
@@ -1505,7 +1594,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
 
         if (m->wd <= 0 && j->inotify_fd >= 0) {
 
-                m->wd = inotify_add_watch(j->inotify_fd, m->path,
+                m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
                                           IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
                                           IN_ONLYDIR);
 
@@ -1516,7 +1605,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
         if (j->no_new_files)
                 return 0;
 
-        FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
+        FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
                 sd_id128_t id;
 
                 if (dirent_is_file_with_suffix(de, ".journal") ||
@@ -1585,8 +1674,7 @@ static int add_current_paths(sd_journal *j) {
         assert(j);
         assert(j->no_new_files);
 
-        /* Simply adds all directories for files we have open as
-         * "root" directories. We don't expect errors here, so we
+        /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
          * treat them as fatal. */
 
         ORDERED_HASHMAP_FOREACH(f, j->files, i) {
@@ -1597,7 +1685,7 @@ static int add_current_paths(sd_journal *j) {
                 if (!dir)
                         return -ENOMEM;
 
-                r = add_root_directory(j, dir, true);
+                r = add_directory(j, dir, NULL);
                 if (r < 0)
                         return r;
         }
@@ -1614,13 +1702,7 @@ static int allocate_inotify(sd_journal *j) {
                         return -errno;
         }
 
-        if (!j->directories_by_wd) {
-                j->directories_by_wd = hashmap_new(NULL);
-                if (!j->directories_by_wd)
-                        return -ENOMEM;
-        }
-
-        return 0;
+        return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
 }
 
 static sd_journal *journal_new(int flags, const char *path) {
@@ -1631,6 +1713,7 @@ static sd_journal *journal_new(int flags, const char *path) {
                 return NULL;
 
         j->original_pid = getpid();
+        j->toplevel_fd = -1;
         j->inotify_fd = -1;
         j->flags = flags;
         j->data_threshold = DEFAULT_DATA_THRESHOLD;
@@ -1684,6 +1767,9 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
         char *p;
         int r;
 
+        /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
+         * combination with sd_journal_open_directory_fd(). */
+
         assert_return(machine, -EINVAL);
         assert_return(ret, -EINVAL);
         assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
@@ -1726,13 +1812,16 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
 
         assert_return(ret, -EINVAL);
         assert_return(path, -EINVAL);
-        assert_return(flags == 0, -EINVAL);
+        assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL);
 
         j = journal_new(flags, path);
         if (!j)
                 return -ENOMEM;
 
-        r = add_root_directory(j, path, false);
+        if (flags & SD_JOURNAL_OS_ROOT)
+                r = add_search_paths(j);
+        else
+                r = add_root_directory(j, path, false);
         if (r < 0)
                 goto fail;
 
@@ -1741,7 +1830,6 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
 
 fail:
         sd_journal_close(j);
-
         return r;
 }
 
@@ -1758,7 +1846,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
                 return -ENOMEM;
 
         STRV_FOREACH(path, paths) {
-                r = add_any_file(j, *path);
+                r = add_any_file(j, -1, *path);
                 if (r < 0)
                         goto fail;
         }
@@ -1770,7 +1858,96 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
 
 fail:
         sd_journal_close(j);
+        return r;
+}
+
+_public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
+        sd_journal *j;
+        struct stat st;
+        int r;
+
+        assert_return(ret, -EINVAL);
+        assert_return(fd >= 0, -EBADF);
+        assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode))
+                return -EBADFD;
+
+        j = journal_new(flags, NULL);
+        if (!j)
+                return -ENOMEM;
+
+        j->toplevel_fd = fd;
+
+        if (flags & SD_JOURNAL_OS_ROOT)
+                r = add_search_paths(j);
+        else
+                r = add_root_directory(j, NULL, false);
+        if (r < 0)
+                goto fail;
 
+        *ret = j;
+        return 0;
+
+fail:
+        sd_journal_close(j);
+        return r;
+}
+
+_public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) {
+        Iterator iterator;
+        JournalFile *f;
+        sd_journal *j;
+        unsigned i;
+        int r;
+
+        assert_return(ret, -EINVAL);
+        assert_return(n_fds > 0, -EBADF);
+        assert_return(flags == 0, -EINVAL);
+
+        j = journal_new(flags, NULL);
+        if (!j)
+                return -ENOMEM;
+
+        for (i = 0; i < n_fds; i++) {
+                struct stat st;
+
+                if (fds[i] < 0) {
+                        r = -EBADF;
+                        goto fail;
+                }
+
+                if (fstat(fds[i], &st) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                if (!S_ISREG(st.st_mode)) {
+                        r = -EBADFD;
+                        goto fail;
+                }
+
+                r = add_any_file(j, fds[i], NULL);
+                if (r < 0)
+                        goto fail;
+        }
+
+        j->no_new_files = true;
+        j->no_inotify = true;
+
+        *ret = j;
+        return 0;
+
+fail:
+        /* If we fail, make sure we don't take possession of the files we managed to make use of successfuly, and they
+         * remain open */
+        ORDERED_HASHMAP_FOREACH(f, j->files, iterator)
+                f->close_fd = false;
+
+        sd_journal_close(j);
         return r;
 }
 
@@ -2097,6 +2274,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
         assert_return(j, -EINVAL);
         assert_return(!journal_pid_changed(j), -ECHILD);
 
+        if (j->no_inotify)
+                return -EMEDIUMTYPE;
+
         if (j->inotify_fd >= 0)
                 return j->inotify_fd;
 
@@ -2104,10 +2284,14 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
         if (r < 0)
                 return r;
 
+        log_debug("Reiterating files to get inotify watches established");
+
         /* Iterate through all dirs again, to add them to the
          * inotify */
         if (j->no_new_files)
                 r = add_current_paths(j);
+        else if (j->toplevel_fd >= 0)
+                r = add_root_directory(j, NULL, false);
         else if (j->path)
                 r = add_root_directory(j, j->path, true);
         else
index 0ef6d36a507b577922e4815d2ccba27738a71da9..6f6d71435d21419d51e7a29f1ba8b18ec6a6ff4f 100644 (file)
@@ -164,7 +164,7 @@ int main(int argc, char *argv[]) {
                 arg_duration = x * USEC_PER_SEC;
         }
         if (argc == 3)
-                (void) safe_atolu(argv[2], &arg_start);
+                (void) safe_atozu(argv[2], &arg_start);
         else
                 arg_start = getpid();
 
index 93dc0e0d817bf60da2619cf72ce4a19385aa1925..ba8b20b228e8d119b4f39c91f6da15a5ae28391c 100644 (file)
@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
         assert_se(mkdtemp(dn));
         fn = strappend(dn, "/test.journal");
 
-        r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal);
+        r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal);
         assert_se(r >= 0);
 
         r = sd_journal_open(&j, 0);
index f887f43f0dd61de1f8fe67877549eca467c4bc0b..5e063f4d049f6c5fd75d35257dd3187e79331439 100644 (file)
@@ -52,7 +52,7 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil
 
 static JournalFile *test_open(const char *name) {
         JournalFile *f;
-        assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f));
+        assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f));
         return f;
 }
 
@@ -216,7 +216,7 @@ static void test_sequence_numbers(void) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
+        assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
                                     true, false, NULL, NULL, NULL, NULL, &one) == 0);
 
         append_number(one, 1, &seqnum);
@@ -233,7 +233,7 @@ static void test_sequence_numbers(void) {
 
         memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
 
-        assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
+        assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
                                     true, false, NULL, NULL, NULL, one, &two) == 0);
 
         assert_se(two->header->state == STATE_ONLINE);
@@ -264,7 +264,7 @@ static void test_sequence_numbers(void) {
         /* restart server */
         seqnum = 0;
 
-        assert_se(journal_file_open("two.journal", O_RDWR, 0,
+        assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0,
                                     true, false, NULL, NULL, NULL, NULL, &two) == 0);
 
         assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
index 839ea5a9a56b32c4c91923389c9bbffce2fc5fb2..7e5a980719149299b72cf09fb64ff3b37d3c2fa1 100644 (file)
@@ -92,9 +92,9 @@ int main(int argc, char *argv[]) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0);
-        assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0);
-        assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0);
+        assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0);
+        assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0);
+        assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0);
 
         for (i = 0; i < N_ENTRIES; i++) {
                 char *p, *q;
index 6b4643cd250553e5198e28b7129212cbf17a50cb..3d2312fc5588919e2c6292ab8ae265b9a6d47fd0 100644 (file)
@@ -55,7 +55,7 @@ static int raw_verify(const char *fn, const char *verification_key) {
         JournalFile *f;
         int r;
 
-        r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f);
+        r = journal_file_open(-1, fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f);
         if (r < 0)
                 return r;
 
@@ -88,7 +88,7 @@ int main(int argc, char *argv[]) {
 
         log_info("Generating...");
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
 
         for (n = 0; n < N_ENTRIES; n++) {
                 struct iovec iovec;
@@ -111,7 +111,7 @@ int main(int argc, char *argv[]) {
 
         log_info("Verifying...");
 
-        assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
         /* journal_file_print_header(f); */
         journal_file_dump(f);
 
index ea685af782d3445fb1f45e3595805daee2b771fb..2543d64b5bf1b1f3a1117d973fd9c600e2c45a21 100644 (file)
@@ -42,7 +42,7 @@ static void test_non_empty(void) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0);
+        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0);
 
         dual_timestamp_get(&ts);
 
@@ -131,13 +131,13 @@ static void test_empty(void) {
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
 
-        assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0);
+        assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0);
 
-        assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0);
+        assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0);
 
-        assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0);
+        assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0);
 
-        assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0);
+        assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0);
 
         journal_file_print_header(f1);
         puts("");
index 1d9ec7be827086ddb23641b7eae7c3f39b7fb022..4f7d4d8bf2ba6cc31143b9b7591dd80833f9466b 100644 (file)
@@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
         if (r < 0)
                 return r;
 
-        unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
+        unaligned_write_be16(&duid->type, DUID_TYPE_EN);
         unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
 
         *len = sizeof(duid->type) + sizeof(duid->en);
index 93f06f5938bed5d4732d067d586596345e1645f9..e6486b78f86489327c2222ab8690b59cf31a1df3 100644 (file)
 #include "sparse-endian.h"
 #include "unaligned.h"
 
+typedef enum DUIDType {
+        DUID_TYPE_RAW       = 0,
+        DUID_TYPE_LLT       = 1,
+        DUID_TYPE_EN        = 2,
+        DUID_TYPE_LL        = 3,
+        DUID_TYPE_UUID      = 4,
+        _DUID_TYPE_MAX,
+        _DUID_TYPE_INVALID  = -1,
+} DUIDType;
+
 /* RFC 3315 section 9.1:
  *      A DUID can be no more than 128 octets long (not including the type code).
  */
 #define MAX_DUID_LEN 128
 
 struct duid {
-        uint16_t type;
+        be16_t type;
         union {
                 struct {
                         /* DHCP6_DUID_LLT */
@@ -61,3 +71,34 @@ struct duid {
 
 int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
 int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
+
+static inline int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
+        struct duid d;
+
+        assert(duid_len > 0);
+
+        switch (duid_type) {
+        case DUID_TYPE_LLT:
+                if (duid_len <= sizeof(d.llt))
+                        return -EINVAL;
+                break;
+        case DUID_TYPE_EN:
+                if (duid_len != sizeof(d.en))
+                        return -EINVAL;
+                break;
+        case DUID_TYPE_LL:
+                if (duid_len <= sizeof(d.ll))
+                        return -EINVAL;
+                break;
+        case DUID_TYPE_UUID:
+                if (duid_len != sizeof(d.uuid))
+                        return -EINVAL;
+                break;
+        default:
+                if (duid_len > sizeof(d.raw))
+                        return -EINVAL;
+                /* accept unknown type in order to be forward compatible */
+                break;
+        }
+        return 0;
+}
index ee4bdfb07ff4e1fdcbc8d4302dbf743d57af5350..2487c470ab7123b62a4ed25e77a196ff224f8620 100644 (file)
@@ -62,13 +62,6 @@ enum {
 #define DHCP6_REB_TIMEOUT                       10 * USEC_PER_SEC
 #define DHCP6_REB_MAX_RT                        600 * USEC_PER_SEC
 
-enum {
-        DHCP6_DUID_LLT                          = 1,
-        DHCP6_DUID_EN                           = 2,
-        DHCP6_DUID_LL                           = 3,
-        DHCP6_DUID_UUID                         = 4,
-};
-
 enum DHCP6State {
         DHCP6_STATE_STOPPED                     = 0,
         DHCP6_STATE_INFORMATION_REQUEST         = 1,
index cb7252bbeb90657252151151cf168c2992cf8937..99b3a1d01f07be21caf0a1ddd580a64d8dd8dd6b 100644 (file)
@@ -335,6 +335,36 @@ int config_parse_hwaddr(const char *unit,
         return 0;
 }
 
+int config_parse_iaid(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) {
+        uint32_t iaid;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou32(rvalue, &iaid);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Unable to read IAID, ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        *((uint32_t *)data) = iaid;
+
+        return 0;
+}
+
 void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
         unsigned i;
 
index c8a531ab0f7ff7a331d1c938ffbccfda3af169d2..72432774d79b9b9d78519c6aaf785ae4c1b5a1de 100644 (file)
@@ -62,6 +62,10 @@ int config_parse_ifalias(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_iaid(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 net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
 const char *net_get_name(struct udev_device *device);
 
index 1188b31500ae15d460c89b118e50383584d29153..287b6e26fabd93df53345b25c9d23b4281730f90 100644 (file)
@@ -82,7 +82,7 @@ struct sd_dhcp_client {
                         } _packed_ ll;
                         struct {
                                 /* 255: Node-specific (RFC 4361) */
-                                uint32_t iaid;
+                                be32_t iaid;
                                 struct duid duid;
                         } _packed_ ns;
                         struct {
@@ -298,6 +298,52 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
         return 0;
 }
 
+int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
+                                 uint16_t duid_type, uint8_t *duid, size_t duid_len) {
+        DHCP_CLIENT_DONT_DESTROY(client);
+        int r;
+        assert_return(client, -EINVAL);
+        zero(client->client_id);
+
+        client->client_id.type = 255;
+
+        /* If IAID is not configured, generate it. */
+        if (iaid == 0) {
+                r = dhcp_identifier_set_iaid(client->index, client->mac_addr,
+                                             client->mac_addr_len,
+                                             &client->client_id.ns.iaid);
+                if (r < 0)
+                        return r;
+        } else
+                client->client_id.ns.iaid = htobe32(iaid);
+
+        /* If DUID is not configured, generate DUID-EN. */
+        if (duid_len == 0) {
+                r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid,
+                                                &duid_len);
+                if (r < 0)
+                        return r;
+        } else {
+                r = dhcp_validate_duid_len(client->client_id.type, duid_len);
+                if (r < 0)
+                        return r;
+                client->client_id.ns.duid.type = htobe16(duid_type);
+                memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
+                duid_len += sizeof(client->client_id.ns.duid.type);
+        }
+
+        client->client_id_len = sizeof(client->client_id.type) + duid_len +
+                                sizeof(client->client_id.ns.iaid);
+
+        if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
+                log_dhcp_client(client, "Configured IAID+DUID, restarting.");
+                client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
+                sd_dhcp_client_start(client);
+        }
+
+        return 0;
+}
+
 int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
                                 const char *hostname) {
         char *new_hostname = NULL;
index af4709d788a6e1114d047530a5bc7d504eacbe31..ee4fb4fc1edba409fde6528709e4c51380e26ee4 100644 (file)
@@ -180,41 +180,29 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
         return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
 }
 
-int sd_dhcp6_client_set_duid(
-                sd_dhcp6_client *client,
-                uint16_t type,
-                uint8_t *duid, size_t duid_len) {
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type,
+                             uint8_t *duid, size_t duid_len) {
+        int r;
         assert_return(client, -EINVAL);
-        assert_return(duid, -EINVAL);
-        assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
-
         assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
 
-        switch (type) {
-        case DHCP6_DUID_LLT:
-                if (duid_len <= sizeof(client->duid.llt))
-                        return -EINVAL;
-                break;
-        case DHCP6_DUID_EN:
-                if (duid_len != sizeof(client->duid.en))
-                        return -EINVAL;
-                break;
-        case DHCP6_DUID_LL:
-                if (duid_len <= sizeof(client->duid.ll))
-                        return -EINVAL;
-                break;
-        case DHCP6_DUID_UUID:
-                if (duid_len != sizeof(client->duid.uuid))
-                        return -EINVAL;
-                break;
-        default:
-                /* accept unknown type in order to be forward compatible */
-                break;
+        if (duid_len > 0) {
+                r = dhcp_validate_duid_len(duid_type, duid_len);
+                if (r < 0)
+                        return r;
+                client->duid.type = htobe16(duid_type);
+                memcpy(&client->duid.raw.data, duid, duid_len);
+                client->duid_len = duid_len + sizeof(client->duid.type);
         }
 
-        client->duid.type = htobe16(type);
-        memcpy(&client->duid.raw.data, duid, duid_len);
-        client->duid_len = duid_len + sizeof(client->duid.type);
+        return 0;
+}
+
+int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
+        assert_return(client, -EINVAL);
+        assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+        client->ia_na.id = htobe32(iaid);
 
         return 0;
 }
index 4ab637b686c52d9f4562637cc866723252407fe5..0b3a1708dc69a461e9d73617b4a6976fe2f18054 100644 (file)
@@ -489,3 +489,9 @@ global:
         sd_journal_enumerate_fields;
         sd_journal_restart_fields;
 } LIBSYSTEMD_227;
+
+LIBSYSTEMD_230 {
+global:
+        sd_journal_open_directory_fd;
+        sd_journal_open_files_fd;
+} LIBSYSTEMD_229;
index 6370061dafcc514e60d63480dc945edf281b9fca..02e3bf904c8623b1853990ac7761415eb29c4491 100644 (file)
@@ -38,6 +38,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,  EDEADLK),
         SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,   EDEADLK),
         SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED,                  ESHUTDOWN),
+        SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED,               EADDRNOTAVAIL),
+        SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_LINKED,                  ELOOP),
         SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,      EBADR),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION,                 EPERM),
         SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN,                ECANCELED),
index 464834979a3e2918953893891f8299d6714cf532..c8f369cb78b6b73c8560e3bfc666dada47b6c91d 100644 (file)
@@ -34,6 +34,8 @@
 #define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
 #define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
 #define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked"
+#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated"
+#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked"
 #define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
 #define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
 #define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
index e860876c12129ee76b1c1a2185a1ecdf77714c89..52128e7b5ce321939855f7e547bef6f5321d6fae 100644 (file)
@@ -678,6 +678,7 @@ int bus_get_name_creds_kdbus(
             (mask & (SD_BUS_CREDS_PPID|
                      SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
                      SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+                     SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
                      SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
                      SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
                      SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -795,6 +796,7 @@ static int bus_get_name_creds_dbus1(
                     ((mask & SD_BUS_CREDS_AUGMENT) &&
                      (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
                               SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+                              SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
                               SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
                               SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
                               SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -947,6 +949,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
             (mask & (SD_BUS_CREDS_PPID|
                      SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
                      SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+                     SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
                      SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
                      SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
                      SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
index 862f26aad758c8cfd6cf5179123c8994aaba2247..04da94e7e3a9a695f5d94a4ff09df5a93e69630e 100644 (file)
@@ -1778,7 +1778,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
 
                 r = bus_write_message(bus, m, hint_sync_call, &idx);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -2083,7 +2083,7 @@ _public_ int sd_bus_call(
 
                 r = bus_read_message(bus, false, 0);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2116,7 +2116,7 @@ _public_ int sd_bus_call(
 
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2766,7 +2766,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 
         case BUS_OPENING:
                 r = bus_socket_process_opening(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2777,7 +2777,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
 
         case BUS_AUTHENTICATING:
                 r = bus_socket_process_authenticating(bus);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
                 } else if (r < 0)
@@ -2791,7 +2791,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
         case BUS_RUNNING:
         case BUS_HELLO:
                 r = process_running(bus, hint_priority, priority, ret);
-                if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                         bus_enter_closing(bus);
                         r = 1;
 
@@ -2914,7 +2914,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         for (;;) {
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
index 8657e61cd9ee9f97047a90538ee396b65bf17f4f..b1c3d5f228895605f540eb27acc767da1e490523 100644 (file)
@@ -1212,19 +1212,19 @@ int device_get_id_filename(sd_device *device, const char **ret) {
                 if (major(devnum) > 0) {
                         assert(subsystem);
 
-                        /* use dev_t -- b259:131072, c254:0 */
+                        /* use dev_t  b259:131072, c254:0 */
                         r = asprintf(&id, "%c%u:%u",
                                      streq(subsystem, "block") ? 'b' : 'c',
                                      major(devnum), minor(devnum));
                         if (r < 0)
                                 return -ENOMEM;
                 } else if (ifindex > 0) {
-                        /* use netdev ifindex -- n3 */
+                        /* use netdev ifindex  n3 */
                         r = asprintf(&id, "n%u", ifindex);
                         if (r < 0)
                                 return -ENOMEM;
                 } else {
-                        /* use $subsys:$sysname -- pci:0000:00:1f.2
+                        /* use $subsys:$sysname  pci:0000:00:1f.2
                          * sysname() has '!' translated, get it from devpath
                          */
                         const char *sysname;
@@ -1457,15 +1457,20 @@ static int device_properties_prepare(sd_device *device) {
                 return r;
 
         if (device->property_devlinks_outdated) {
-                char *devlinks = NULL;
+                _cleanup_free_ char *devlinks = NULL;
+                size_t devlinks_allocated = 0, devlinks_len = 0;
                 const char *devlink;
 
-                devlink = sd_device_get_devlink_first(device);
-                if (devlink)
-                        devlinks = strdupa(devlink);
+                for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
+                        char *e;
 
-                while ((devlink = sd_device_get_devlink_next(device)))
-                        devlinks = strjoina(devlinks, " ", devlink);
+                        if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
+                                return -ENOMEM;
+                        if (devlinks_len > 0)
+                                stpcpy(devlinks + devlinks_len++, " ");
+                        e = stpcpy(devlinks + devlinks_len, devlink);
+                        devlinks_len = e - devlinks;
+                }
 
                 r = device_add_property_internal(device, "DEVLINKS", devlinks);
                 if (r < 0)
@@ -1475,17 +1480,23 @@ static int device_properties_prepare(sd_device *device) {
         }
 
         if (device->property_tags_outdated) {
-                char *tags = NULL;
+                _cleanup_free_ char *tags = NULL;
+                size_t tags_allocated = 0, tags_len = 0;
                 const char *tag;
 
-                tag = sd_device_get_tag_first(device);
-                if (tag)
-                        tags = strjoina(":", tag);
+                if (!GREEDY_REALLOC(tags, tags_allocated, 2))
+                        return -ENOMEM;
+                stpcpy(tags, ":");
+                tags_len++;
 
-                while ((tag = sd_device_get_tag_next(device)))
-                        tags = strjoina(tags, ":", tag);
+                for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
+                        char *e;
 
-                tags = strjoina(tags, ":");
+                        if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
+                                return -ENOMEM;
+                        e = stpcpy(stpcpy(tags + tags_len, tag), ":");
+                        tags_len = e - tags;
+                }
 
                 r = device_add_property_internal(device, "TAGS", tags);
                 if (r < 0)
index 841358ed03c73a9a0cb32136b5a0bfe1baeeffa7..7ba6527f63164dbdfafcf81c5e61c865eb73db90 100644 (file)
@@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time(
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
+        if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) &&
+            !clock_boottime_supported())
+                return -EOPNOTSUPP;
+
         if (!callback)
                 callback = time_exit_callback;
 
@@ -1145,8 +1149,7 @@ _public_ int sd_event_add_signal(
         int r;
 
         assert_return(e, -EINVAL);
-        assert_return(sig > 0, -EINVAL);
-        assert_return(sig < _NSIG, -EINVAL);
+        assert_return(SIGNAL_VALID(sig), -EINVAL);
         assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
         assert_return(!event_pid_changed(e), -ECHILD);
 
@@ -2200,7 +2203,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
                 if (_unlikely_(n != sizeof(si)))
                         return -EIO;
 
-                assert(si.ssi_signo < _NSIG);
+                assert(SIGNAL_VALID(si.ssi_signo));
 
                 read_one = true;
 
@@ -2528,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
         }
 
         dual_timestamp_get(&e->timestamp);
-        e->timestamp_boottime = now(CLOCK_BOOTTIME);
+        if (clock_boottime_supported())
+                e->timestamp_boottime = now(CLOCK_BOOTTIME);
 
         for (i = 0; i < m; i++) {
 
@@ -2762,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
                              CLOCK_BOOTTIME,
                              CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP);
 
+        if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported())
+                return -EOPNOTSUPP;
+
         if (!dual_timestamp_is_set(&e->timestamp)) {
                 /* Implicitly fall back to now() if we never ran
                  * before and thus have no cached time. */
index fd31588b8f2ba1d47144ba07ef8453b63ad835b7..289114490ccf6d1765b70c7cdfbdb0e70f8f05de 100644 (file)
@@ -270,8 +270,10 @@ static void test_sd_event_now(void) {
         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
         assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
         assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0);
-        assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
-        assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
+        if (clock_boottime_supported()) {
+                assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
+                assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
+        }
         assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
         assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
 
@@ -280,8 +282,10 @@ static void test_sd_event_now(void) {
         assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
         assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0);
         assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0);
-        assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
-        assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
+        if (clock_boottime_supported()) {
+                assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
+                assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
+        }
         assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
         assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
 }
index 6abd8fd0cc0fd70b904d582e763e5f0240b4febc..ed9ee041ab47fd46a8431c3de80306b786ead0a4 100644 (file)
@@ -155,8 +155,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
                 n_list++;
         };
 
-        if (n_list > 0)
-                qsort(list, n_list, sizeof(struct local_address), address_compare);
+        qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
 
         *ret = list;
         list = NULL;
index a5758bb516842c00f1d69ea4c59031c6ea0cfe16..3a4bac2cedbade2ab34195825bebefa8788a3579 100644 (file)
@@ -95,12 +95,43 @@ static const NLType rtnl_link_info_data_macvlan_types[] = {
 };
 
 static const NLType rtnl_link_info_data_bridge_types[] = {
-        [IFLA_BR_FORWARD_DELAY]  = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BR_HELLO_TIME]     = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BR_MAX_AGE]        = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BR_AGEING_TIME]    = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BR_STP_STATE]      = { .type = NETLINK_TYPE_U32 },
-        [IFLA_BR_PRIORITY]       = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_FORWARD_DELAY]              = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_HELLO_TIME]                 = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_MAX_AGE]                    = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_AGEING_TIME]                = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_STP_STATE]                  = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_PRIORITY]                   = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_VLAN_FILTERING]             = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_VLAN_PROTOCOL]              = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_GROUP_FWD_MASK]             = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_ROOT_PORT]                  = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_ROOT_PATH_COST]             = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_TOPOLOGY_CHANGE]            = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_TOPOLOGY_CHANGE_DETECTED]   = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_HELLO_TIMER]                = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_TCN_TIMER]                  = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_TOPOLOGY_CHANGE_TIMER]      = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_GC_TIMER]                   = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_GROUP_ADDR]                 = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_FDB_FLUSH]                  = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_MCAST_ROUTER]               = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_MCAST_SNOOPING]             = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_MCAST_QUERY_USE_IFADDR]     = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_MCAST_QUERIER]              = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_MCAST_HASH_ELASTICITY]      = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_MCAST_HASH_MAX]             = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_MCAST_LAST_MEMBER_CNT]      = { .type = NETLINK_TYPE_U32 },
+        [IFLA_BR_MCAST_STARTUP_QUERY_CNT]    = { .type = NETLINK_TYPE_U16 },
+        [IFLA_BR_MCAST_LAST_MEMBER_INTVL]    = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_MCAST_MEMBERSHIP_INTVL]     = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_MCAST_QUERIER_INTVL]        = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_MCAST_QUERY_INTVL]          = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_MCAST_STARTUP_QUERY_INTVL]  = { .type = NETLINK_TYPE_U64 },
+        [IFLA_BR_NF_CALL_IPTABLES]           = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_NF_CALL_IP6TABLES]          = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_NF_CALL_ARPTABLES]          = { .type = NETLINK_TYPE_U8 },
+        [IFLA_BR_VLAN_DEFAULT_PVID]          = { .type = NETLINK_TYPE_U16 },
 };
 
 static const NLType rtnl_link_info_data_vlan_types[] = {
index 255526bf32d1bddd5558938ff722d7021fa8b8b3..f251536a891b2d064b9fff29810166f0f0863fa6 100644 (file)
@@ -402,7 +402,6 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
         int r;
 
         assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
-        assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
         assert_return(ret, -EINVAL);
 
         r = message_new(rtnl, ret, nlmsg_type);
index 37585048b818c32da552304a25cb08a2804180d7..d8303e2e69353dc97a44703d99ac95c06dbcd79f 100644 (file)
@@ -579,9 +579,10 @@ static void resolve_free(sd_resolve *resolve) {
                         (void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
         }
 
-        /* Now terminate them and wait until they are gone. */
+        /* Now terminate them and wait until they are gone.
+           If we get an error than most likely the thread already exited. */
         for (i = 0; i < resolve->n_valid_workers; i++)
-                pthread_join(resolve->workers[i], NULL);
+                (void) pthread_join(resolve->workers[i], NULL);
 
         /* Close all communication channels */
         for (i = 0; i < _FD_MAX; i++)
index 33ef6fc0f7469c34863f964bdcf7ac042b240744..1be1a7f8a72de400de3b29ac814e781a45357dd3 100644 (file)
@@ -63,7 +63,7 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c
                 return 0;
         }
 
-        printf("Host: %s -- Serv: %s\n", strna(host), strna(serv));
+        printf("Host: %s  Serv: %s\n", strna(host), strna(serv));
         return 0;
 }
 
index 6aadda091a05575a6d3cd8d74fb483137fcf0ed2..d0b02a6b98f8ccd4f865c151456d57b9975cb62d 100644 (file)
@@ -3,6 +3,10 @@ en_AU en_AU:en_GB
 en_IE en_IE:en_GB
 en_NZ en_NZ:en_GB
 en_ZA en_ZA:en_GB
+fr_BE fr_BE:fr_FR
+fr_CA fr_CA:fr_FR
+fr_CH fr_CH:fr_FR
+fr_LU fr_LU:fr_FR
 it_CH it_CH:it_IT
 mai_IN mai:hi
 nds_DE nds:de
index 46405ca68a11486fb01312415db5d4e2e1cbd985..3b22a582ac9cd7f5e1cdc9264fb50be29a267857 100644 (file)
@@ -24,6 +24,7 @@
 
 #ifdef HAVE_XKBCOMMON
 #include <xkbcommon/xkbcommon.h>
+#include <dlfcn.h>
 #endif
 
 #include "sd-bus.h"
@@ -1101,6 +1102,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
 }
 
 #ifdef HAVE_XKBCOMMON
+
 _printf_(3, 0)
 static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
         const char *fmt;
@@ -1109,7 +1111,24 @@ static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char
         log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
 }
 
+#define LOAD_SYMBOL(symbol, dl, name)                                   \
+        ({                                                              \
+                (symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
+                (symbol) ? 0 : -EOPNOTSUPP;                             \
+        })
+
 static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+
+        /* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
+         * after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
+         * pointers to the shared library are below: */
+
+        struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL;
+        void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL;
+        void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL;
+        struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL;
+        void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL;
+
         const struct xkb_rule_names rmlvo = {
                 .model          = model,
                 .layout         = layout,
@@ -1118,35 +1137,68 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
         };
         struct xkb_context *ctx = NULL;
         struct xkb_keymap *km = NULL;
+        void *dl;
         int r;
 
-        /* compile keymap from RMLVO information to check out its validity */
+        /* Compile keymap from RMLVO information to check out its validity */
+
+        dl = dlopen("libxkbcommon.so.0", RTLD_LAZY);
+        if (!dl)
+                return -EOPNOTSUPP;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn");
+        if (r < 0)
+                goto finish;
 
-        ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+        r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names");
+        if (r < 0)
+                goto finish;
+
+        r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref");
+        if (r < 0)
+                goto finish;
+
+        ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
         if (!ctx) {
                 r = -ENOMEM;
-                goto exit;
+                goto finish;
         }
 
-        xkb_context_set_log_fn(ctx, log_xkb);
+        symbol_xkb_context_set_log_fn(ctx, log_xkb);
 
-        km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
+        km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
         if (!km) {
                 r = -EINVAL;
-                goto exit;
+                goto finish;
         }
 
         r = 0;
 
-exit:
-        xkb_keymap_unref(km);
-        xkb_context_unref(ctx);
+finish:
+        if (symbol_xkb_keymap_unref && km)
+                symbol_xkb_keymap_unref(km);
+
+        if (symbol_xkb_context_unref && ctx)
+                symbol_xkb_context_unref(ctx);
+
+        (void) dlclose(dl);
         return r;
 }
+
 #else
+
 static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
         return 0;
 }
+
 #endif
 
 static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
@@ -1203,7 +1255,11 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
                 if (r < 0) {
                         log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
                                         strempty(model), strempty(layout), strempty(variant), strempty(options));
-                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
+
+                        if (r == -EOPNOTSUPP)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
+
+                        return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
                 }
 
                 if (free_and_strdup(&c->x11_layout, layout) < 0 ||
index 39088ec25217c5795c6cedc62e492b5d6ae66682..3a8ba497c1e9016ddd0fbdd0d46beeb5892b26f6 100644 (file)
@@ -1,4 +1,5 @@
 /logind-gperf.c
+/logind.conf
 /org.freedesktop.login1.policy
 /71-seat.rules
 /73-seat-late.rules
index c9a5cd796b22b2d27609d62d2c447b5acdb10d2b..1c755656368a9a31054e837f3ed3ddbe9b8ac4b1 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "alloc-util.h"
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
@@ -48,6 +49,7 @@
 
 static char **arg_property = NULL;
 static bool arg_all = false;
+static bool arg_value = false;
 static bool arg_full = false;
 static bool arg_no_pager = false;
 static bool arg_legend = true;
@@ -226,18 +228,15 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ char *path = NULL;
         const char *cgroup;
-        int r;
         unsigned c;
+        int r;
 
         assert(bus);
         assert(unit);
 
-        if (arg_transport != BUS_TRANSPORT_LOCAL)
-                return 0;
-
         path = unit_dbus_path_from_name(unit);
         if (!path)
-                return -ENOMEM;
+                return log_oom();
 
         r = sd_bus_get_property(
                         bus,
@@ -245,27 +244,40 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
                         path,
                         interface,
                         "ControlGroup",
-                        &error, &reply, "s");
+                        &error,
+                        &reply,
+                        "s");
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_read(reply, "s", &cgroup);
         if (r < 0)
-                return r;
+                return bus_log_parse_error(r);
 
         if (isempty(cgroup))
                 return 0;
 
-        if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
-                return 0;
-
         c = columns();
         if (c > 18)
                 c -= 18;
         else
                 c = 0;
 
-        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, get_output_flags());
+        r = unit_show_processes(bus, unit, cgroup, "\t\t  ", c, get_output_flags(), &error);
+        if (r == -EBADR) {
+
+                if (arg_transport == BUS_TRANSPORT_REMOTE)
+                        return 0;
+
+                /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
+
+                if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+                        return 0;
+
+                show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, &leader, leader > 0, get_output_flags());
+        } else if (r < 0)
+                return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
+
         return 0;
 }
 
@@ -292,6 +304,7 @@ typedef struct SessionStatusInfo {
 
 typedef struct UserStatusInfo {
         uid_t uid;
+        bool linger;
         char *name;
         struct dual_timestamp timestamp;
         char *state;
@@ -550,6 +563,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
 
         static const struct bus_properties_map map[]  = {
                 { "Name",               "s",     NULL,                     offsetof(UserStatusInfo, name)                },
+                { "Linger",             "b",     NULL,                     offsetof(UserStatusInfo, linger)              },
                 { "Slice",              "s",     NULL,                     offsetof(UserStatusInfo, slice)               },
                 { "State",              "s",     NULL,                     offsetof(UserStatusInfo, state)               },
                 { "UID",                "u",     NULL,                     offsetof(UserStatusInfo, uid)                 },
@@ -594,16 +608,16 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
                 char **l;
                 printf("\tSessions:");
 
-                STRV_FOREACH(l, i.sessions) {
-                        if (streq_ptr(*l, i.display))
-                                printf(" *%s", *l);
-                        else
-                                printf(" %s", *l);
-                }
+                STRV_FOREACH(l, i.sessions)
+                        printf(" %s%s",
+                               streq_ptr(*l, i.display) ? "*" : "",
+                               *l);
 
                 printf("\n");
         }
 
+        printf("\t  Linger: %s\n", yes_no(i.linger));
+
         if (i.slice) {
                 printf("\t    Unit: %s\n", i.slice);
                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
@@ -679,6 +693,14 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
         return 0;
 }
 
+#define property(name, fmt, ...)                                        \
+        do {                                                            \
+                if (arg_value)                                          \
+                        printf(fmt "\n", __VA_ARGS__);                  \
+                else                                                    \
+                        printf("%s=" fmt "\n", name, __VA_ARGS__);      \
+        } while(0)
+
 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
         int r;
 
@@ -702,7 +724,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         if (arg_all || !isempty(s))
-                                printf("%s=%s\n", name, s);
+                                property(name, "%s", s);
 
                         return 0;
 
@@ -718,8 +740,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return -EINVAL;
                         }
 
-                        printf("%s=" UID_FMT "\n", name, uid);
-
+                        property(name, UID_FMT, uid);
                         return 0;
                 }
 
@@ -735,14 +756,16 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        printf("%s=", name);
+                        if (!arg_value)
+                                printf("%s=", name);
 
                         while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
                                 printf("%s%s", space ? " " : "", s);
                                 space = true;
                         }
 
-                        printf("\n");
+                        if (space || !arg_value)
+                                printf("\n");
 
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -757,7 +780,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                 break;
         }
 
-        r = bus_print_property(name, m, arg_all);
+        r = bus_print_property(name, m, arg_value, arg_all);
         if (r < 0)
                 return bus_log_parse_error(r);
 
@@ -1330,6 +1353,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -M --machine=CONTAINER   Operate on local container\n"
                "  -p --property=NAME       Show only properties by this name\n"
                "  -a --all                 Show all properties, including empty ones\n"
+               "     --value               When showing properties, only print the value\n"
                "  -l --full                Do not ellipsize output\n"
                "     --kill-who=WHO        Who to send signal to\n"
                "  -s --signal=SIGNAL       Which signal to send\n"
@@ -1371,6 +1395,7 @@ static int parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_VERSION = 0x100,
+                ARG_VALUE,
                 ARG_NO_PAGER,
                 ARG_NO_LEGEND,
                 ARG_KILL_WHO,
@@ -1382,6 +1407,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",         no_argument,       NULL, ARG_VERSION         },
                 { "property",        required_argument, NULL, 'p'                 },
                 { "all",             no_argument,       NULL, 'a'                 },
+                { "value",           no_argument,       NULL, ARG_VALUE           },
                 { "full",            no_argument,       NULL, 'l'                 },
                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
@@ -1427,6 +1453,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_all = true;
                         break;
 
+                case ARG_VALUE:
+                        arg_value = true;
+                        break;
+
                 case 'l':
                         arg_full = true;
                         break;
index 8bdb3a9a38322f3aa33a5db87126a79478d45b12..cbf8d757fee4230bd0a89d8460ebcf755f1a99b0 100644 (file)
@@ -364,16 +364,16 @@ bool manager_shall_kill(Manager *m, const char *user) {
         assert(m);
         assert(user);
 
-        if (!m->kill_user_processes)
+        if (!m->kill_exclude_users && streq(user, "root"))
                 return false;
 
         if (strv_contains(m->kill_exclude_users, user))
                 return false;
 
-        if (strv_isempty(m->kill_only_users))
-                return true;
+        if (!strv_isempty(m->kill_only_users))
+                return strv_contains(m->kill_only_users, user);
 
-        return strv_contains(m->kill_only_users, user);
+        return m->kill_user_processes;
 }
 
 static int vt_is_busy(unsigned int vtnr) {
index 1d3133ee252338ca913ec711f1c04e9e87061b08..a281f99a343199c3526d945d69e79a65b5158e3a 100644 (file)
@@ -1077,11 +1077,11 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus
 static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *cc = NULL;
         Manager *m = userdata;
-        int b, r;
+        int r, b, interactive;
         struct passwd *pw;
         const char *path;
         uint32_t uid;
-        int interactive;
+        bool self = false;
 
         assert(message);
         assert(m);
@@ -1102,6 +1102,8 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
                 if (r < 0)
                         return r;
 
+                self = true;
+
         } else if (!uid_is_valid(uid))
                 return -EINVAL;
 
@@ -1113,7 +1115,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
         r = bus_verify_polkit_async(
                         message,
                         CAP_SYS_ADMIN,
-                        "org.freedesktop.login1.set-user-linger",
+                        self ? "org.freedesktop.login1.set-self-linger" : "org.freedesktop.login1.set-user-linger",
                         NULL,
                         interactive,
                         UID_INVALID,
index ff9170683bafd49b3dbbe0a49e3c15ebfe32e778..0f8862c0d9ca1543bf84f674754731a8bab9147f 100644 (file)
@@ -28,6 +28,7 @@
 #include "logind-session-device.h"
 #include "logind-session.h"
 #include "logind.h"
+#include "signal-util.h"
 #include "strv.h"
 #include "util.h"
 
@@ -300,7 +301,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
         }
 
-        if (signo <= 0 || signo >= _NSIG)
+        if (!SIGNAL_VALID(signo))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
 
         r = bus_verify_polkit_async(
index e088225bebbaf722a76a37dcc0fb660f73d1e346..a8b1d5943dbbd9084b807fadd1f90d377fdf10fa 100644 (file)
@@ -513,7 +513,7 @@ static int session_start_scope(Session *s) {
                 if (!scope)
                         return log_oom();
 
-                description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
+                description = strjoina("Session ", s->id, " of user ", s->user->name);
 
                 r = manager_start_scope(
                                 s->manager,
@@ -797,7 +797,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
 
         /* Graphical sessions should really implement a real
          * idle hint logic */
-        if (s->display)
+        if (SESSION_TYPE_IS_GRAPHICAL(s->type))
                 goto dont_know;
 
         /* For sessions with an explicitly configured tty, let's check
index fd98c7becafb800daeb3f7ada0f8d8e06484a8ea..b73f9ea69e8c30d8f94108fdd23f3431ce5c9b70 100644 (file)
@@ -25,6 +25,7 @@
 #include "formats-util.h"
 #include "logind-user.h"
 #include "logind.h"
+#include "signal-util.h"
 #include "strv.h"
 #include "user-util.h"
 
@@ -222,7 +223,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
         if (r < 0)
                 return r;
 
-        if (signo <= 0 || signo >= _NSIG)
+        if (!SIGNAL_VALID(signo))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
 
         r = user_kill(u, signo);
index d5f6757bd3c017aec37d0effd3e4f3490a48ec34..a48e2fc61ec3d9a9eac57e8250ec1d350ba45ad0 100644 (file)
 
 static void manager_free(Manager *m);
 
-static Manager *manager_new(void) {
-        Manager *m;
-        int r;
-
-        m = new0(Manager, 1);
-        if (!m)
-                return NULL;
-
-        m->console_active_fd = -1;
-        m->reserve_vt_fd = -1;
-
+static void manager_reset_config(Manager *m) {
         m->n_autovts = 6;
         m->reserve_vt = 6;
         m->remove_ipc = true;
@@ -61,16 +51,38 @@ static Manager *manager_new(void) {
         m->handle_hibernate_key = HANDLE_HIBERNATE;
         m->handle_lid_switch = HANDLE_SUSPEND;
         m->handle_lid_switch_docked = HANDLE_IGNORE;
+        m->power_key_ignore_inhibited = false;
+        m->suspend_key_ignore_inhibited = false;
+        m->hibernate_key_ignore_inhibited = false;
         m->lid_switch_ignore_inhibited = true;
+
         m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
 
         m->idle_action_usec = 30 * USEC_PER_MINUTE;
         m->idle_action = HANDLE_IGNORE;
-        m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
 
         m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
         m->user_tasks_max = UINT64_C(12288);
 
+        m->kill_user_processes = KILL_USER_PROCESSES;
+
+        m->kill_only_users = strv_free(m->kill_only_users);
+        m->kill_exclude_users = strv_free(m->kill_exclude_users);
+}
+
+static Manager *manager_new(void) {
+        Manager *m;
+        int r;
+
+        m = new0(Manager, 1);
+        if (!m)
+                return NULL;
+
+        m->console_active_fd = -1;
+        m->reserve_vt_fd = -1;
+
+        m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
+
         m->devices = hashmap_new(&string_hash_ops);
         m->seats = hashmap_new(&string_hash_ops);
         m->sessions = hashmap_new(&string_hash_ops);
@@ -84,10 +96,6 @@ static Manager *manager_new(void) {
         if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
                 goto fail;
 
-        m->kill_exclude_users = strv_new("root", NULL);
-        if (!m->kill_exclude_users)
-                goto fail;
-
         m->udev = udev_new();
         if (!m->udev)
                 goto fail;
@@ -98,6 +106,8 @@ static Manager *manager_new(void) {
 
         sd_event_set_watchdog(m->event, true);
 
+        manager_reset_config(m);
+
         return m;
 
 fail:
@@ -986,6 +996,30 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
         return 0;
 }
 
+static int manager_parse_config_file(Manager *m) {
+        assert(m);
+
+        return config_parse_many(PKGSYSCONFDIR "/logind.conf",
+                                 CONF_PATHS_NULSTR("systemd/logind.conf.d"),
+                                 "Login\0",
+                                 config_item_perf_lookup, logind_gperf_lookup,
+                                 false, m);
+}
+
+static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        Manager *m = userdata;
+        int r;
+
+        manager_reset_config(m);
+        r = manager_parse_config_file(m);
+        if (r < 0)
+                log_warning_errno(r, "Failed to parse config file, using defaults: %m");
+        else
+                log_info("Config file reloaded.");
+
+        return 0;
+}
+
 static int manager_startup(Manager *m) {
         int r;
         Seat *seat;
@@ -997,6 +1031,12 @@ static int manager_startup(Manager *m) {
 
         assert(m);
 
+        assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGHUP, -1) >= 0);
+
+        r = sd_event_add_signal(m->event, NULL, SIGHUP, manager_dispatch_reload_signal, m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to register SIGHUP handler: %m");
+
         /* Connect to console */
         r = manager_connect_console(m);
         if (r < 0)
@@ -1099,16 +1139,6 @@ static int manager_run(Manager *m) {
         }
 }
 
-static int manager_parse_config_file(Manager *m) {
-        assert(m);
-
-        return config_parse_many(PKGSYSCONFDIR "/logind.conf",
-                                 CONF_PATHS_NULSTR("systemd/logind.conf.d"),
-                                 "Login\0",
-                                 config_item_perf_lookup, logind_gperf_lookup,
-                                 false, m);
-}
-
 int main(int argc, char *argv[]) {
         Manager *m = NULL;
         int r;
similarity index 95%
rename from src/login/logind.conf
rename to src/login/logind.conf.in
index 6095e482ace398488947deef2295ae518813b2f0..3c96def45d941eb92040f8d59c473e17a936f69c 100644 (file)
@@ -14,7 +14,7 @@
 [Login]
 #NAutoVTs=6
 #ReserveVT=6
-#KillUserProcesses=no
+#KillUserProcesses=@KILL_USER_PROCESSES@
 #KillOnlyUsers=
 #KillExcludeUsers=root
 #InhibitDelayMaxSec=5
index 23326bb79feedf56adae5099e835c86665f92576..1fa64416294ce194331c2d46638ce028f599db5f 100644 (file)
                 </defaults>
         </action>
 
+        <action id="org.freedesktop.login1.set-self-linger">
+                <_description>Allow non-logged-in user to run programs</_description>
+                <_message>Explicit request is required to run programs as a non-logged-in user.</_message>
+                <defaults>
+                        <allow_any>yes</allow_any>
+                </defaults>
+        </action>
+
         <action id="org.freedesktop.login1.set-user-linger">
                 <_description>Allow non-logged-in users to run programs</_description>
                 <_message>Authentication is required to run programs as a non-logged-in user.</_message>
index 7933508f2bd33d8d3951209cc66a00dc39571208..f188a8e548fb8926e89ed037137b50c098eb39d8 100644 (file)
@@ -8,4 +8,5 @@ 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
index 73f5112c4da9080c732131509eaf2b7f9e91bdde..0eed9b81bb5a5b32a06c4d2f669d85875d240d47 100644 (file)
 #include "alloc-util.h"
 #include "bus-label.h"
 #include "bus-util.h"
+#include "fd-util.h"
 #include "image-dbus.h"
 #include "io-util.h"
 #include "machine-image.h"
+#include "process-util.h"
 #include "strv.h"
 #include "user-util.h"
 
@@ -33,13 +35,18 @@ int bus_image_method_remove(
                 void *userdata,
                 sd_bus_error *error) {
 
+        _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
         Image *image = userdata;
         Manager *m = image->userdata;
+        pid_t child;
         int r;
 
         assert(message);
         assert(image);
 
+        if (m->n_operations >= OPERATIONS_MAX)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+
         r = bus_verify_polkit_async(
                         message,
                         CAP_SYS_ADMIN,
@@ -54,11 +61,35 @@ int bus_image_method_remove(
         if (r == 0)
                 return 1; /* Will call us back */
 
-        r = image_remove(image);
-        if (r < 0)
+        if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+        child = fork();
+        if (child < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+        if (child == 0) {
+                errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+                r = image_remove(image);
+                if (r < 0) {
+                        (void) write(errno_pipe_fd[1], &r, sizeof(r));
+                        _exit(EXIT_FAILURE);
+                }
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+        r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+        if (r < 0) {
+                (void) sigkill_wait(child);
                 return r;
+        }
 
-        return sd_bus_reply_method_return(message, NULL);
+        errno_pipe_fd[0] = -1;
+
+        return 1;
 }
 
 int bus_image_method_rename(
@@ -107,13 +138,19 @@ int bus_image_method_clone(
                 void *userdata,
                 sd_bus_error *error) {
 
+        _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
         Image *image = userdata;
         Manager *m = image->userdata;
         const char *new_name;
         int r, read_only;
+        pid_t child;
 
         assert(message);
         assert(image);
+        assert(m);
+
+        if (m->n_operations >= OPERATIONS_MAX)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
 
         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
         if (r < 0)
@@ -136,11 +173,35 @@ int bus_image_method_clone(
         if (r == 0)
                 return 1; /* Will call us back */
 
-        r = image_clone(image, new_name, read_only);
-        if (r < 0)
+        if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+        child = fork();
+        if (child < 0)
+                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+        if (child == 0) {
+                errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+                r = image_clone(image, new_name, read_only);
+                if (r < 0) {
+                        (void) write(errno_pipe_fd[1], &r, sizeof(r));
+                        _exit(EXIT_FAILURE);
+                }
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+        r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+        if (r < 0) {
+                (void) sigkill_wait(child);
                 return r;
+        }
 
-        return sd_bus_reply_method_return(message, NULL);
+        errno_pipe_fd[0] = -1;
+
+        return 1;
 }
 
 int bus_image_method_mark_read_only(
index c5bbf2fbde92982da41dc18644abd0926f3c9970..7b9aa66d63286af74001e728746bf340e0489047 100644 (file)
@@ -46,6 +46,7 @@
 #include "mkdir.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "signal-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "user-util.h"
@@ -166,7 +167,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
         }
 
-        if (signo <= 0 || signo >= _NSIG)
+        if (!SIGNAL_VALID(signo))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
 
         r = bus_verify_polkit_async(
@@ -729,7 +730,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
                 return r;
 
         /* Name and mode */
-        unit = strjoina("container-shell@", p, ".service", NULL);
+        unit = strjoina("container-shell@", p, ".service");
         r = sd_bus_message_append(tm, "ss", unit, "fail");
         if (r < 0)
                 return r;
@@ -1084,52 +1085,11 @@ finish:
         return r;
 }
 
-static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        MachineOperation *o = userdata;
-        int r;
-
-        assert(o);
-        assert(si);
-
-        o->pid = 0;
-
-        if (si->si_code != CLD_EXITED) {
-                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
-                goto fail;
-        }
-
-        if (si->si_status != EXIT_SUCCESS) {
-                if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
-                        r = sd_bus_error_set_errnof(&error, r, "%m");
-                else
-                        r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-
-                goto fail;
-        }
-
-        r = sd_bus_reply_method_return(o->message, NULL);
-        if (r < 0)
-                log_error_errno(r, "Failed to reply to message: %m");
-
-        machine_operation_unref(o);
-        return 0;
-
-fail:
-        r = sd_bus_reply_method_error(o->message, &error);
-        if (r < 0)
-                log_error_errno(r, "Failed to reply to message: %m");
-
-        machine_operation_unref(o);
-        return 0;
-}
-
 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
         _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
         _cleanup_close_ int hostfd = -1;
         Machine *m = userdata;
-        MachineOperation *o;
         bool copy_from;
         pid_t child;
         char *t;
@@ -1138,7 +1098,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
         assert(message);
         assert(m);
 
-        if (m->n_operations >= MACHINE_OPERATIONS_MAX)
+        if (m->manager->n_operations >= OPERATIONS_MAX)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
 
         if (m->class != MACHINE_CONTAINER)
@@ -1248,29 +1208,107 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
 
         errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
 
-        /* Copying might take a while, hence install a watch the
-         * child, and return */
+        /* Copying might take a while, hence install a watch on the child, and return */
 
-        o = new0(MachineOperation, 1);
-        if (!o)
-                return log_oom();
-
-        o->pid = child;
-        o->message = sd_bus_message_ref(message);
-        o->errno_fd = errno_pipe_fd[0];
+        r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]);
+        if (r < 0) {
+                (void) sigkill_wait(child);
+                return r;
+        }
         errno_pipe_fd[0] = -1;
 
-        r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
-        if (r < 0) {
-                machine_operation_unref(o);
-                return log_oom();
+        return 1;
+}
+
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_close_ int fd = -1;
+        Machine *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = bus_verify_polkit_async(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.machine1.manage-machines",
+                        NULL,
+                        false,
+                        UID_INVALID,
+                        &m->manager->polkit_registry,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Will call us back */
+
+        switch (m->class) {
+
+        case MACHINE_HOST:
+                fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                if (fd < 0)
+                        return -errno;
+
+                break;
+
+        case MACHINE_CONTAINER: {
+                _cleanup_close_ int mntns_fd = -1, root_fd = -1;
+                _cleanup_close_pair_ int pair[2] = { -1, -1 };
+                siginfo_t si;
+                pid_t child;
+
+                r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
+                if (r < 0)
+                        return r;
+
+                if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+                        return -errno;
+
+                child = fork();
+                if (child < 0)
+                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+
+                if (child == 0) {
+                        _cleanup_close_ int dfd = -1;
+
+                        pair[0] = safe_close(pair[0]);
+
+                        r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
+                        if (r < 0)
+                                _exit(EXIT_FAILURE);
+
+                        dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+                        if (dfd < 0)
+                                _exit(EXIT_FAILURE);
+
+                        r = send_one_fd(pair[1], dfd, 0);
+                        dfd = safe_close(dfd);
+                        if (r < 0)
+                                _exit(EXIT_FAILURE);
+
+                        _exit(EXIT_SUCCESS);
+                }
+
+                pair[1] = safe_close(pair[1]);
+
+                r = wait_for_terminate(child, &si);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
+                if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+
+                fd = receive_one_fd(pair[0], MSG_DONTWAIT);
+                if (fd < 0)
+                        return fd;
+
+                break;
         }
 
-        LIST_PREPEND(operations, m->operations, o);
-        m->n_operations++;
-        o->machine = m;
+        default:
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
+        }
 
-        return 1;
+        return sd_bus_reply_method_return(message, "h", fd);
 }
 
 const sd_bus_vtable machine_vtable[] = {
@@ -1296,6 +1334,7 @@ const sd_bus_vtable machine_vtable[] = {
         SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_VTABLE_END
 };
 
index 3a8162b1712d53b647819947ab9538efb0a47323..241b23c7ecc55de3f7e586246fa6eefce7093f7d 100644 (file)
@@ -38,6 +38,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
 int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
 int machine_send_signal(Machine *m, bool new_machine);
 int machine_send_create_reply(Machine *m, sd_bus_error *error);
index 7d4270a8fffe350737f398e2ce3acf701c834270..c1fae570849b7f39468c48a5cdec90d3b4be228e 100644 (file)
@@ -89,7 +89,7 @@ void machine_free(Machine *m) {
         assert(m);
 
         while (m->operations)
-                machine_operation_unref(m->operations);
+                operation_free(m->operations);
 
         if (m->in_gc_queue)
                 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
@@ -596,28 +596,6 @@ int machine_open_terminal(Machine *m, const char *path, int mode) {
         }
 }
 
-MachineOperation *machine_operation_unref(MachineOperation *o) {
-        if (!o)
-                return NULL;
-
-        sd_event_source_unref(o->event_source);
-
-        safe_close(o->errno_fd);
-
-        if (o->pid > 1)
-                (void) kill(o->pid, SIGKILL);
-
-        sd_bus_message_unref(o->message);
-
-        if (o->machine) {
-                LIST_REMOVE(operations, o->machine->operations, o);
-                o->machine->n_operations--;
-        }
-
-        free(o);
-        return NULL;
-}
-
 void machine_release_unit(Machine *m) {
         assert(m);
 
index 1d8cc5911a707da20f3ee2ab02c8ac7effdcae0d..e5d75361a9a635b23db77dc448a040556197a94f 100644 (file)
 ***/
 
 typedef struct Machine Machine;
-typedef struct MachineOperation MachineOperation;
 typedef enum KillWho KillWho;
 
 #include "list.h"
 #include "machined.h"
+#include "operation.h"
 
 typedef enum MachineState {
         MACHINE_OPENING,    /* Machine is being registered */
@@ -49,17 +49,6 @@ enum KillWho {
         _KILL_WHO_INVALID = -1
 };
 
-#define MACHINE_OPERATIONS_MAX 64
-
-struct MachineOperation {
-        Machine *machine;
-        pid_t pid;
-        sd_bus_message *message;
-        int errno_fd;
-        sd_event_source *event_source;
-        LIST_FIELDS(MachineOperation, operations);
-};
-
 struct Machine {
         Manager *manager;
 
@@ -88,10 +77,9 @@ struct Machine {
         int *netif;
         unsigned n_netif;
 
-        LIST_FIELDS(Machine, gc_queue);
+        LIST_HEAD(Operation, operations);
 
-        MachineOperation *operations;
-        unsigned n_operations;
+        LIST_FIELDS(Machine, gc_queue);
 };
 
 Machine* machine_new(Manager *manager, MachineClass class, const char *name);
@@ -109,8 +97,6 @@ void machine_release_unit(Machine *m);
 
 MachineState machine_get_state(Machine *u);
 
-MachineOperation *machine_operation_unref(MachineOperation *o);
-
 const char* machine_class_to_string(MachineClass t) _const_;
 MachineClass machine_class_from_string(const char *s) _pure_;
 
index e49c90fd1b28b87a659f05f6e4653ff95618a84f..1165ab5afadce5151fead7282b72b400cbb37631 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "alloc-util.h"
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
@@ -61,6 +62,7 @@
 
 static char **arg_property = NULL;
 static bool arg_all = false;
+static bool arg_value = false;
 static bool arg_full = false;
 static bool arg_no_pager = false;
 static bool arg_legend = true;
@@ -129,15 +131,14 @@ static int list_machines(int argc, char *argv[], void *userdata) {
 
         pager_open(arg_no_pager, false);
 
-        r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "ListMachines",
-                                &error,
-                                &reply,
-                                NULL);
+        r = sd_bus_call_method(bus,
+                               "org.freedesktop.machine1",
+                               "/org/freedesktop/machine1",
+                               "org.freedesktop.machine1.Manager",
+                               "ListMachines",
+                               &error,
+                               &reply,
+                               NULL);
         if (r < 0) {
                 log_error("Could not get machines: %s", bus_error_message(&error, -r));
                 return r;
@@ -232,15 +233,14 @@ static int list_images(int argc, char *argv[], void *userdata) {
 
         pager_open(arg_no_pager, false);
 
-        r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.machine1",
-                                "/org/freedesktop/machine1",
-                                "org.freedesktop.machine1.Manager",
-                                "ListImages",
-                                &error,
-                                &reply,
-                                "");
+        r = sd_bus_call_method(bus,
+                               "org.freedesktop.machine1",
+                               "/org/freedesktop/machine1",
+                               "org.freedesktop.machine1.Manager",
+                               "ListImages",
+                               &error,
+                               &reply,
+                               "");
         if (r < 0) {
                 log_error("Could not get images: %s", bus_error_message(&error, -r));
                 return r;
@@ -332,8 +332,8 @@ static int list_images(int argc, char *argv[], void *userdata) {
 }
 
 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ char *path = NULL;
         const char *cgroup;
         int r;
@@ -342,9 +342,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         assert(bus);
         assert(unit);
 
-        if (arg_transport == BUS_TRANSPORT_REMOTE)
-                return 0;
-
         path = unit_dbus_path_from_name(unit);
         if (!path)
                 return log_oom();
@@ -358,16 +355,14 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
                         &error,
                         &reply,
                         "s");
-        if (r < 0) {
-                log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
 
         r = sd_bus_message_read(reply, "s", &cgroup);
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+        if (isempty(cgroup))
                 return 0;
 
         c = columns();
@@ -376,7 +371,21 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         else
                 c = 0;
 
-        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, get_output_flags());
+        r = unit_show_processes(bus, unit, cgroup, "\t\t  ", c, get_output_flags(), &error);
+        if (r == -EBADR) {
+
+                if (arg_transport == BUS_TRANSPORT_REMOTE)
+                        return 0;
+
+                /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
+
+                if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+                        return 0;
+
+                show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, &leader, leader > 0, get_output_flags());
+        } else if (r < 0)
+                return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
+
         return 0;
 }
 
@@ -680,7 +689,7 @@ static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line
 
         *new_line = true;
 
-        r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
+        r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
         if (r < 0)
                 log_error_errno(r, "Could not get properties: %m");
 
@@ -713,15 +722,14 @@ static int show_machine(int argc, char *argv[], void *userdata) {
         for (i = 1; i < argc; i++) {
                 const char *path = NULL;
 
-                r = sd_bus_call_method(
-                                        bus,
-                                        "org.freedesktop.machine1",
-                                        "/org/freedesktop/machine1",
-                                        "org.freedesktop.machine1.Manager",
-                                        "GetMachine",
-                                        &error,
-                                        &reply,
-                                        "s", argv[i]);
+                r = sd_bus_call_method(bus,
+                                       "org.freedesktop.machine1",
+                                       "/org/freedesktop/machine1",
+                                       "org.freedesktop.machine1.Manager",
+                                       "GetMachine",
+                                       &error,
+                                       &reply,
+                                       "s", argv[i]);
                 if (r < 0) {
                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
                         return r;
@@ -929,7 +937,7 @@ static int show_image_properties(sd_bus *bus, const char *path, bool *new_line)
 
         *new_line = true;
 
-        r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
+        r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
         if (r < 0)
                 log_error_errno(r, "Could not get properties: %m");
 
@@ -1068,6 +1076,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
 
 static int copy_files(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 *m = NULL;
         _cleanup_free_ char *abs_host_path = NULL;
         char *dest, *host_path, *container_path;
         sd_bus *bus = userdata;
@@ -1091,18 +1100,27 @@ static int copy_files(int argc, char *argv[], void *userdata) {
                 host_path = abs_host_path;
         }
 
-        r = sd_bus_call_method(
+        r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.machine1",
                         "/org/freedesktop/machine1",
                         "org.freedesktop.machine1.Manager",
-                        copy_from ? "CopyFromMachine" : "CopyToMachine",
-                        &error,
-                        NULL,
+                        copy_from ? "CopyFromMachine" : "CopyToMachine");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(
+                        m,
                         "sss",
                         argv[1],
                         copy_from ? container_path : host_path,
                         copy_from ? host_path : container_path);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        /* This is a slow operation, hence turn off any method call timeouts */
+        r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
 
@@ -1385,7 +1403,6 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
 }
 
 static int remove_image(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         sd_bus *bus = userdata;
         int r, i;
 
@@ -1394,19 +1411,27 @@ static int remove_image(int argc, char *argv[], void *userdata) {
         polkit_agent_open_if_enabled();
 
         for (i = 1; i < argc; i++) {
-                r = sd_bus_call_method(
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+                r = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.machine1",
                                 "/org/freedesktop/machine1",
                                 "org.freedesktop.machine1.Manager",
-                                "RemoveImage",
-                                &error,
-                                NULL,
-                                "s", argv[i]);
-                if (r < 0) {
-                        log_error("Could not remove image: %s", bus_error_message(&error, -r));
-                        return r;
-                }
+                                "RemoveImage");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append(m, "s", argv[i]);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                /* This is a slow operation, hence turn off any method call timeouts */
+                r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+                if (r < 0)
+                        return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
         }
 
         return 0;
@@ -1438,24 +1463,30 @@ static int rename_image(int argc, char *argv[], void *userdata) {
 
 static int clone_image(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 *m = NULL;
         sd_bus *bus = userdata;
         int r;
 
         polkit_agent_open_if_enabled();
 
-        r = sd_bus_call_method(
+        r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.machine1",
                         "/org/freedesktop/machine1",
                         "org.freedesktop.machine1.Manager",
-                        "CloneImage",
-                        &error,
-                        NULL,
-                        "ssb", argv[1], argv[2], arg_read_only);
-        if (r < 0) {
-                log_error("Could not clone image: %s", bus_error_message(&error, -r));
-                return r;
-        }
+                        "CloneImage");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        /* This is a slow operation, hence turn off any method call timeouts */
+        r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
 
         return 0;
 }
@@ -2183,15 +2214,14 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
 
         pager_open(arg_no_pager, false);
 
-        r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.import1",
-                                "/org/freedesktop/import1",
-                                "org.freedesktop.import1.Manager",
-                                "ListTransfers",
-                                &error,
-                                &reply,
-                                NULL);
+        r = sd_bus_call_method(bus,
+                               "org.freedesktop.import1",
+                               "/org/freedesktop/import1",
+                               "org.freedesktop.import1.Manager",
+                               "ListTransfers",
+                               &error,
+                               &reply,
+                               NULL);
         if (r < 0) {
                 log_error("Could not get transfers: %s", bus_error_message(&error, -r));
                 return r;
@@ -2341,6 +2371,50 @@ static int set_limit(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int clean_images(int argc, char *argv[], void *userdata) {
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        uint64_t usage, total = 0;
+        char fb[FORMAT_BYTES_MAX];
+        sd_bus *bus = userdata;
+        const char *name;
+        unsigned c = 0;
+        int r;
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.machine1",
+                        "/org/freedesktop/machine1",
+                        "org.freedesktop.machine1.Manager",
+                        "CleanPool",
+                        &error,
+                        &reply,
+                        "s", arg_all ? "all" : "hidden");
+        if (r < 0)
+                return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
+
+        r = sd_bus_message_enter_container(reply, 'a', "(st)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
+                log_info("Removed image '%s'. Freed exclusive disk space: %s",
+                         name, format_bytes(fb, sizeof(fb), usage));
+
+                total += usage;
+                c++;
+        }
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        log_info("Removed %u images in total. Total freed exclusive disk space %s.",
+                 c, format_bytes(fb, sizeof(fb), total));
+
+        return 0;
+}
+
 static int help(int argc, char *argv[], void *userdata) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -2356,11 +2430,12 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -p --property=NAME          Show only properties by this name\n"
                "  -q --quiet                  Suppress output\n"
                "  -a --all                    Show all properties, including empty ones\n"
+               "     --value                  When showing properties, only print the value\n"
                "  -l --full                   Do not ellipsize output\n"
                "     --kill-who=WHO           Who to send signal to\n"
                "  -s --signal=SIGNAL          Which signal to send\n"
                "     --uid=USER               Specify user ID to invoke shell as\n"
-               "     --setenv=VAR=VALUE       Add an environment variable for shell\n"
+               "  -E --setenv=VAR=VALUE       Add an environment variable for shell\n"
                "     --read-only              Create read-only bind mount\n"
                "     --mkdir                  Create directory before bind mounting, if missing\n"
                "  -n --lines=INTEGER          Number of journal entries to show\n"
@@ -2397,7 +2472,8 @@ static int help(int argc, char *argv[], void *userdata) {
                "  rename NAME NAME            Rename an image\n"
                "  read-only NAME [BOOL]       Mark or unmark image read-only\n"
                "  remove NAME...              Remove an image\n"
-               "  set-limit [NAME] BYTES      Set image or pool size limit (disk quota)\n\n"
+               "  set-limit [NAME] BYTES      Set image or pool size limit (disk quota)\n"
+               "  clean                       Remove hidden (or all) images\n\n"
                "Image Transfer Commands:\n"
                "  pull-tar URL [NAME]         Download a TAR container image\n"
                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"
@@ -2418,6 +2494,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERSION = 0x100,
                 ARG_NO_PAGER,
                 ARG_NO_LEGEND,
+                ARG_VALUE,
                 ARG_KILL_WHO,
                 ARG_READ_ONLY,
                 ARG_MKDIR,
@@ -2426,7 +2503,6 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_FORCE,
                 ARG_FORMAT,
                 ARG_UID,
-                ARG_SETENV,
         };
 
         static const struct option options[] = {
@@ -2434,6 +2510,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version",         no_argument,       NULL, ARG_VERSION         },
                 { "property",        required_argument, NULL, 'p'                 },
                 { "all",             no_argument,       NULL, 'a'                 },
+                { "value",           no_argument,       NULL, ARG_VALUE           },
                 { "full",            no_argument,       NULL, 'l'                 },
                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
@@ -2451,16 +2528,38 @@ static int parse_argv(int argc, char *argv[]) {
                 { "force",           no_argument,       NULL, ARG_FORCE           },
                 { "format",          required_argument, NULL, ARG_FORMAT          },
                 { "uid",             required_argument, NULL, ARG_UID             },
-                { "setenv",          required_argument, NULL, ARG_SETENV          },
+                { "setenv",          required_argument, NULL, 'E'                 },
                 {}
         };
 
+        bool reorder = false;
         int c, r;
 
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
+        for (;;) {
+                const char * const option_string = "+hp:als:H:M:qn:o:";
+
+                c = getopt_long(argc, argv, option_string + reorder, options, NULL);
+                if (c < 0) {
+                        /* We generally are fine with the fact that getopt_long() reorders the command line, and looks
+                         * for switches after the main verb. However, for "shell" we really don't want that, since we
+                         * want that switches passed after that are passed to the program to execute, and not processed
+                         * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled
+                         * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the
+                         * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any
+                         * further options processed. However, if it is anything else, we process the same argument
+                         * again, but this time allow reordering. */
+
+                        if (!reorder && optind < argc && !streq(argv[optind], "shell")) {
+                                reorder = true;
+                                optind--;
+                                continue;
+                        }
+
+                        break;
+                }
 
                 switch (c) {
 
@@ -2485,6 +2584,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_all = true;
                         break;
 
+                case ARG_VALUE:
+                        arg_value = true;
+                        break;
+
                 case 'l':
                         arg_full = true;
                         break;
@@ -2575,7 +2678,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_uid = optarg;
                         break;
 
-                case ARG_SETENV:
+                case 'E':
                         if (!env_assignment_is_valid(optarg)) {
                                 log_error("Environment assignment invalid: %s", optarg);
                                 return -EINVAL;
@@ -2592,6 +2695,7 @@ static int parse_argv(int argc, char *argv[]) {
                 default:
                         assert_not_reached("Unhandled option");
                 }
+        }
 
         return 1;
 }
@@ -2631,6 +2735,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
                 { "list-transfers",  VERB_ANY, 1,        0,            list_transfers    },
                 { "cancel-transfer", 2,        VERB_ANY, 0,            cancel_transfer   },
                 { "set-limit",       2,        3,        0,            set_limit         },
+                { "clean",           VERB_ANY, 1,        0,            clean_images      },
                 {}
         };
 
index 20894433e7d7f826935acd88a5d898e620f28723..31efa3695bba9cb60129fdcb9f33924d9d9f5d86 100644 (file)
@@ -706,6 +706,26 @@ static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_e
         return bus_machine_method_copy(message, machine, error);
 }
 
+static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        Machine *machine;
+        const char *name;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        machine = hashmap_get(m->machines, name);
+        if (!machine)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+        return bus_machine_method_open_root_directory(message, machine, error);
+}
+
 static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(image_unrefp) Image* i = NULL;
         const char *name;
@@ -802,6 +822,93 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata,
         return bus_image_method_mark_read_only(message, i, error);
 }
 
+static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        enum {
+                REMOVE_ALL,
+                REMOVE_HIDDEN,
+        } mode;
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+        Manager *m = userdata;
+        Image *image;
+        const char *mm;
+        Iterator i;
+        int r;
+
+        assert(message);
+
+        r = sd_bus_message_read(message, "s", &mm);
+        if (r < 0)
+                return r;
+
+        if (streq(mm, "all"))
+                mode = REMOVE_ALL;
+        else if (streq(mm, "hidden"))
+                mode = REMOVE_HIDDEN;
+        else
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
+
+        r = bus_verify_polkit_async(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.machine1.manage-machines",
+                        NULL,
+                        false,
+                        UID_INVALID,
+                        &m->polkit_registry,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Will call us back */
+
+        images = hashmap_new(&string_hash_ops);
+        if (!images)
+                return -ENOMEM;
+
+        r = image_discover(images);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(st)");
+        if (r < 0)
+                return r;
+
+        HASHMAP_FOREACH(image, images, i) {
+
+                /* We can't remove vendor images (i.e. those in /usr) */
+                if (IMAGE_IS_VENDOR(image))
+                        continue;
+
+                if (IMAGE_IS_HOST(image))
+                        continue;
+
+                if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
+                        continue;
+
+                r = image_remove(image);
+                if (r == -EBUSY) /* keep images that are currently being used. */
+                        continue;
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name);
+
+                r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
+}
+
 static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         uint64_t limit;
@@ -1138,12 +1245,14 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
index f2c1966a6b6ce143eb5791f10c006466ebd27fb7..f7ceb5e603d4628188380eb58e4f178b8136dde5 100644 (file)
@@ -70,6 +70,11 @@ void manager_free(Manager *m) {
 
         assert(m);
 
+        while (m->operations)
+                operation_free(m->operations);
+
+        assert(m->n_operations == 0);
+
         while ((machine = hashmap_first(m->machines)))
                 machine_free(machine);
 
@@ -336,6 +341,9 @@ int manager_startup(Manager *m) {
 static bool check_idle(void *userdata) {
         Manager *m = userdata;
 
+        if (m->operations)
+                return false;
+
         manager_gc(m, true);
 
         return hashmap_isempty(m->machines);
index e7d7dfdcebcbf7e41fdbb08a47f08e43c1823f9c..7b9b148044987034a5e9a7b0b828f465ff1a4066 100644 (file)
@@ -32,6 +32,7 @@ typedef struct Manager Manager;
 #include "image-dbus.h"
 #include "machine-dbus.h"
 #include "machine.h"
+#include "operation.h"
 
 struct Manager {
         sd_event *event;
@@ -49,6 +50,9 @@ struct Manager {
         LIST_HEAD(Machine, machine_gc_queue);
 
         Machine *host_machine;
+
+        LIST_HEAD(Operation, operations);
+        unsigned n_operations;
 };
 
 Manager *manager_new(void);
diff --git a/src/machine/operation.c b/src/machine/operation.c
new file mode 100644 (file)
index 0000000..e6ddc41
--- /dev/null
@@ -0,0 +1,131 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "operation.h"
+#include "process-util.h"
+
+static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        Operation *o = userdata;
+        int r;
+
+        assert(o);
+        assert(si);
+
+        log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i",
+                  o->pid,
+                  sigchld_code_to_string(si->si_code), si->si_status);
+
+        o->pid = 0;
+
+        if (si->si_code != CLD_EXITED) {
+                r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+                goto fail;
+        }
+
+        if (si->si_status != EXIT_SUCCESS) {
+                if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
+                        r = sd_bus_error_set_errnof(&error, r, "%m");
+                else
+                        r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+
+                goto fail;
+        }
+
+        r = sd_bus_reply_method_return(o->message, NULL);
+        if (r < 0)
+                log_error_errno(r, "Failed to reply to message: %m");
+
+        operation_free(o);
+        return 0;
+
+fail:
+        r = sd_bus_reply_method_error(o->message, &error);
+        if (r < 0)
+                log_error_errno(r, "Failed to reply to message: %m");
+
+        operation_free(o);
+        return 0;
+}
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) {
+        Operation *o;
+        int r;
+
+        assert(manager);
+        assert(child > 1);
+        assert(message);
+        assert(errno_fd >= 0);
+
+        o = new0(Operation, 1);
+        if (!o)
+                return -ENOMEM;
+
+        r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
+        if (r < 0) {
+                free(o);
+                return r;
+        }
+
+        o->pid = child;
+        o->message = sd_bus_message_ref(message);
+        o->errno_fd = errno_fd;
+
+        LIST_PREPEND(operations, manager->operations, o);
+        manager->n_operations++;
+        o->manager = manager;
+
+        if (machine) {
+                LIST_PREPEND(operations_by_machine, machine->operations, o);
+                o->machine = machine;
+        }
+
+        log_debug("Started new operation " PID_FMT ".", child);
+
+        /* At this point we took ownership of both the child and the errno file descriptor! */
+
+        return 0;
+}
+
+Operation *operation_free(Operation *o) {
+        if (!o)
+                return NULL;
+
+        sd_event_source_unref(o->event_source);
+
+        safe_close(o->errno_fd);
+
+        if (o->pid > 1)
+                (void) sigkill_wait(o->pid);
+
+        sd_bus_message_unref(o->message);
+
+        if (o->manager) {
+                LIST_REMOVE(operations, o->manager->operations, o);
+                o->manager->n_operations--;
+        }
+
+        if (o->machine)
+                LIST_REMOVE(operations_by_machine, o->machine->operations, o);
+
+        free(o);
+        return NULL;
+}
diff --git a/src/machine/operation.h b/src/machine/operation.h
new file mode 100644 (file)
index 0000000..7ca47bc
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+#include "sd-bus.h"
+#include "sd-event.h"
+
+#include "list.h"
+
+typedef struct Operation Operation;
+
+#include "machined.h"
+
+#define OPERATIONS_MAX 64
+
+struct Operation {
+        Manager *manager;
+        Machine *machine;
+        pid_t pid;
+        sd_bus_message *message;
+        int errno_fd;
+        sd_event_source *event_source;
+        LIST_FIELDS(Operation, operations);
+        LIST_FIELDS(Operation, operations_by_machine);
+};
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd);
+Operation *operation_free(Operation *o);
index 8858596489610f1cd9cd7fca968dd310b7f88c7b..aca55206b75b3d3f374e88f4f9da3cfda692fb84 100644 (file)
@@ -1,2 +1,3 @@
 /networkd-network-gperf.c
 /networkd-netdev-gperf.c
+/networkd-gperf.c
index d9d487d805d31d3988498d6307755ac478f7065b..ebc6c9eb9edb9a2b7749a3d0203a608a767bd85a 100644 (file)
@@ -148,8 +148,12 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
         for (;;) {
                 if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
                         _cleanup_free_ char *s = NULL;
+                        int r;
+
+                        r = in_addr_to_string(p->family, &u, &s);
+                        if (r < 0)
+                                return r;
 
-                        in_addr_to_string(p->family, &u, &s);
                         log_debug("Found range %s/%u", strna(s), prefixlen);
 
                         *found = u;
index 7f9a7268cc1c53ceea5c0238f2d6e296bb1ae0ce..429319da6bbbd3e50bde4965303eb7415fee272d 100644 (file)
@@ -67,16 +67,15 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
         if (r < 0)
                 return r;
 
-        address->network = network;
-
-        LIST_APPEND(addresses, network->static_addresses, address);
-
         if (section) {
                 address->section = section;
                 hashmap_put(network->addresses_by_section,
                             UINT_TO_PTR(address->section), address);
         }
 
+        address->network = network;
+        LIST_APPEND(addresses, network->static_addresses, address);
+
         *ret = address;
         address = NULL;
 
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
new file mode 100644 (file)
index 0000000..70f0121
--- /dev/null
@@ -0,0 +1,171 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.com>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <ctype.h>
+
+#include "conf-parser.h"
+#include "def.h"
+#include "dhcp-identifier.h"
+#include "hexdecoct.h"
+#include "networkd-conf.h"
+#include "string-table.h"
+
+int manager_parse_config_file(Manager *m) {
+        assert(m);
+
+        return config_parse_many(PKGSYSCONFDIR "/networkd.conf",
+                                 CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
+                                 "DHCP\0",
+                                 config_item_perf_lookup, networkd_gperf_lookup,
+                                 false, m);
+}
+
+static const char* const duid_type_table[_DUID_TYPE_MAX] = {
+        [DUID_TYPE_RAW]  = "raw",
+        [DUID_TYPE_LLT]  = "link-layer-time",
+        [DUID_TYPE_EN]   = "vendor",
+        [DUID_TYPE_LL]   = "link-layer",
+        [DUID_TYPE_UUID] = "uuid"
+};
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type");
+
+int config_parse_duid_rawdata(
+                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 r;
+        char *cbyte;
+        const char *pduid = rvalue;
+        Manager *m = userdata;
+        Network *n = userdata;
+        DUIDType duidtype;
+        uint16_t dhcp_duid_type = 0;
+        uint8_t dhcp_duid[MAX_DUID_LEN];
+        size_t len, count = 0, duid_start_offset = 0, dhcp_duid_len = 0;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(userdata);
+
+        duidtype = (ltype == DUID_CONFIG_SOURCE_GLOBAL) ? m->duid_type : n->duid_type;
+
+        if (duidtype == _DUID_TYPE_INVALID)
+                duidtype = DUID_TYPE_RAW;
+
+        switch (duidtype) {
+
+        case DUID_TYPE_LLT:
+                /* RawData contains DUID-LLT link-layer address (offset 6) */
+                duid_start_offset = 6;
+                break;
+
+        case DUID_TYPE_EN:
+                /* RawData contains DUID-EN identifier (offset 4) */
+                duid_start_offset = 4;
+                break;
+
+        case DUID_TYPE_LL:
+                /* RawData contains DUID-LL link-layer address (offset 2) */
+                duid_start_offset = 2;
+                break;
+
+        case DUID_TYPE_UUID:
+                /* RawData specifies UUID (offset 0) - fall thru */
+
+        case DUID_TYPE_RAW:
+                /* First two bytes of RawData is DUID Type - fall thru */
+
+        default:
+                break;
+        }
+
+        if (duidtype != DUID_TYPE_RAW)
+                dhcp_duid_type = (uint16_t) duidtype;
+
+        /* RawData contains DUID in format " NN:NN:NN... " */
+        for (;;) {
+                int n1, n2;
+                uint32_t byte;
+
+                r = extract_first_word(&pduid, &cbyte, ":", 0);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue);
+                        return 0;
+                }
+                if (r == 0)
+                        break;
+                if (duid_start_offset + dhcp_duid_len >= MAX_DUID_LEN) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
+                        return 0;
+                }
+
+                len = strlen(cbyte);
+                if (len != 1 && len != 2) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
+                        return 0;
+                }
+                n1 = unhexchar(cbyte[0]);
+                if (len == 2)
+                        n2 = unhexchar(cbyte[1]);
+                else
+                        n2 = 0;
+
+                if (n1 < 0 || n2 < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue);
+                        return 0;
+                }
+
+                byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2;
+
+                /* If DUID_TYPE_RAW, first two bytes hold DHCP DUID type code */
+                if (duidtype == DUID_TYPE_RAW && count < 2) {
+                        dhcp_duid_type |= (byte << (8 * (1 - count)));
+                        count++;
+                        continue;
+                }
+
+                dhcp_duid[duid_start_offset + dhcp_duid_len] = byte;
+                dhcp_duid_len++;
+        }
+
+        if (ltype == DUID_CONFIG_SOURCE_GLOBAL) {
+                m->duid_type = duidtype;
+                m->dhcp_duid_type = dhcp_duid_type;
+                m->dhcp_duid_len = dhcp_duid_len;
+                memcpy(&m->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
+        } else {
+                /* DUID_CONFIG_SOURCE_NETWORK */
+                n->duid_type = duidtype;
+                n->dhcp_duid_type = dhcp_duid_type;
+                n->dhcp_duid_len = dhcp_duid_len;
+                memcpy(&n->dhcp_duid[duid_start_offset], dhcp_duid, dhcp_duid_len);
+        }
+
+        return 0;
+}
diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h
new file mode 100644 (file)
index 0000000..671e656
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.com>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "networkd.h"
+
+typedef enum DuidConfigSource {
+        DUID_CONFIG_SOURCE_GLOBAL = 0,
+        DUID_CONFIG_SOURCE_NETWORK,
+} DuidConfigSource;
+
+int manager_parse_config_file(Manager *m);
+
+const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length);
+
+int config_parse_duid_type(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_duid_rawdata(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 68998eabf2dd65767411f472e83eb8be67e13785..c5b61abc9e58f072463852087bee0b2ba6f960e9 100644 (file)
@@ -57,6 +57,10 @@ static int link_set_dhcp_routes(Link *link) {
 
         assert(link);
         assert(link->dhcp_lease);
+        assert(link->network);
+
+        if (!link->network->dhcp_use_routes)
+                return 0;
 
         r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
         if (r < 0 && r != -ENODATA)
@@ -625,7 +629,21 @@ int dhcp4_configure(Link *link) {
 
         switch (link->network->dhcp_client_identifier) {
         case DHCP_CLIENT_ID_DUID:
-                /* Library defaults to this. */
+                /* If configured, apply user specified DUID and/or IAID */
+                if (link->network->duid_type != _DUID_TYPE_INVALID)
+                        r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+                                                         link->network->iaid,
+                                                         link->network->dhcp_duid_type,
+                                                         link->network->dhcp_duid,
+                                                         link->network->dhcp_duid_len);
+                else
+                        r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+                                                         link->network->iaid,
+                                                         link->manager->dhcp_duid_type,
+                                                         link->manager->dhcp_duid,
+                                                         link->manager->dhcp_duid_len);
+                if (r < 0)
+                        return r;
                 break;
         case DHCP_CLIENT_ID_MAC:
                 r = sd_dhcp_client_set_client_id(link->dhcp_client,
index 5f7a005c36a34b18d1b850012fb79d7c123b3211..d4b2fbfc57cdbac939e457a3f3040d97a57a491d 100644 (file)
@@ -230,6 +230,23 @@ int dhcp6_configure(Link *link) {
         if (r < 0)
                 goto error;
 
+        r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
+        if (r < 0)
+                goto error;
+
+        if (link->network->duid_type != _DUID_TYPE_INVALID)
+                r = sd_dhcp6_client_set_duid(client,
+                                             link->network->dhcp_duid_type,
+                                             link->network->dhcp_duid,
+                                             link->network->dhcp_duid_len);
+        else
+                r = sd_dhcp6_client_set_duid(client,
+                                             link->manager->dhcp_duid_type,
+                                             link->manager->dhcp_duid,
+                                             link->manager->dhcp_duid_len);
+        if (r < 0)
+                goto error;
+
         r = sd_dhcp6_client_set_index(client, link->ifindex);
         if (r < 0)
                 goto error;
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
new file mode 100644 (file)
index 0000000..afc71b4
--- /dev/null
@@ -0,0 +1,18 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "networkd-conf.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name networkd_gperf_hash
+%define lookup-function-name networkd_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+DHCP.DUIDType,              config_parse_duid_type,                 0,                                  offsetof(Manager, duid_type)
+DHCP.DUIDRawData,           config_parse_duid_rawdata,              DUID_CONFIG_SOURCE_GLOBAL,          offsetof(Manager, dhcp_duid)
index ae3bac217b336b905056dd1743821679e631e42f..5fc513bfdad9906a5eac984aaa2a4cfbfe5baf2a 100644 (file)
@@ -42,6 +42,9 @@
 static bool link_dhcp6_enabled(Link *link) {
         assert(link);
 
+        if (!socket_ipv6_is_supported())
+                return false;
+
         if (link->flags & IFF_LOOPBACK)
                 return false;
 
@@ -90,6 +93,9 @@ static bool link_ipv4ll_enabled(Link *link) {
 static bool link_ipv6ll_enabled(Link *link) {
         assert(link);
 
+        if (!socket_ipv6_is_supported())
+                return false;
+
         if (link->flags & IFF_LOOPBACK)
                 return false;
 
@@ -99,6 +105,15 @@ static bool link_ipv6ll_enabled(Link *link) {
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
 }
 
+static bool link_ipv6_enabled(Link *link) {
+        assert(link);
+
+        if (!socket_ipv6_is_supported())
+                return false;
+
+        return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
+}
+
 static bool link_lldp_rx_enabled(Link *link) {
         assert(link);
 
@@ -165,9 +180,27 @@ static bool link_ipv6_forward_enabled(Link *link) {
         return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
 }
 
+static bool link_proxy_arp_enabled(Link *link) {
+        assert(link);
+
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        if (link->network->proxy_arp < 0)
+                return false;
+
+        return true;
+}
+
 static bool link_ipv6_accept_ra_enabled(Link *link) {
         assert(link);
 
+        if (!socket_ipv6_is_supported())
+                return false;
+
         if (link->flags & IFF_LOOPBACK)
                 return false;
 
@@ -190,6 +223,7 @@ static bool link_ipv6_accept_ra_enabled(Link *link) {
 }
 
 static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
+        assert(link);
 
         if (!socket_ipv6_is_supported())
                 return _IPV6_PRIVACY_EXTENSIONS_INVALID;
@@ -203,6 +237,31 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
         return link->network->ipv6_privacy_extensions;
 }
 
+static int link_enable_ipv6(Link *link) {
+        const char *p = NULL;
+        bool disabled;
+        int r;
+
+        if (link->flags & IFF_LOOPBACK)
+                return 0;
+
+        disabled = !link_ipv6_enabled(link);
+
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
+
+        r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", disabled ? "disable" : "enable", link->ifname);
+        else {
+                if (disabled)
+                        log_link_info(link, "IPv6 disabled for interface: %m");
+                else
+                        log_link_info(link, "IPv6 enabled for interface: %m");
+        }
+
+        return 0;
+}
+
 void link_update_operstate(Link *link) {
         LinkOperationalState operstate;
         assert(link);
@@ -250,7 +309,6 @@ void link_update_operstate(Link *link) {
                 link->operstate = operstate;
                 link_send_changed(link, "OperationalState", NULL);
                 link_dirty(link);
-                manager_dirty(link->manager);
         }
 }
 
@@ -518,8 +576,6 @@ static void link_set_state(Link *link, LinkState state) {
         link->state = state;
 
         link_send_changed(link, "AdministrativeState", NULL);
-
-        return;
 }
 
 static void link_enter_unmanaged(Link *link) {
@@ -1039,6 +1095,22 @@ static int link_set_bridge_fdb(Link *const link) {
         return r;
 }
 
+static int link_set_proxy_arp(Link *const link) {
+        const char *p = NULL;
+        int r;
+
+        if (!link_proxy_arp_enabled(link))
+                return 0;
+
+        p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp");
+
+        r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
+
+        return 0;
+}
+
 static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
@@ -1384,7 +1456,7 @@ static int link_acquire_ipv6_conf(Link *link) {
         return 0;
 }
 
-static int link_acquire_conf(Link *link) {
+static int link_acquire_ipv4_conf(Link *link) {
         int r;
 
         assert(link);
@@ -1412,6 +1484,24 @@ static int link_acquire_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
         }
 
+        return 0;
+}
+
+static int link_acquire_conf(Link *link) {
+        int r;
+
+        assert(link);
+
+        r = link_acquire_ipv4_conf(link);
+        if (r < 0)
+                return r;
+
+        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
+                r = link_acquire_ipv6_conf(link);
+                if (r < 0)
+                        return r;
+        }
+
         if (link_lldp_tx_enabled(link)) {
                 r = link_lldp_tx_start(link);
                 if (r < 0)
@@ -1479,7 +1569,21 @@ static int link_up(Link *link) {
                         return log_link_error_errno(link, r, "Could not set MAC address: %m");
         }
 
+        /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled)
+           for this interface then disable IPv6 else enable it. */
+        (void) link_enable_ipv6(link);
+
         if (link->network->mtu) {
+                /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
+                   on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
+                if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) {
+
+                        log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
+                                         "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m");
+
+                        link->network->mtu = IPV6_MIN_MTU;
+                }
+
                 r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set MTU: %m");
@@ -1489,7 +1593,7 @@ static int link_up(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
 
-        if (socket_ipv6_is_supported()) {
+        if (link_ipv6_enabled(link)) {
                 /* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
                 r = sd_netlink_message_open_container(req, AF_INET6);
                 if (r < 0)
@@ -2167,6 +2271,10 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_set_proxy_arp(link);
+        if (r < 0)
+               return r;
+
         r = link_set_ipv4_forward(link);
         if (r < 0)
                 return r;
@@ -2259,12 +2367,6 @@ static int link_configure(Link *link) {
                 r = link_acquire_conf(link);
                 if (r < 0)
                         return r;
-
-                if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
-                        r = link_acquire_ipv6_conf(link);
-                        if (r < 0)
-                                return r;
-                }
         }
 
         return link_enter_join_netdev(link);
@@ -2647,6 +2749,10 @@ static int link_carrier_gained(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
+
+                r = link_enter_set_addresses(link);
+                if (r < 0)
+                        return r;
         }
 
         r = link_handle_bound_by_list(link);
@@ -2780,6 +2886,21 @@ int link_update(Link *link, sd_netlink_message *m) {
                                                            ARPHRD_ETHER);
                                 if (r < 0)
                                         return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
+
+                                if (link->network->duid_type != _DUID_TYPE_INVALID)
+                                        r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+                                                                         link->network->iaid,
+                                                                         link->network->dhcp_duid_type,
+                                                                         link->network->dhcp_duid,
+                                                                         link->network->dhcp_duid_len);
+                                else
+                                        r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+                                                                         link->network->iaid,
+                                                                         link->manager->dhcp_duid_type,
+                                                                         link->manager->dhcp_duid,
+                                                                         link->manager->dhcp_duid_len);
+                                if (r < 0)
+                                        return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
                         }
 
                         if (link->dhcp6_client) {
@@ -2789,6 +2910,24 @@ int link_update(Link *link, sd_netlink_message *m) {
                                                             ARPHRD_ETHER);
                                 if (r < 0)
                                         return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
+
+                                r = sd_dhcp6_client_set_iaid(link->dhcp6_client,
+                                                             link->network->iaid);
+                                if (r < 0)
+                                        return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
+
+                                if (link->network->duid_type != _DUID_TYPE_INVALID)
+                                        r = sd_dhcp6_client_set_duid(link->dhcp6_client,
+                                                                     link->network->dhcp_duid_type,
+                                                                     link->network->dhcp_duid,
+                                                                     link->network->dhcp_duid_len);
+                                else
+                                        r = sd_dhcp6_client_set_duid(link->dhcp6_client,
+                                                                     link->manager->dhcp_duid_type,
+                                                                     link->manager->dhcp_duid,
+                                                                     link->manager->dhcp_duid_len);
+                                if (r < 0)
+                                        return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
                         }
                 }
         }
@@ -3112,14 +3251,17 @@ void link_dirty(Link *link) {
 
         assert(link);
 
+        /* mark manager dirty as link is dirty */
+        manager_dirty(link->manager);
+
         r = set_ensure_allocated(&link->manager->dirty_links, NULL);
         if (r < 0)
                 /* allocation errors are ignored */
                 return;
 
         r = set_put(link->manager->dirty_links, link);
-        if (r < 0)
-                /* allocation errors are ignored */
+        if (r <= 0)
+                /* don't take another ref if the link was already dirty */
                 return;
 
         link_ref(link);
index 5af2a31ea7b22363c737845720ef982b3b2315b7..6bde04bc32300e77f044445de5ebc504a617411a 100644 (file)
@@ -30,6 +30,8 @@
 #include "string-util.h"
 #include "unaligned.h"
 
+#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
+
 /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
 #define LLDP_TX_FAST_INIT 4U
 
@@ -127,7 +129,7 @@ static int lldp_make_packet(
 
         h = (struct ether_header*) packet;
         h->ether_type = htobe16(ETHERTYPE_LLDP);
-        memcpy(h->ether_dhost, &(struct ether_addr) { SD_LLDP_MULTICAST_ADDR }, ETH_ALEN);
+        memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN);
         memcpy(h->ether_shost, hwaddr, ETH_ALEN);
 
         p = (uint8_t*) packet + sizeof(struct ether_header);
@@ -199,7 +201,7 @@ static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size)
                 .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
                 .ll.sll_ifindex = ifindex,
                 .ll.sll_halen = ETH_ALEN,
-                .ll.sll_addr = SD_LLDP_MULTICAST_ADDR,
+                .ll.sll_addr = LLDP_MULTICAST_ADDR,
         };
 
         _cleanup_close_ int fd = -1;
@@ -239,9 +241,8 @@ static int link_send_lldp(Link *link) {
         (void) gethostname_strict(&hostname);
         (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL);
 
+        assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC);
         ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
-        if (ttl > (usec_t) UINT16_MAX)
-                ttl = (usec_t) UINT16_MAX;
 
         caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
                 SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
index b8cb7f875dfe1bc0ce13e95573444fb8ebda89f3..d355aaa19c8d598530d8fe9666e1ff0eace43c4d 100644 (file)
@@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) {
         if (r < 0)
                 return r;
 
+        m->duid_type = _DUID_TYPE_INVALID;
+
         *ret = m;
         m = NULL;
 
index cdcd08f057e151d075aeb97ae9ec968b298159a8..3f91b2eaeab3819f6535002afe5e87b76446cd24 100644 (file)
@@ -89,6 +89,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
         }
 
+        if (b->mcast_querier >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
+        }
+
         r = sd_netlink_message_close_container(req);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -106,8 +112,19 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
         return r;
 }
 
+static void bridge_init(NetDev *n) {
+        Bridge *b;
+
+        b = BRIDGE(n);
+
+        assert(b);
+
+        b->mcast_querier = -1;
+}
+
 const NetDevVTable bridge_vtable = {
         .object_size = sizeof(Bridge),
+        .init = bridge_init,
         .sections = "Match\0NetDev\0Bridge\0",
         .post_create = netdev_bridge_post_create,
         .create_type = NETDEV_CREATE_MASTER,
index 27f26f78704570fcfb9fb2538b293ffe78427dc9..3f6f1d0502571e791bae55852372833cc00541e7 100644 (file)
@@ -26,6 +26,8 @@ typedef struct Bridge Bridge;
 struct Bridge {
         NetDev meta;
 
+        int mcast_querier;
+
         usec_t forward_delay;
         usec_t hello_time;
         usec_t max_age;
index 8f506af0922b695094ec3f1eb46ecc0e729418db..15a787a9e3bf1f4b3e035dcd7ad78cfa1478a158 100644 (file)
@@ -92,3 +92,4 @@ Bond.LearnPacketIntervalSec, config_parse_sec,                   0,
 Bridge.HelloTimeSec,         config_parse_sec,                   0,                             offsetof(Bridge, hello_time)
 Bridge.MaxAgeSec,            config_parse_sec,                   0,                             offsetof(Bridge, max_age)
 Bridge.ForwardDelaySec,      config_parse_sec,                   0,                             offsetof(Bridge, forward_delay)
+Bridge.MulticastQuerier,     config_parse_tristate,              0,                             offsetof(Bridge, mcast_querier)
index a5d1714293536e67f31c96ab861602181834dfaa..654d6a0316b4346f9d1f36a55562fc737d59b95a 100644 (file)
@@ -2,6 +2,7 @@
 #include <stddef.h>
 #include "conf-parser.h"
 #include "networkd.h"
+#include "networkd-conf.h"
 #include "network-internal.h"
 %}
 struct ConfigPerfItem;
@@ -26,6 +27,7 @@ Match.KernelCommandLine,                config_parse_net_condition,
 Match.Architecture,                     config_parse_net_condition,                     CONDITION_ARCHITECTURE,        offsetof(Network, match_arch)
 Link.MACAddress,                        config_parse_hwaddr,                            0,                             offsetof(Network, mac)
 Link.MTUBytes,                          config_parse_iec_size,                          0,                             offsetof(Network, mtu)
+Link.IAID,                              config_parse_iaid,                              0,                             offsetof(Network, iaid)
 Network.Description,                    config_parse_string,                            0,                             offsetof(Network, description)
 Network.Bridge,                         config_parse_netdev,                            0,                             offsetof(Network, bridge)
 Network.Bond,                           config_parse_netdev,                            0,                             offsetof(Network, bond)
@@ -57,6 +59,7 @@ Network.IPv6PrivacyExtensions,          config_parse_ipv6_privacy_extensions,
 Network.IPv6AcceptRouterAdvertisements, config_parse_tristate,                          0,                             offsetof(Network, ipv6_accept_ra)
 Network.IPv6DuplicateAddressDetection,  config_parse_int,                               0,                             offsetof(Network, ipv6_dad_transmits)
 Network.IPv6HopLimit,                   config_parse_int,                               0,                             offsetof(Network, ipv6_hop_limit)
+Network.ProxyARP,                       config_parse_tristate,                          0,                             offsetof(Network, proxy_arp)
 Network.BindCarrier,                    config_parse_strv,                              0,                             offsetof(Network, bind_carrier)
 Address.Address,                        config_parse_address,                           0,                             0
 Address.Peer,                           config_parse_address,                           0,                             0
@@ -80,6 +83,8 @@ DHCP.Hostname,                          config_parse_hostname,
 DHCP.RequestBroadcast,                  config_parse_bool,                              0,                             offsetof(Network, dhcp_broadcast)
 DHCP.CriticalConnection,                config_parse_bool,                              0,                             offsetof(Network, dhcp_critical)
 DHCP.VendorClassIdentifier,             config_parse_string,                            0,                             offsetof(Network, dhcp_vendor_class_identifier)
+DHCP.DUIDType,                          config_parse_duid_type,                         0,                             offsetof(Network, duid_type)
+DHCP.DUIDRawData,                       config_parse_duid_rawdata,                      DUID_CONFIG_SOURCE_NETWORK,    offsetof(Network, dhcp_duid)
 DHCP.RouteMetric,                       config_parse_unsigned,                          0,                             offsetof(Network, dhcp_route_metric)
 DHCP.UseTimezone,                       config_parse_bool,                              0,                             offsetof(Network, dhcp_use_timezone)
 DHCPServer.MaxLeaseTimeSec,             config_parse_sec,                               0,                             offsetof(Network, dhcp_server_max_lease_time_usec)
index 491b9a3efaaf3905b6fe88b6f486492d967705b4..2ebcdfa744b4aef3591486b913c8738031af8d5e 100644 (file)
@@ -131,6 +131,8 @@ static int network_load_one(Manager *manager, const char *filename) {
         network->ipv6_accept_ra = -1;
         network->ipv6_dad_transmits = -1;
         network->ipv6_hop_limit = -1;
+        network->duid_type = _DUID_TYPE_INVALID;
+        network->proxy_arp = -1;
 
         r = config_parse(NULL, filename, file,
                          "Match\0"
@@ -396,6 +398,19 @@ int network_apply(Manager *manager, Network *network, Link *link) {
         return 0;
 }
 
+bool network_has_static_ipv6_addresses(Network *network) {
+        Address *address;
+
+        assert(network);
+
+        LIST_FOREACH(addresses, address, network->static_addresses) {
+                if (address->family == AF_INET6)
+                        return true;
+        }
+
+        return false;
+}
+
 int config_parse_netdev(const char *unit,
                 const char *filename,
                 unsigned line,
index 4a13e2b574e6e2caedd172e1718f7e6b72acd015..15417f48280f00ef3ab2eaced79b1691143dad79 100644 (file)
@@ -24,6 +24,7 @@
 
 typedef struct Network Network;
 
+#include "dhcp-identifier.h"
 #include "networkd-address.h"
 #include "networkd-fdb.h"
 #include "networkd-netdev.h"
@@ -138,12 +139,20 @@ struct Network {
         int ipv6_accept_ra;
         int ipv6_dad_transmits;
         int ipv6_hop_limit;
+        int proxy_arp;
 
         union in_addr_union ipv6_token;
         IPv6PrivacyExtensions ipv6_privacy_extensions;
 
         struct ether_addr *mac;
         unsigned mtu;
+        uint32_t iaid;
+        /* Value of Type in [DUID] section */
+        DUIDType duid_type;
+        /* DUID type code - RFC 3315 */
+        uint16_t dhcp_duid_type;
+        size_t dhcp_duid_len;
+        uint8_t dhcp_duid[MAX_DUID_LEN];
 
         LLDPMode lldp_mode; /* LLDP reception */
         bool lldp_emit;     /* LLDP transmission */
@@ -177,6 +186,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret);
 int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
 int network_apply(Manager *manager, Network *network, Link *link);
 
+bool network_has_static_ipv6_addresses(Network *network);
+
 int config_parse_netdev(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_domains(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_tunnel(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 e065a5a5a9ef94c28b352f7479faafe6f5822508..bda2707e6da61851209e69124f83225751622d3d 100644 (file)
@@ -52,8 +52,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
         int r;
 
         if (section) {
-                route = hashmap_get(network->routes_by_section,
-                                    UINT_TO_PTR(section));
+                route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section));
                 if (route) {
                         *ret = route;
                         route = NULL;
@@ -67,16 +66,18 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
                 return r;
 
         route->protocol = RTPROT_STATIC;
-        route->network = network;
-
-        LIST_PREPEND(routes, network->static_routes, route);
 
         if (section) {
                 route->section = section;
-                hashmap_put(network->routes_by_section,
-                            UINT_TO_PTR(route->section), route);
+
+                r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route);
+                if (r < 0)
+                        return r;
         }
 
+        route->network = network;
+        LIST_PREPEND(routes, network->static_routes, route);
+
         *ret = route;
         route = NULL;
 
index 3a2615e6fde7370329bff05047480ab0933947ec..c8f81a2ca60c2686fe37282ecd9886b55a6567af 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "capability-util.h"
 #include "networkd.h"
+#include "networkd-conf.h"
 #include "signal-util.h"
 #include "user-util.h"
 
@@ -89,6 +90,10 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
+        r = manager_parse_config_file(m);
+        if (r < 0)
+                log_warning_errno(r, "Failed to parse configuration file: %m");
+
         r = manager_load_config(m);
         if (r < 0) {
                 log_error_errno(r, "Could not load configuration files: %m");
index 6bdd8302a0236f124d416372ce9393a62b7590d1..72a2438ac8db5d5f88fffe2c71448f3dffb30d80 100644 (file)
@@ -31,6 +31,7 @@
 
 typedef struct Manager Manager;
 
+#include "dhcp-identifier.h"
 #include "networkd-address-pool.h"
 #include "networkd-link.h"
 #include "networkd-network.h"
@@ -61,6 +62,13 @@ struct Manager {
         LIST_HEAD(AddressPool, address_pools);
 
         usec_t network_dirs_ts_usec;
+
+        /* Value of Type in [DUID] section */
+        DUIDType duid_type;
+        /* DUID type code - RFC 3315 */
+        uint16_t dhcp_duid_type;
+        size_t dhcp_duid_len;
+        uint8_t dhcp_duid[MAX_DUID_LEN];
 };
 
 extern const char* const network_dirs[];
index ecbbe6c3c9f65a1cc6559080bee4c1bbc779b820..adbe09a5e1dd8d7ae712b57e44f714ed44c7e209 100644 (file)
@@ -9,7 +9,7 @@
 
 int main(int argc, char **argv) {
         test_table(bond_mode, NETDEV_BOND_MODE);
-        /* test_table(link_state, LINK_STATE);  -- not a reversible mapping */
+        /* test_table(link_state, LINK_STATE);   not a reversible mapping */
         test_table(link_operstate, LINK_OPERSTATE);
         test_table(address_family_boolean, ADDRESS_FAMILY_BOOLEAN);
         test_table(netdev_kind, NETDEV_KIND);
index 116655cdd25377ed3577be4c2edf7c8b5a630f93..34e1310e296c940dee5673566fb14922c8e3c3a6 100644 (file)
@@ -16,7 +16,7 @@ struct ConfigPerfItem;
 %includes
 %%
 Exec.Boot,                    config_parse_boot,          0, 0
-Exec.ProcessTwo,              config_parse_pid2,          0, 0,
+Exec.ProcessTwo,              config_parse_pid2,          0, 0
 Exec.Parameters,              config_parse_strv,          0, offsetof(Settings, parameters)
 Exec.Environment,             config_parse_strv,          0, offsetof(Settings, environment)
 Exec.User,                    config_parse_string,        0, offsetof(Settings, user)
@@ -26,11 +26,13 @@ Exec.KillSignal,              config_parse_signal,        0, offsetof(Settings,
 Exec.Personality,             config_parse_personality,   0, offsetof(Settings, personality)
 Exec.MachineID,               config_parse_id128,         0, offsetof(Settings, machine_id)
 Exec.WorkingDirectory,        config_parse_path,          0, offsetof(Settings, working_directory)
+Exec.PrivateUsers,            config_parse_private_users, 0, 0
 Files.ReadOnly,               config_parse_tristate,      0, offsetof(Settings, read_only)
 Files.Volatile,               config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
 Files.Bind,                   config_parse_bind,          0, 0
 Files.BindReadOnly,           config_parse_bind,          1, 0
 Files.TemporaryFileSystem,    config_parse_tmpfs,         0, 0
+Files.PrivateUsersChown,      config_parse_tristate,      0, offsetof(Settings, userns_chown)
 Network.Private,              config_parse_tristate,      0, offsetof(Settings, private_network)
 Network.Interface,            config_parse_strv,          0, offsetof(Settings, network_interfaces)
 Network.MACVLAN,              config_parse_strv,          0, offsetof(Settings, network_macvlan)
index 64cb6b3ce3064bbb9ea3ea9918621057c038327b..8e2d2d543ce075507a4e89755963ef0966c91330 100644 (file)
@@ -438,21 +438,22 @@ static int mount_bind(const char *dest, CustomMount *m) {
                 r = mkdir_parents_label(where, 0755);
                 if (r < 0)
                         return log_error_errno(r, "Failed to make parents of %s: %m", where);
+
+                /* Create the mount point. Any non-directory file can be
+                * mounted on any non-directory file (regular, fifo, socket,
+                * char, block).
+                */
+                if (S_ISDIR(source_st.st_mode))
+                        r = mkdir_label(where, 0755);
+                else
+                        r = touch(where);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create mount point %s: %m", where);
+
         } else {
                 return log_error_errno(errno, "Failed to stat %s: %m", where);
         }
 
-        /* Create the mount point. Any non-directory file can be
-         * mounted on any non-directory file (regular, fifo, socket,
-         * char, block).
-         */
-        if (S_ISDIR(source_st.st_mode))
-                r = mkdir_label(where, 0755);
-        else
-                r = touch(where);
-        if (r < 0 && r != -EEXIST)
-                return log_error_errno(r, "Failed to create mount point %s: %m", where);
-
         if (mount(m->source, where, NULL, mount_flags, mount_opts) < 0)
                 return log_error_errno(errno, "mount(%s) failed: %m", where);
 
index 74a0ae865b40f929c36865d5917b9bcf20da9747..f2b7e4dd797ccfb1ec638a27bb3b15d5fb65c781 100644 (file)
@@ -538,3 +538,50 @@ int veth_extra_parse(char ***l, const char *p) {
         a = b = NULL;
         return 0;
 }
+
+static int remove_one_veth_link(sd_netlink *rtnl, const char *name) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        int r;
+
+        if (isempty(name))
+                return 0;
+
+        r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate netlink message: %m");
+
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add netlink interface name: %m");
+
+        r = sd_netlink_call(rtnl, m, 0, NULL);
+        if (r == -ENODEV) /* Already gone */
+                return 0;
+        if (r < 0)
+                return log_error_errno(r, "Failed to remove veth interface %s: %m", name);
+
+        return 1;
+}
+
+int remove_veth_links(const char *primary, char **pairs) {
+        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+        char **a, **b;
+        int r;
+
+        /* In some cases the kernel might pin the veth links between host and container even after the namespace
+         * died. Hence, let's better remove them explicitly too. */
+
+        if (isempty(primary) && strv_isempty(pairs))
+                return 0;
+
+        r = sd_netlink_open(&rtnl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to netlink: %m");
+
+        remove_one_veth_link(rtnl, primary);
+
+        STRV_FOREACH_PAIR(a, b, pairs)
+                remove_one_veth_link(rtnl, *a);
+
+        return 0;
+}
index 9ab1606d1c5a8ae67c54eb4ffd24b4a400eb5522..c5036ab470e2dea5558f718b665f4a9cef39959c 100644 (file)
@@ -34,3 +34,5 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
 int move_network_interfaces(pid_t pid, char **ifaces);
 
 int veth_extra_parse(char ***l, const char *p);
+
+int remove_veth_links(const char *primary, char **pairs);
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
new file mode 100644 (file)
index 0000000..c7382d4
--- /dev/null
@@ -0,0 +1,469 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <linux/magic.h>
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+#include "acl-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "missing.h"
+#include "nspawn-patch-uid.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+
+#ifdef HAVE_ACL
+
+static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
+        char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+        acl_t acl;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        if (name) {
+                _cleanup_close_ int child_fd = -1;
+
+                child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+                if (child_fd < 0)
+                        return -errno;
+
+                xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
+                acl = acl_get_file(procfs_path, type);
+        } else if (type == ACL_TYPE_ACCESS)
+                acl = acl_get_fd(fd);
+        else {
+                xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+                acl = acl_get_file(procfs_path, type);
+        }
+        if (!acl)
+                return -errno;
+
+        *ret = acl;
+        return 0;
+}
+
+static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
+        char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+        int r;
+
+        assert(fd >= 0);
+        assert(acl);
+
+        if (name) {
+                _cleanup_close_ int child_fd = -1;
+
+                child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+                if (child_fd < 0)
+                        return -errno;
+
+                xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
+                r = acl_set_file(procfs_path, type, acl);
+        } else if (type == ACL_TYPE_ACCESS)
+                r = acl_set_fd(fd, acl);
+        else {
+                xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+                r = acl_set_file(procfs_path, type, acl);
+        }
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) {
+        _cleanup_(acl_freep) acl_t copy = NULL;
+        acl_entry_t i;
+        int r;
+
+        assert(acl);
+        assert(ret);
+
+        r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+        if (r < 0)
+                return -errno;
+        while (r > 0) {
+                uid_t *old_uid, new_uid;
+                bool modify = false;
+                acl_tag_t tag;
+
+                if (acl_get_tag_type(i, &tag) < 0)
+                        return -errno;
+
+                if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
+
+                        /* We don't distuingish here between uid_t and gid_t, let's make sure the compiler checks that
+                         * this is actually OK */
+                        assert_cc(sizeof(uid_t) == sizeof(gid_t));
+
+                        old_uid = acl_get_qualifier(i);
+                        if (!old_uid)
+                                return -errno;
+
+                        new_uid = shift | (*old_uid & UINT32_C(0xFFFF));
+                        if (!uid_is_valid(new_uid))
+                                return -EINVAL;
+
+                        modify = new_uid != *old_uid;
+                        if (modify && !copy) {
+                                int n;
+
+                                /* There's no copy of the ACL yet? if so, let's create one, and start the loop from the
+                                 * beginning, so that we copy all entries, starting from the first, this time. */
+
+                                n = acl_entries(acl);
+                                if (n < 0)
+                                        return -errno;
+
+                                copy = acl_init(n);
+                                if (!copy)
+                                        return -errno;
+
+                                /* Seek back to the beginning */
+                                r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+                                if (r < 0)
+                                        return -errno;
+                                continue;
+                        }
+                }
+
+                if (copy) {
+                        acl_entry_t new_entry;
+
+                        if (acl_create_entry(&copy, &new_entry) < 0)
+                                return -errno;
+
+                        if (acl_copy_entry(new_entry, i) < 0)
+                                return -errno;
+
+                        if (modify)
+                                if (acl_set_qualifier(new_entry, &new_uid) < 0)
+                                        return -errno;
+                }
+
+                r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i);
+                if (r < 0)
+                        return -errno;
+        }
+
+        *ret = copy;
+        copy = NULL;
+
+        return !!*ret;
+}
+
+static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) {
+        _cleanup_(acl_freep) acl_t acl = NULL, shifted = NULL;
+        bool changed = false;
+        int r;
+
+        assert(fd >= 0);
+        assert(st);
+
+        /* ACLs are not supported on symlinks, there's no point in trying */
+        if (S_ISLNK(st->st_mode))
+                return 0;
+
+        r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl);
+        if (r == -EOPNOTSUPP)
+                return 0;
+        if (r < 0)
+                return r;
+
+        r = shift_acl(acl, shift, &shifted);
+        if (r < 0)
+                return r;
+        if (r > 0) {
+                r = set_acl(fd, name, ACL_TYPE_ACCESS, shifted);
+                if (r < 0)
+                        return r;
+
+                changed = true;
+        }
+
+        if (S_ISDIR(st->st_mode)) {
+                acl_free(acl);
+                acl_free(shifted);
+
+                acl = shifted = NULL;
+
+                r = get_acl(fd, name, ACL_TYPE_DEFAULT, &acl);
+                if (r < 0)
+                        return r;
+
+                r = shift_acl(acl, shift, &shifted);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        r = set_acl(fd, name, ACL_TYPE_DEFAULT, shifted);
+                        if (r < 0)
+                                return r;
+
+                        changed = true;
+                }
+        }
+
+        return changed;
+}
+
+#else
+
+static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) {
+        return 0;
+}
+
+#endif
+
+static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift) {
+        uid_t new_uid;
+        gid_t new_gid;
+        bool changed = false;
+        int r;
+
+        assert(fd >= 0);
+        assert(st);
+
+        new_uid =         shift | (st->st_uid & UINT32_C(0xFFFF));
+        new_gid = (gid_t) shift | (st->st_gid & UINT32_C(0xFFFF));
+
+        if (!uid_is_valid(new_uid) || !gid_is_valid(new_gid))
+                return -EINVAL;
+
+        if (st->st_uid != new_uid || st->st_gid != new_gid) {
+                if (name)
+                        r = fchownat(fd, name, new_uid, new_gid, AT_SYMLINK_NOFOLLOW);
+                else
+                        r = fchown(fd, new_uid, new_gid);
+                if (r < 0)
+                        return -errno;
+
+                /* The Linux kernel alters the mode in some cases of chown(). Let's undo this. */
+                if (name && !S_ISLNK(st->st_mode))
+                        r = fchmodat(fd, name, st->st_mode, 0);
+                else
+                        r = fchmod(fd, st->st_mode);
+                if (r < 0)
+                        return -errno;
+
+                changed = true;
+        }
+
+        r = patch_acls(fd, name, st, shift);
+        if (r < 0)
+                return r;
+
+        return r > 0 || changed;
+}
+
+static int is_procfs_sysfs_or_suchlike(int fd) {
+        struct statfs sfs;
+
+        assert(fd >= 0);
+
+        if (fstatfs(fd, &sfs) < 0)
+                return -errno;
+
+        return F_TYPE_EQUAL(sfs.f_type, BINFMTFS_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, CGROUP_SUPER_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, CGROUP2_SUPER_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, DEBUGFS_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, DEVPTS_SUPER_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, EFIVARFS_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, HUGETLBFS_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, MQUEUE_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, PROC_SUPER_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, PSTOREFS_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, SELINUX_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, SMACK_MAGIC) ||
+               F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC);
+}
+
+static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift, bool is_toplevel) {
+        bool changed = false;
+        int r;
+
+        assert(fd >= 0);
+
+        /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we
+         * probably shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's
+         * stop the recursion when we hit a procfs or sysfs file system. */
+        r = is_procfs_sysfs_or_suchlike(fd);
+        if (r < 0)
+                goto finish;
+        if (r > 0) {
+                r = 0; /* don't recurse */
+                goto finish;
+        }
+
+        r = patch_fd(fd, NULL, st, shift);
+        if (r == -EROFS) {
+                _cleanup_free_ char *name = NULL;
+
+                if (!is_toplevel) {
+                        /* When we hit a ready-only subtree we simply skip it, but log about it. */
+                        (void) fd_get_path(fd, &name);
+                        log_debug("Skippping read-only file or directory %s.", strna(name));
+                        r = 0;
+                }
+
+                goto finish;
+        }
+        if (r < 0)
+                goto finish;
+
+        if (S_ISDIR(st->st_mode)) {
+                _cleanup_closedir_ DIR *d = NULL;
+                struct dirent *de;
+
+                if (!donate_fd) {
+                        int copy;
+
+                        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+                        if (copy < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+
+                        fd = copy;
+                        donate_fd = true;
+                }
+
+                d = fdopendir(fd);
+                if (!d) {
+                        r = -errno;
+                        goto finish;
+                }
+                fd = -1;
+
+                FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
+                        struct stat fst;
+
+                        if (STR_IN_SET(de->d_name, ".", ".."))
+                                continue;
+
+                        if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) {
+                                r = -errno;
+                                goto finish;
+                        }
+
+                        if (S_ISDIR(fst.st_mode)) {
+                                int subdir_fd;
+
+                                subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+                                if (subdir_fd < 0) {
+                                        r = -errno;
+                                        goto finish;
+
+                                }
+
+                                r = recurse_fd(subdir_fd, true, &fst, shift, false);
+                                if (r < 0)
+                                        goto finish;
+                                if (r > 0)
+                                        changed = true;
+
+                        } else {
+                                r = patch_fd(dirfd(d), de->d_name, &fst, shift);
+                                if (r < 0)
+                                        goto finish;
+                                if (r > 0)
+                                        changed = true;
+                        }
+                }
+        }
+
+        r = changed;
+
+finish:
+        if (donate_fd)
+                safe_close(fd);
+
+        return r;
+}
+
+static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t range) {
+        struct stat st;
+        int r;
+
+        assert(fd >= 0);
+
+        /* Recursively adjusts the UID/GIDs of all files of a directory tree. This is used to automatically fix up an
+         * OS tree to the used user namespace UID range. Note that this automatic adjustment only works for UID ranges
+         * following the concept that the upper 16bit of a UID identify the container, and the lower 16bit are the actual
+         * UID within the container. */
+
+        if ((shift & 0xFFFF) != 0) {
+                /* We only support containers where the shift starts at a 2^16 boundary */
+                r = -EOPNOTSUPP;
+                goto finish;
+        }
+
+        if (range != 0x10000) {
+                /* We only support containers with 16bit UID ranges for the patching logic */
+                r = -EOPNOTSUPP;
+                goto finish;
+        }
+
+        if (fstat(fd, &st) < 0) {
+                r = -errno;
+                goto finish;
+        }
+
+        if ((uint32_t) st.st_uid >> 16 != (uint32_t) st.st_gid >> 16) {
+                /* We only support containers where the uid/gid container ID match */
+                r = -EBADE;
+                goto finish;
+        }
+
+        /* Try to detect if the range is already right. Of course, this a pretty drastic optimization, as we assume
+         * that if the top-level dir has the right upper 16bit assigned, then everything below will have too... */
+        if (((uint32_t) (st.st_uid ^ shift) >> 16) == 0)
+                return 0;
+
+        return recurse_fd(fd, donate_fd, &st, shift, true);
+
+finish:
+        if (donate_fd)
+                safe_close(fd);
+
+        return r;
+}
+
+int fd_patch_uid(int fd, uid_t shift, uid_t range) {
+        return fd_patch_uid_internal(fd, false, shift, range);
+}
+
+int path_patch_uid(const char *path, uid_t shift, uid_t range) {
+        int fd;
+
+        fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+        if (fd < 0)
+                return -errno;
+
+        return fd_patch_uid_internal(fd, true, shift, range);
+}
diff --git a/src/nspawn/nspawn-patch-uid.h b/src/nspawn/nspawn-patch-uid.h
new file mode 100644 (file)
index 0000000..55d0990
--- /dev/null
@@ -0,0 +1,23 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+
+int fd_patch_uid(int fd, uid_t shift, uid_t range);
+int path_patch_uid(const char *path, uid_t shift, uid_t range);
index 760861089d2dcc3fffdd8c6ea7afd4d880788044..20103c5e8873dd4140fe818ea822391e0a9f75fe 100644 (file)
@@ -20,6 +20,7 @@
 #include "sd-bus.h"
 
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "nspawn-register.h"
 #include "stat-util.h"
index 4fb005469813e4ca956265a0c81709be6950e7a9..b98a79fd0949386d336c06c70311bb2b6435c39c 100644 (file)
@@ -25,7 +25,9 @@
 #include "parse-util.h"
 #include "process-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
+#include "string-util.h"
 
 int settings_load(FILE *f, const char *path, Settings **ret) {
         _cleanup_(settings_freep) Settings *s = NULL;
@@ -40,9 +42,13 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
 
         s->start_mode = _START_MODE_INVALID;
         s->personality = PERSONALITY_INVALID;
+        s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
+        s->uid_shift = UID_INVALID;
+        s->uid_range = UID_INVALID;
 
         s->read_only = -1;
         s->volatile_mode = _VOLATILE_MODE_INVALID;
+        s->userns_chown = -1;
 
         s->private_network = -1;
         s->network_veth = -1;
@@ -59,6 +65,16 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
         if (r < 0)
                 return r;
 
+        /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
+         * both fields shall be initialized or neither. */
+        if (s->userns_mode == USER_NAMESPACE_PICK)
+                s->userns_chown = true;
+        else if (s->userns_mode != _USER_NAMESPACE_MODE_INVALID && s->userns_chown < 0)
+                s->userns_chown = false;
+
+        if (s->userns_chown >= 0 && s->userns_mode == _USER_NAMESPACE_MODE_INVALID)
+                s->userns_mode = USER_NAMESPACE_NO;
+
         *ret = s;
         s = NULL;
 
@@ -392,3 +408,73 @@ conflict:
         log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
         return 0;
 }
+
+int config_parse_private_users(
+                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) {
+
+        Settings *settings = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = parse_boolean(rvalue);
+        if (r == 0) {
+                /* no: User namespacing off */
+                settings->userns_mode = USER_NAMESPACE_NO;
+                settings->uid_shift = UID_INVALID;
+                settings->uid_range = UINT32_C(0x10000);
+        } else if (r > 0) {
+                /* yes: User namespacing on, UID range is read from root dir */
+                settings->userns_mode = USER_NAMESPACE_FIXED;
+                settings->uid_shift = UID_INVALID;
+                settings->uid_range = UINT32_C(0x10000);
+        } else if (streq(rvalue, "pick")) {
+                /* pick: User namespacing on, UID range is picked randomly */
+                settings->userns_mode = USER_NAMESPACE_PICK;
+                settings->uid_shift = UID_INVALID;
+                settings->uid_range = UINT32_C(0x10000);
+        } else {
+                const char *range, *shift;
+                uid_t sh, rn;
+
+                /* anything else: User namespacing on, UID range is explicitly configured */
+
+                range = strchr(rvalue, ':');
+                if (range) {
+                        shift = strndupa(rvalue, range - rvalue);
+                        range++;
+
+                        r = safe_atou32(range, &rn);
+                        if (r < 0 || rn <= 0) {
+                                log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
+                                return 0;
+                        }
+                } else {
+                        shift = rvalue;
+                        rn = UINT32_C(0x10000);
+                }
+
+                r = parse_uid(shift, &sh);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
+                        return 0;
+                }
+
+                settings->userns_mode = USER_NAMESPACE_FIXED;
+                settings->uid_shift = sh;
+                settings->uid_range = rn;
+        }
+
+        return 0;
+}
index a017405cd9816a678e4f6838319257c8b6a1c4d8..e12e91b886d73a6481dc4cee98c6d8c00974ada0 100644 (file)
@@ -33,6 +33,14 @@ typedef enum StartMode {
         _START_MODE_INVALID = -1
 } StartMode;
 
+typedef enum UserNamespaceMode {
+        USER_NAMESPACE_NO,
+        USER_NAMESPACE_FIXED,
+        USER_NAMESPACE_PICK,
+        _USER_NAMESPACE_MODE_MAX,
+        _USER_NAMESPACE_MODE_INVALID = -1,
+} UserNamespaceMode;
+
 typedef enum SettingsMask {
         SETTING_START_MODE        = 1 << 0,
         SETTING_ENVIRONMENT       = 1 << 1,
@@ -47,7 +55,8 @@ typedef enum SettingsMask {
         SETTING_VOLATILE_MODE     = 1 << 10,
         SETTING_CUSTOM_MOUNTS     = 1 << 11,
         SETTING_WORKING_DIRECTORY = 1 << 12,
-        _SETTINGS_MASK_ALL        = (1 << 13) -1
+        SETTING_USERNS            = 1 << 13,
+        _SETTINGS_MASK_ALL        = (1 << 14) -1
 } SettingsMask;
 
 typedef struct Settings {
@@ -62,12 +71,15 @@ typedef struct Settings {
         unsigned long personality;
         sd_id128_t machine_id;
         char *working_directory;
+        UserNamespaceMode userns_mode;
+        uid_t uid_shift, uid_range;
 
         /* [Image] */
         int read_only;
         VolatileMode volatile_mode;
         CustomMount *custom_mounts;
         unsigned n_custom_mounts;
+        int userns_chown;
 
         /* [Network] */
         int private_network;
@@ -99,3 +111,4 @@ int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, co
 int config_parse_veth_extra(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_boot(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_pid2(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_private_users(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 eb89916b7e1ea728fdd9d2d097088dbfea88c951..3fc6cc955cf8277abb2f79d51e34146fc986fab9 100644 (file)
@@ -22,7 +22,9 @@
 #endif
 #include <errno.h>
 #include <getopt.h>
+#include <grp.h>
 #include <linux/loop.h>
+#include <pwd.h>
 #include <sched.h>
 #ifdef HAVE_SECCOMP
 #include <seccomp.h>
@@ -64,6 +66,7 @@
 #include "hostname-util.h"
 #include "log.h"
 #include "loopback-setup.h"
+#include "machine-id-setup.h"
 #include "machine-image.h"
 #include "macro.h"
 #include "missing.h"
@@ -74,6 +77,7 @@
 #include "nspawn-expose-ports.h"
 #include "nspawn-mount.h"
 #include "nspawn-network.h"
+#include "nspawn-patch-uid.h"
 #include "nspawn-register.h"
 #include "nspawn-settings.h"
 #include "nspawn-setuid.h"
 #include "user-util.h"
 #include "util.h"
 
+/* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit
+ * UID range here */
+#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000))
+#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000))
+
 typedef enum ContainerStatus {
         CONTAINER_TERMINATED,
         CONTAINER_REBOOTED
@@ -172,8 +181,9 @@ static char *arg_image = NULL;
 static VolatileMode arg_volatile_mode = VOLATILE_NO;
 static ExposePort *arg_expose_ports = NULL;
 static char **arg_property = NULL;
+static UserNamespaceMode arg_userns_mode = USER_NAMESPACE_NO;
 static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
-static bool arg_userns = false;
+static bool arg_userns_chown = false;
 static int arg_kill_signal = 0;
 static bool arg_unified_cgroup_hierarchy = false;
 static SettingsMask arg_settings_mask = 0;
@@ -201,8 +211,10 @@ static void help(void) {
                "     --uuid=UUID            Set a specific machine UUID for the container\n"
                "  -S --slice=SLICE          Place the container in the specified slice\n"
                "     --property=NAME=VALUE  Set scope unit property\n"
+               "  -U --private-users=pick   Run within user namespace, pick UID/GID range automatically\n"
                "     --private-users[=UIDBASE[:NUIDS]]\n"
-               "                            Run within user namespace\n"
+               "                            Run within user namespace, user configured UID/GID range\n"
+               "     --private-user-chown   Adjust OS tree file ownership for private UID/GID range\n"
                "     --private-network      Disable network in container\n"
                "     --network-interface=INTERFACE\n"
                "                            Assign an existing network interface to the\n"
@@ -249,7 +261,7 @@ static void help(void) {
                "                            the container\n"
                "     --overlay-ro=PATH[:PATH...]:PATH\n"
                "                            Similar, but creates a read-only overlay mount\n"
-               "     --setenv=NAME=VALUE    Pass an environment variable to PID 1\n"
+               "  -E --setenv=NAME=VALUE    Pass an environment variable to PID 1\n"
                "     --share-system         Share system namespaces with host\n"
                "     --register=BOOLEAN     Register container as machine\n"
                "     --keep-unit            Do not register a scope for the machine, reuse\n"
@@ -271,9 +283,15 @@ static int custom_mounts_prepare(void) {
         for (i = 0; i < arg_n_custom_mounts; i++) {
                 CustomMount *m = &arg_custom_mounts[i];
 
-                if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) {
-                        log_error("--private-users with automatic UID shift may not be combined with custom root mounts.");
-                        return -EINVAL;
+                if (path_equal(m->destination, "/") && arg_userns_mode != USER_NAMESPACE_NO) {
+
+                        if (arg_userns_chown) {
+                                log_error("--private-users-chown may not be combined with custom root mounts.");
+                                return -EINVAL;
+                        } else if (arg_uid_shift == UID_INVALID) {
+                                log_error("--private-users with automatic UID shift may not be combined with custom root mounts.");
+                                return -EINVAL;
+                        }
                 }
 
                 if (m->type != CUSTOM_MOUNT_OVERLAY)
@@ -332,7 +350,6 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_TMPFS,
                 ARG_OVERLAY,
                 ARG_OVERLAY_RO,
-                ARG_SETENV,
                 ARG_SHARE_SYSTEM,
                 ARG_REGISTER,
                 ARG_KEEP_UNIT,
@@ -349,6 +366,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_KILL_SIGNAL,
                 ARG_SETTINGS,
                 ARG_CHDIR,
+                ARG_PRIVATE_USERS_CHOWN,
         };
 
         static const struct option options[] = {
@@ -373,7 +391,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "overlay-ro",            required_argument, NULL, ARG_OVERLAY_RO        },
                 { "machine",               required_argument, NULL, 'M'                   },
                 { "slice",                 required_argument, NULL, 'S'                   },
-                { "setenv",                required_argument, NULL, ARG_SETENV            },
+                { "setenv",                required_argument, NULL, 'E'                   },
                 { "selinux-context",       required_argument, NULL, 'Z'                   },
                 { "selinux-apifs-context", required_argument, NULL, 'L'                   },
                 { "quiet",                 no_argument,       NULL, 'q'                   },
@@ -392,6 +410,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "port",                  required_argument, NULL, 'p'                   },
                 { "property",              required_argument, NULL, ARG_PROPERTY          },
                 { "private-users",         optional_argument, NULL, ARG_PRIVATE_USERS     },
+                { "private-users-chown",   optional_argument, NULL, ARG_PRIVATE_USERS_CHOWN},
                 { "kill-signal",           required_argument, NULL, ARG_KILL_SIGNAL       },
                 { "settings",              required_argument, NULL, ARG_SETTINGS          },
                 { "chdir",                 required_argument, NULL, ARG_CHDIR             },
@@ -406,7 +425,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nU", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -710,7 +729,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_SETENV: {
+                case 'E': {
                         char **n;
 
                         if (!env_assignment_is_valid(optarg)) {
@@ -797,10 +816,29 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_PRIVATE_USERS:
-                        if (optarg) {
+
+                        r = optarg ? parse_boolean(optarg) : 1;
+                        if (r == 0) {
+                                /* no: User namespacing off */
+                                arg_userns_mode = USER_NAMESPACE_NO;
+                                arg_uid_shift = UID_INVALID;
+                                arg_uid_range = UINT32_C(0x10000);
+                        } else if (r > 0) {
+                                /* yes: User namespacing on, UID range is read from root dir */
+                                arg_userns_mode = USER_NAMESPACE_FIXED;
+                                arg_uid_shift = UID_INVALID;
+                                arg_uid_range = UINT32_C(0x10000);
+                        } else if (streq(optarg, "pick")) {
+                                /* pick: User namespacing on, UID range is picked randomly */
+                                arg_userns_mode = USER_NAMESPACE_PICK;
+                                arg_uid_shift = UID_INVALID;
+                                arg_uid_range = UINT32_C(0x10000);
+                        } else {
                                 _cleanup_free_ char *buffer = NULL;
                                 const char *range, *shift;
 
+                                /* anything else: User namespacing on, UID range is explicitly configured */
+
                                 range = strchr(optarg, ':');
                                 if (range) {
                                         buffer = strndup(optarg, range - optarg);
@@ -820,9 +858,28 @@ static int parse_argv(int argc, char *argv[]) {
                                         log_error("Failed to parse UID: %s", optarg);
                                         return -EINVAL;
                                 }
+
+                                arg_userns_mode = USER_NAMESPACE_FIXED;
                         }
 
-                        arg_userns = true;
+                        arg_settings_mask |= SETTING_USERNS;
+                        break;
+
+                case 'U':
+                        if (userns_supported()) {
+                                arg_userns_mode = USER_NAMESPACE_PICK;
+                                arg_uid_shift = UID_INVALID;
+                                arg_uid_range = UINT32_C(0x10000);
+
+                                arg_settings_mask |= SETTING_USERNS;
+                        }
+
+                        break;
+
+                case ARG_PRIVATE_USERS_CHOWN:
+                        arg_userns_chown = true;
+
+                        arg_settings_mask |= SETTING_USERNS;
                         break;
 
                 case ARG_KILL_SIGNAL:
@@ -893,6 +950,9 @@ static int parse_argv(int argc, char *argv[]) {
         if (arg_share_system)
                 arg_register = false;
 
+        if (arg_userns_mode == USER_NAMESPACE_PICK)
+                arg_userns_chown = true;
+
         if (arg_start_mode != START_PID1 && arg_share_system) {
                 log_error("--boot and --share-system may not be combined.");
                 return -EINVAL;
@@ -933,8 +993,15 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (arg_userns && access("/proc/self/uid_map", F_OK) < 0)
-                return log_error_errno(EOPNOTSUPP, "--private-users= is not supported, kernel compiled without user namespace support.");
+        if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported()) {
+                log_error("--private-users= is not supported, kernel compiled without user namespace support.");
+                return -EOPNOTSUPP;
+        }
+
+        if (arg_userns_chown && arg_read_only) {
+                log_error("--read-only and --private-users-chown may not be combined.");
+                return -EINVAL;
+        }
 
         if (argc > optind) {
                 arg_parameters = strv_copy(argv + optind);
@@ -993,7 +1060,7 @@ static int verify_arguments(void) {
 static int userns_lchown(const char *p, uid_t uid, gid_t gid) {
         assert(p);
 
-        if (!arg_userns)
+        if (arg_userns_mode == USER_NAMESPACE_NO)
                 return 0;
 
         if (uid == UID_INVALID && gid == GID_INVALID)
@@ -1375,11 +1442,11 @@ static int setup_hostname(void) {
 }
 
 static int setup_journal(const char *directory) {
-        sd_id128_t machine_id, this_id;
-        _cleanup_free_ char *b = NULL, *d = NULL;
-        const char *etc_machine_id, *p, *q;
+        sd_id128_t this_id;
+        _cleanup_free_ char *d = NULL;
+        const char *p, *q;
         bool try;
-        char *id;
+        char id[33];
         int r;
 
         /* Don't link journals in ephemeral mode */
@@ -1391,30 +1458,13 @@ static int setup_journal(const char *directory) {
 
         try = arg_link_journal_try || arg_link_journal == LINK_AUTO;
 
-        etc_machine_id = prefix_roota(directory, "/etc/machine-id");
-
-        r = read_one_line_file(etc_machine_id, &b);
-        if (r == -ENOENT && try)
-                return 0;
-        else if (r < 0)
-                return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
-
-        id = strstrip(b);
-        if (isempty(id) && try)
-                return 0;
-
-        /* Verify validity */
-        r = sd_id128_from_string(id, &machine_id);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
-
         r = sd_id128_get_machine(&this_id);
         if (r < 0)
                 return log_error_errno(r, "Failed to retrieve machine ID: %m");
 
-        if (sd_id128_equal(machine_id, this_id)) {
+        if (sd_id128_equal(arg_uuid, this_id)) {
                 log_full(try ? LOG_WARNING : LOG_ERR,
-                         "Host and machine ids are equal (%s): refusing to link journals", id);
+                         "Host and machine ids are equal (%s): refusing to link journals", sd_id128_to_string(arg_uuid, id));
                 if (try)
                         return 0;
                 return -EEXIST;
@@ -1432,6 +1482,8 @@ static int setup_journal(const char *directory) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create /var/log/journal: %m");
 
+        (void) sd_id128_to_string(arg_uuid, id);
+
         p = strjoina("/var/log/journal/", id);
         q = prefix_roota(directory, p);
 
@@ -1496,7 +1548,7 @@ static int setup_journal(const char *directory) {
         }
 
         if (arg_link_journal == LINK_HOST) {
-                /* don't create parents here -- if the host doesn't have
+                /* don't create parents here  if the host doesn't have
                  * permanent journal set up, don't force it here */
 
                 if (mkdir(p, 0755) < 0 && errno != EEXIST) {
@@ -2201,6 +2253,61 @@ static int mount_device(const char *what, const char *where, const char *directo
 #endif
 }
 
+static int setup_machine_id(const char *directory) {
+        int r;
+        const char *etc_machine_id, *t;
+        _cleanup_free_ char *s = NULL;
+
+        etc_machine_id = prefix_roota(directory, "/etc/machine-id");
+
+        r = read_one_line_file(etc_machine_id, &s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
+
+        t = strstrip(s);
+
+        if (!isempty(t)) {
+                r = sd_id128_from_string(t, &arg_uuid);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
+        } else {
+                if (sd_id128_is_null(arg_uuid)) {
+                        r = sd_id128_randomize(&arg_uuid);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to generate random machine ID: %m");
+                }
+        }
+
+        r = machine_id_setup(directory, arg_uuid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to setup machine ID: %m");
+
+        return 0;
+}
+
+static int recursive_chown(const char *directory, uid_t shift, uid_t range) {
+        int r;
+
+        assert(directory);
+
+        if (arg_userns_mode == USER_NAMESPACE_NO || !arg_userns_chown)
+                return 0;
+
+        r = path_patch_uid(directory, arg_uid_shift, arg_uid_range);
+        if (r == -EOPNOTSUPP)
+                return log_error_errno(r, "Automatic UID/GID adjusting is only supported for UID/GID ranges starting at multiples of 2^16 with a range of 2^16.");
+        if (r == -EBADE)
+                return log_error_errno(r, "Upper 16 bits of root directory UID and GID do not match.");
+        if (r < 0)
+                return log_error_errno(r, "Failed to adjust UID/GID shift of OS tree: %m");
+        if (r == 0)
+                log_debug("Root directory of image is already owned by the right UID/GID range, skipping recursive chown operation.");
+        else
+                log_debug("Patched directory tree to match UID/GID range.");
+
+        return r;
+}
+
 static int mount_devices(
                 const char *where,
                 const char *root_device, bool root_device_rw,
@@ -2418,7 +2525,7 @@ static int determine_names(void) {
 static int determine_uid_shift(const char *directory) {
         int r;
 
-        if (!arg_userns) {
+        if (arg_userns_mode == USER_NAMESPACE_NO) {
                 arg_uid_shift = 0;
                 return 0;
         }
@@ -2445,7 +2552,6 @@ static int determine_uid_shift(const char *directory) {
                 return -EINVAL;
         }
 
-        log_info("Using user namespaces with base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
         return 0;
 }
 
@@ -2458,6 +2564,7 @@ static int inner_child(
                 FDSet *fds) {
 
         _cleanup_free_ char *home = NULL;
+        char as_uuid[37];
         unsigned n_env = 1;
         const char *envp[] = {
                 "PATH=" DEFAULT_PATH_SPLIT_USR,
@@ -2481,7 +2588,7 @@ static int inner_child(
 
         cg_unified_flush();
 
-        if (arg_userns) {
+        if (arg_userns_mode != USER_NAMESPACE_NO) {
                 /* Tell the parent, that it now can write the UID map. */
                 (void) barrier_place(barrier); /* #1 */
 
@@ -2492,7 +2599,14 @@ static int inner_child(
                 }
         }
 
-        r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_all(NULL,
+                      arg_userns_mode != USER_NAMESPACE_NO,
+                      true,
+                      arg_private_network,
+                      arg_uid_shift,
+                      arg_uid_range,
+                      arg_selinux_apifs_context);
+
         if (r < 0)
                 return r;
 
@@ -2575,12 +2689,10 @@ static int inner_child(
             (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
                 return log_oom();
 
-        if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) {
-                char as_uuid[37];
+        assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL));
 
-                if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
-                        return log_oom();
-        }
+        if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
+                return log_oom();
 
         if (fdset_size(fds) > 0) {
                 r = fdset_cloexec(fds, false);
@@ -2648,7 +2760,8 @@ static int inner_child(
                 execvpe(arg_parameters[0], arg_parameters, env_use);
         else {
                 if (!arg_chdir)
-                        chdir(home ?: "/root");
+                        /* If we cannot change the directory, we'll end up in /, that is expected. */
+                        (void) chdir(home ?: "/root");
 
                 execle("/bin/bash", "-bash", NULL, env_use);
                 execle("/bin/sh", "-sh", NULL, env_use);
@@ -2669,6 +2782,7 @@ static int outer_child(
                 bool interactive,
                 bool secondary,
                 int pid_socket,
+                int uuid_socket,
                 int kmsg_socket,
                 int rtnl_socket,
                 int uid_shift_socket,
@@ -2682,6 +2796,7 @@ static int outer_child(
         assert(directory);
         assert(console);
         assert(pid_socket >= 0);
+        assert(uuid_socket >= 0);
         assert(kmsg_socket >= 0);
 
         cg_unified_flush();
@@ -2730,7 +2845,8 @@ static int outer_child(
         if (r < 0)
                 return r;
 
-        if (arg_userns) {
+        if (arg_userns_mode != USER_NAMESPACE_NO) {
+                /* Let the parent know which UID shift we read from the image */
                 l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL);
                 if (l < 0)
                         return log_error_errno(errno, "Failed to send UID shift: %m");
@@ -2738,17 +2854,49 @@ static int outer_child(
                         log_error("Short write while sending UID shift.");
                         return -EIO;
                 }
+
+                if (arg_userns_mode == USER_NAMESPACE_PICK) {
+                        /* When we are supposed to pick the UID shift, the parent will check now whether the UID shift
+                         * we just read from the image is available. If yes, it will send the UID shift back to us, if
+                         * not it will pick a different one, and send it back to us. */
+
+                        l = recv(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), 0);
+                        if (l < 0)
+                                return log_error_errno(errno, "Failed to recv UID shift: %m");
+                        if (l != sizeof(arg_uid_shift)) {
+                                log_error("Short read while recieving UID shift.");
+                                return -EIO;
+                        }
+                }
+
+                log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
         }
 
         /* Turn directory into bind mount */
         if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0)
                 return log_error_errno(errno, "Failed to make bind mount: %m");
 
-        r = setup_volatile(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context);
+        r = recursive_chown(directory, arg_uid_shift, arg_uid_range);
+        if (r < 0)
+                return r;
+
+        r = setup_volatile(
+                        directory,
+                        arg_volatile_mode,
+                        arg_userns_mode != USER_NAMESPACE_NO,
+                        arg_uid_shift,
+                        arg_uid_range,
+                        arg_selinux_context);
         if (r < 0)
                 return r;
 
-        r = setup_volatile_state(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context);
+        r = setup_volatile_state(
+                        directory,
+                        arg_volatile_mode,
+                        arg_userns_mode != USER_NAMESPACE_NO,
+                        arg_uid_shift,
+                        arg_uid_range,
+                        arg_selinux_context);
         if (r < 0)
                 return r;
 
@@ -2762,7 +2910,13 @@ static int outer_child(
                         return log_error_errno(r, "Failed to make tree read-only: %m");
         }
 
-        r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_all(directory,
+                      arg_userns_mode != USER_NAMESPACE_NO,
+                      false,
+                      arg_private_network,
+                      arg_uid_shift,
+                      arg_uid_range,
+                      arg_selinux_apifs_context);
         if (r < 0)
                 return r;
 
@@ -2796,15 +2950,32 @@ static int outer_child(
         if (r < 0)
                 return r;
 
+        r = setup_machine_id(directory);
+        if (r < 0)
+                return r;
+
         r = setup_journal(directory);
         if (r < 0)
                 return r;
 
-        r = mount_custom(directory, arg_custom_mounts, arg_n_custom_mounts, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_custom(
+                        directory,
+                        arg_custom_mounts,
+                        arg_n_custom_mounts,
+                        arg_userns_mode != USER_NAMESPACE_NO,
+                        arg_uid_shift,
+                        arg_uid_range,
+                        arg_selinux_apifs_context);
         if (r < 0)
                 return r;
 
-        r = mount_cgroups(directory, arg_unified_cgroup_hierarchy, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_cgroups(
+                        directory,
+                        arg_unified_cgroup_hierarchy,
+                        arg_userns_mode != USER_NAMESPACE_NO,
+                        arg_uid_shift,
+                        arg_uid_range,
+                        arg_selinux_apifs_context);
         if (r < 0)
                 return r;
 
@@ -2815,12 +2986,13 @@ static int outer_child(
         pid = raw_clone(SIGCHLD|CLONE_NEWNS|
                         (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) |
                         (arg_private_network ? CLONE_NEWNET : 0) |
-                        (arg_userns ? CLONE_NEWUSER : 0),
+                        (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0),
                         NULL);
         if (pid < 0)
                 return log_error_errno(errno, "Failed to fork inner child: %m");
         if (pid == 0) {
                 pid_socket = safe_close(pid_socket);
+                uuid_socket = safe_close(uuid_socket);
                 uid_shift_socket = safe_close(uid_shift_socket);
 
                 /* The inner child has all namespaces that are
@@ -2842,13 +3014,77 @@ static int outer_child(
                 return -EIO;
         }
 
+        l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNAL);
+        if (l < 0)
+                return log_error_errno(errno, "Failed to send machine ID: %m");
+        if (l != sizeof(arg_uuid)) {
+                log_error("Short write while sending machine ID.");
+                return -EIO;
+        }
+
         pid_socket = safe_close(pid_socket);
+        uuid_socket = safe_close(uuid_socket);
         kmsg_socket = safe_close(kmsg_socket);
         rtnl_socket = safe_close(rtnl_socket);
 
         return 0;
 }
 
+static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) {
+        unsigned n_tries = 100;
+        uid_t candidate;
+        int r;
+
+        assert(shift);
+        assert(ret_lock_file);
+        assert(arg_userns_mode == USER_NAMESPACE_PICK);
+        assert(arg_uid_range == 0x10000U);
+
+        candidate = *shift;
+
+        (void) mkdir("/run/systemd/nspawn-uid", 0755);
+
+        for (;;) {
+                char lock_path[strlen("/run/systemd/nspawn-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
+                _cleanup_release_lock_file_ LockFile lf = LOCK_FILE_INIT;
+
+                if (--n_tries <= 0)
+                        return -EBUSY;
+
+                if (candidate < UID_SHIFT_PICK_MIN || candidate > UID_SHIFT_PICK_MAX)
+                        goto next;
+                if ((candidate & UINT32_C(0xFFFF)) != 0)
+                        goto next;
+
+                xsprintf(lock_path, "/run/systemd/nspawn-uid/" UID_FMT, candidate);
+                r = make_lock_file(lock_path, LOCK_EX|LOCK_NB, &lf);
+                if (r == -EBUSY) /* Range already taken by another nspawn instance */
+                        goto next;
+                if (r < 0)
+                        return r;
+
+                /* Make some superficial checks whether the range is currently known in the user database */
+                if (getpwuid(candidate))
+                        goto next;
+                if (getpwuid(candidate + UINT32_C(0xFFFE)))
+                        goto next;
+                if (getgrgid(candidate))
+                        goto next;
+                if (getgrgid(candidate + UINT32_C(0xFFFE)))
+                        goto next;
+
+                *ret_lock_file = lf;
+                lf = (struct LockFile) LOCK_FILE_INIT;
+                *shift = candidate;
+                return 0;
+
+        next:
+                random_bytes(&candidate, sizeof(candidate));
+                candidate = (candidate % (UID_SHIFT_PICK_MAX - UID_SHIFT_PICK_MIN)) + UID_SHIFT_PICK_MIN;
+                candidate &= (uid_t) UINT32_C(0xFFFF0000);
+        }
+}
+
 static int setup_uid_map(pid_t pid) {
         char uid_map[strlen("/proc//uid_map") + DECIMAL_STR_MAX(uid_t) + 1], line[DECIMAL_STR_MAX(uid_t)*3+3+1];
         int r;
@@ -3080,6 +3316,19 @@ static int load_settings(void) {
                 }
         }
 
+        if ((arg_settings_mask & SETTING_USERNS) == 0 &&
+            settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", p);
+                else {
+                        arg_userns_mode = settings->userns_mode;
+                        arg_uid_shift = settings->uid_shift;
+                        arg_uid_range = settings->uid_range;
+                        arg_userns_chown = settings->userns_chown;
+                }
+        }
+
         return 0;
 }
 
@@ -3090,7 +3339,7 @@ int main(int argc, char *argv[]) {
         _cleanup_close_ int master = -1, image_fd = -1;
         _cleanup_fdset_free_ FDSet *fds = NULL;
         int r, n_fd_passed, loop_nr = -1;
-        char veth_name[IFNAMSIZ];
+        char veth_name[IFNAMSIZ] = "";
         bool secondary = false, remove_subvol = false;
         sigset_t mask_chld;
         pid_t pid = 0;
@@ -3318,19 +3567,42 @@ int main(int argc, char *argv[]) {
         }
 
         for (;;) {
-                _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
-                ContainerStatus container_status;
-                _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
                 static const struct sigaction sa = {
                         .sa_handler = nop_signal_handler,
                         .sa_flags = SA_NOCLDSTOP,
                 };
-                int ifi = 0;
-                ssize_t l;
+
+                _cleanup_release_lock_file_ LockFile uid_shift_lock = LOCK_FILE_INIT;
+                _cleanup_close_ int etc_passwd_lock = -1;
+                _cleanup_close_pair_ int
+                        kmsg_socket_pair[2] = { -1, -1 },
+                        rtnl_socket_pair[2] = { -1, -1 },
+                        pid_socket_pair[2] = { -1, -1 },
+                        uuid_socket_pair[2] = { -1, -1 },
+                        uid_shift_socket_pair[2] = { -1, -1 };
+                _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
                 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
                 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
                 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+                ContainerStatus container_status;
                 char last_char = 0;
+                int ifi = 0;
+                ssize_t l;
+
+                if (arg_userns_mode == USER_NAMESPACE_PICK) {
+                        /* When we shall pick the UID/GID range, let's first lock /etc/passwd, so that we can safely
+                         * check with getpwuid() if the specific user already exists. Note that /etc might be
+                         * read-only, in which case this will fail with EROFS. But that's really OK, as in that case we
+                         * can be reasonably sure that no users are going to be added. Note that getpwuid() checks are
+                         * really just an extra safety net. We kinda assume that the UID range we allocate from is
+                         * really ours. */
+
+                        etc_passwd_lock = take_etc_passwd_lock(NULL);
+                        if (etc_passwd_lock < 0 && etc_passwd_lock != -EROFS) {
+                                log_error_errno(r, "Failed to take /etc/passwd lock: %m");
+                                goto finish;
+                        }
+                }
 
                 r = barrier_create(&barrier);
                 if (r < 0) {
@@ -3353,7 +3625,12 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
-                if (arg_userns)
+                if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uuid_socket_pair) < 0) {
+                        r = log_error_errno(errno, "Failed to create id socket pair: %m");
+                        goto finish;
+                }
+
+                if (arg_userns_mode != USER_NAMESPACE_NO)
                         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
                                 r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
                                 goto finish;
@@ -3393,6 +3670,7 @@ int main(int argc, char *argv[]) {
                         kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
                         rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
                         pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
+                        uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
                         uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
 
                         (void) reset_all_signal_handlers();
@@ -3407,6 +3685,7 @@ int main(int argc, char *argv[]) {
                                         interactive,
                                         secondary,
                                         pid_socket_pair[1],
+                                        uuid_socket_pair[1],
                                         kmsg_socket_pair[1],
                                         rtnl_socket_pair[1],
                                         uid_shift_socket_pair[1],
@@ -3424,8 +3703,46 @@ int main(int argc, char *argv[]) {
                 kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
                 rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
                 pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
+                uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
                 uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
 
+                if (arg_userns_mode != USER_NAMESPACE_NO) {
+                        /* The child just let us know the UID shift it might have read from the image. */
+                        l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0);
+                        if (l < 0) {
+                                r = log_error_errno(errno, "Failed to read UID shift: %m");
+                                goto finish;
+                        }
+                        if (l != sizeof(arg_uid_shift)) {
+                                log_error("Short read while reading UID shift.");
+                                r = EIO;
+                                goto finish;
+                        }
+
+                        if (arg_userns_mode == USER_NAMESPACE_PICK) {
+                                /* If we are supposed to pick the UID shift, let's try to use the shift read from the
+                                 * image, but if that's already in use, pick a new one, and report back to the child,
+                                 * which one we now picked. */
+
+                                r = uid_shift_pick(&arg_uid_shift, &uid_shift_lock);
+                                if (r < 0) {
+                                        log_error_errno(r, "Failed to pick suitable UID/GID range: %m");
+                                        goto finish;
+                                }
+
+                                l = send(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL);
+                                if (l < 0) {
+                                        r = log_error_errno(errno, "Failed to send UID shift: %m");
+                                        goto finish;
+                                }
+                                if (l != sizeof(arg_uid_shift)) {
+                                        log_error("Short write while writing UID shift.");
+                                        r = -EIO;
+                                        goto finish;
+                                }
+                        }
+                }
+
                 /* Wait for the outer child. */
                 r = wait_for_terminate_and_warn("namespace helper", pid, NULL);
                 if (r < 0)
@@ -3448,26 +3765,27 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
+                /* We also retrieve container UUID in case it was generated by outer child */
+                l = recv(uuid_socket_pair[0], &arg_uuid, sizeof(arg_uuid), 0);
+                if (l < 0) {
+                        r = log_error_errno(errno, "Failed to read container machine ID: %m");
+                        goto finish;
+                }
+                if (l != sizeof(arg_uuid)) {
+                        log_error("Short read while reading container machined ID.");
+                        r = EIO;
+                        goto finish;
+                }
+
                 log_debug("Init process invoked as PID " PID_FMT, pid);
 
-                if (arg_userns) {
+                if (arg_userns_mode != USER_NAMESPACE_NO) {
                         if (!barrier_place_and_sync(&barrier)) { /* #1 */
                                 log_error("Child died too early.");
                                 r = -ESRCH;
                                 goto finish;
                         }
 
-                        l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0);
-                        if (l < 0) {
-                                r = log_error_errno(errno, "Failed to read UID shift: %m");
-                                goto finish;
-                        }
-                        if (l != sizeof(arg_uid_shift)) {
-                                log_error("Short read while reading UID shift.");
-                                r = EIO;
-                                goto finish;
-                        }
-
                         r = setup_uid_map(pid);
                         if (r < 0)
                                 goto finish;
@@ -3565,6 +3883,10 @@ int main(int argc, char *argv[]) {
                         goto finish;
                 }
 
+                /* At this point we have made use of the UID we picked, and thus nss-mymachines will make them appear
+                 * in getpwuid(), thus we can release the /etc/passwd lock. */
+                etc_passwd_lock = safe_close(etc_passwd_lock);
+
                 sd_notifyf(false,
                            "READY=1\n"
                            "STATUS=Container running.\n"
@@ -3659,6 +3981,7 @@ int main(int argc, char *argv[]) {
                 }
 
                 expose_port_flush(arg_expose_ports, &exposed);
+                (void) remove_veth_links(veth_name, arg_network_veth_extra);
         }
 
 finish:
@@ -3691,6 +4014,7 @@ finish:
         }
 
         expose_port_flush(arg_expose_ports, &exposed);
+        (void) remove_veth_links(veth_name, arg_network_veth_extra);
 
         free(arg_directory);
         free(arg_template);
diff --git a/src/nspawn/test-patch-uid.c b/src/nspawn/test-patch-uid.c
new file mode 100644 (file)
index 0000000..11c5321
--- /dev/null
@@ -0,0 +1,61 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "log.h"
+#include "nspawn-patch-uid.h"
+#include "user-util.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+        uid_t shift, range;
+        int r;
+
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+        log_open();
+
+        if (argc != 4) {
+                log_error("Expected PATH SHIFT RANGE parameters.");
+                return EXIT_FAILURE;
+        }
+
+        r = parse_uid(argv[2], &shift);
+        if (r < 0) {
+                log_error_errno(r, "Failed to parse UID shift %s.", argv[2]);
+                return EXIT_FAILURE;
+        }
+
+        r = parse_gid(argv[3], &range);
+        if (r < 0) {
+                log_error_errno(r, "Failed to parse UID range %s.", argv[3]);
+                return EXIT_FAILURE;
+        }
+
+        r = path_patch_uid(argv[1], shift, range);
+        if (r < 0) {
+                log_error_errno(r, "Failed to patch directory tree: %m");
+                return EXIT_FAILURE;
+        }
+
+        log_info("Changed: %s", yes_no(r));
+
+        return EXIT_SUCCESS;
+}
index 2536ad2898c440f5b696278816fdfa39be8e37bb..2b83d127b7ac228366dc7f3f2dddd7baa3d53da6 100644 (file)
@@ -127,7 +127,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
         memcpy(r_name, canonical, l+1);
         idx = ALIGN(l+1);
 
-        if (n_addresses <= 0) {
+        assert(n_addresses >= 0);
+        if (n_addresses == 0) {
                 /* Second, fill in IPv6 tuple */
                 r_tuple = (struct gaih_addrtuple*) (buffer + idx);
                 r_tuple->next = r_tuple_prev;
@@ -453,38 +454,33 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
         }
 
         n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
-        if (n_addresses > 0) {
-                for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
-                        if (af != a->family)
-                                continue;
+        for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+                if (af != a->family)
+                        continue;
 
-                        if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
-                                goto found;
-                }
+                if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
+                        goto found;
         }
 
         addresses = mfree(addresses);
 
         n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
-        if (n_addresses > 0) {
-                for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
-                        if (af != a->family)
-                                continue;
+        for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+                if (af != a->family)
+                        continue;
 
-                        if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
-                                canonical = "gateway";
-                                goto found;
-                        }
+                if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
+                        canonical = "gateway";
+                        goto found;
                 }
         }
 
         *errnop = ENOENT;
         *h_errnop = HOST_NOT_FOUND;
-
         return NSS_STATUS_NOTFOUND;
 
 found:
-        if (!canonical || (!additional && additional_from_hostname)) {
+        if (!canonical || additional_from_hostname) {
                 hn = gethostname_malloc();
                 if (!hn) {
                         *errnop = ENOMEM;
@@ -494,8 +490,7 @@ found:
 
                 if (!canonical)
                         canonical = hn;
-
-                if (!additional && additional_from_hostname)
+                else
                         additional = hn;
         }
 
index 0de6bd2241066501b07dc3d931d9030a28e2ce3f..5ce10f1cbd9788edd76061b20799fb573b854dba 100644 (file)
@@ -117,13 +117,6 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                 int *errnop, int *h_errnop,
                 int32_t *ttlp) {
 
-        enum nss_status (*fallback)(
-                        const char *name,
-                        struct gaih_addrtuple **pat,
-                        char *buffer, size_t buflen,
-                        int *errnop, int *h_errnop,
-                        int32_t *ttlp);
-
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
@@ -275,15 +268,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         return NSS_STATUS_SUCCESS;
 
 fallback:
-        fallback = (enum nss_status (*)(const char *name,
-                                        struct gaih_addrtuple **pat,
-                                        char *buffer, size_t buflen,
-                                        int *errnop, int *h_errnop,
-                                        int32_t *ttlp))
-                find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
+        {
+                _nss_gethostbyname4_r_t fallback;
+
+                fallback = (_nss_gethostbyname4_r_t)
+                        find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
 
-        if (fallback)
-                return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
+                if (fallback)
+                        return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
+        }
 
 fail:
         *errnop = -r;
@@ -300,15 +293,6 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 int32_t *ttlp,
                 char **canonp) {
 
-        enum nss_status (*fallback)(
-                        const char *name,
-                        int af,
-                        struct hostent *result,
-                        char *buffer, size_t buflen,
-                        int *errnop, int *h_errnop,
-                        int32_t *ttlp,
-                        char **canonp);
-
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char *r_name, *r_aliases, *r_addr, *r_addr_list;
@@ -480,16 +464,14 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         return NSS_STATUS_SUCCESS;
 
 fallback:
-        fallback = (enum nss_status (*)(const char *name,
-                                        int af,
-                                        struct hostent *result,
-                                        char *buffer, size_t buflen,
-                                        int *errnop, int *h_errnop,
-                                        int32_t *ttlp,
-                                        char **canonp))
-                find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
-        if (fallback)
-                return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+        {
+                _nss_gethostbyname3_r_t fallback;
+
+                fallback = (_nss_gethostbyname3_r_t)
+                        find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
+                if (fallback)
+                        return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+        }
 
 fail:
         *errnop = -r;
@@ -505,15 +487,6 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
                 int *errnop, int *h_errnop,
                 int32_t *ttlp) {
 
-        enum nss_status (*fallback)(
-                        const void* addr, socklen_t len,
-                        int af,
-                        struct hostent *result,
-                        char *buffer, size_t buflen,
-                        int *errnop, int *h_errnop,
-                        int32_t *ttlp);
-
-
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char *r_name, *r_aliases, *r_addr, *r_addr_list;
@@ -682,17 +655,15 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         return NSS_STATUS_SUCCESS;
 
 fallback:
-        fallback = (enum nss_status (*)(
-                                    const void* addr, socklen_t len,
-                                    int af,
-                                    struct hostent *result,
-                                    char *buffer, size_t buflen,
-                                    int *errnop, int *h_errnop,
-                                    int32_t *ttlp))
-                find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
-
-        if (fallback)
-                return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
+        {
+                _nss_gethostbyaddr2_r_t fallback;
+
+                fallback = (_nss_gethostbyaddr2_r_t)
+                        find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
+
+                if (fallback)
+                        return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
+        }
 
 fail:
         *errnop = -r;
index 22004a00cd62ad4a0086db5c2292d62db57c09a3..09c85f951820eaae3c6f106693c406b10dbb9f3d 100644 (file)
@@ -8,7 +8,7 @@ D = Comprehensively Implemented, by a dependency of resolved
 Y https://tools.ietf.org/html/rfc1034 → DOMAIN NAMES - CONCEPTS AND FACILITIES
 Y https://tools.ietf.org/html/rfc1035 → DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
 ? https://tools.ietf.org/html/rfc1101 → DNS Encoding of Network Names and Other Types
-Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts -- Application and Support
+Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts  Application and Support
 ~ https://tools.ietf.org/html/rfc1464 → Using the Domain Name System To Store Arbitrary String Attributes
 Y https://tools.ietf.org/html/rfc1536 → Common DNS Implementation Errors and Suggested Fixes
 Y https://tools.ietf.org/html/rfc1876 → A Means for Expressing Location Information in the Domain Name System
index 16cae8c1e599e1ac140fa77f2afcadffcf6aefc4..33f7c615576c94c0bd7b0675cd89f878bd826870 100644 (file)
@@ -424,8 +424,9 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
         if (added <= 0) {
                 _cleanup_free_ char *ip = NULL;
 
-                in_addr_to_string(q->request_family, &q->request_address, &ip);
-                r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
+                (void) in_addr_to_string(q->request_family, &q->request_address, &ip);
+                r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
+                                               "Address '%s' does not have any RR of requested type", strnull(ip));
                 goto finish;
         }
 
index 0af75514252f196ff8041d78fc821813ea57ee7e..a54aed3a63c7071d9bca2d475bbb9019dcaebbbc 100644 (file)
@@ -1734,7 +1734,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
         if (r <= 0)
                 return r;
 
-        wc = strjoina("*.", common_suffix, NULL);
+        wc = strjoina("*.", common_suffix);
         return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
 }
 
index a5129c201e09df4de6dcbea2b8ddb2af6b2c6274..081131ede0e63d83417423eb3501cc3945b0b404 100644 (file)
@@ -262,7 +262,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
         if (manager_our_packet(t->scope->manager, p) != 0)
                 return;
 
-        in_addr_to_string(p->family, &p->sender, &pretty);
+        (void) in_addr_to_string(p->family, &p->sender, &pretty);
 
         log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.",
                   t->id,
@@ -270,7 +270,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
                   dns_protocol_to_string(t->scope->protocol),
                   t->scope->link ? t->scope->link->name : "*",
                   af_to_name_short(t->scope->family),
-                  pretty);
+                  strnull(pretty));
 
         /* RFC 4795, Section 4.1 says that the peer with the
          * lexicographically smaller IP address loses */
index c5863b3aa240f75832caff66a8e6df1d5852ff54..b0dc65036d9e77e1e32081f66e59bb60b6771b09 100644 (file)
@@ -468,7 +468,7 @@ static void link_read_settings(Link *l) {
         }
         if (r > 0) {
 
-                /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */
+                /* If this link used to be managed, but is now unmanaged, flush all our settings  but only once. */
                 if (l->is_managed)
                         link_flush_settings(l);
 
index 540a612fdfc60a4ff8afa3c43e76ffabfff7313a..1d0f74ad219ba7a8b31da544be2dee4f14e6fb8d 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "alloc-util.h"
 #include "bus-error.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "calendarspec.h"
 #include "env-util.h"
@@ -103,7 +104,7 @@ static void help(void) {
                "     --uid=USER                   Run as system user\n"
                "     --gid=GROUP                  Run as system group\n"
                "     --nice=NICE                  Nice level\n"
-               "     --setenv=NAME=VALUE          Set environment\n"
+               "  -E --setenv=NAME=VALUE          Set environment\n"
                "  -t --pty                        Run service on pseudo tty\n"
                "  -q --quiet                      Suppress information messages during runtime\n\n"
                "Timer options:\n\n"
@@ -125,7 +126,6 @@ static int parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_VERSION = 0x100,
-                ARG_NO_ASK_PASSWORD,
                 ARG_USER,
                 ARG_SYSTEM,
                 ARG_SCOPE,
@@ -133,12 +133,10 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_DESCRIPTION,
                 ARG_SLICE,
                 ARG_SEND_SIGHUP,
+                ARG_SERVICE_TYPE,
                 ARG_EXEC_USER,
                 ARG_EXEC_GROUP,
-                ARG_SERVICE_TYPE,
                 ARG_NICE,
-                ARG_SETENV,
-                ARG_TTY,
                 ARG_ON_ACTIVE,
                 ARG_ON_BOOT,
                 ARG_ON_STARTUP,
@@ -147,6 +145,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ON_CALENDAR,
                 ARG_TIMER_PROPERTY,
                 ARG_NO_BLOCK,
+                ARG_NO_ASK_PASSWORD,
         };
 
         static const struct option options[] = {
@@ -166,9 +165,10 @@ static int parse_argv(int argc, char *argv[]) {
                 { "uid",               required_argument, NULL, ARG_EXEC_USER        },
                 { "gid",               required_argument, NULL, ARG_EXEC_GROUP       },
                 { "nice",              required_argument, NULL, ARG_NICE             },
-                { "setenv",            required_argument, NULL, ARG_SETENV           },
+                { "setenv",            required_argument, NULL, 'E'                  },
                 { "property",          required_argument, NULL, 'p'                  },
-                { "tty",               no_argument,       NULL, 't'                  },
+                { "tty",               no_argument,       NULL, 't'                  }, /* deprecated */
+                { "pty",               no_argument,       NULL, 't'                  },
                 { "quiet",             no_argument,       NULL, 'q'                  },
                 { "on-active",         required_argument, NULL, ARG_ON_ACTIVE        },
                 { "on-boot",           required_argument, NULL, ARG_ON_BOOT          },
@@ -266,7 +266,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_nice_set = true;
                         break;
 
-                case ARG_SETENV:
+                case 'E':
                         if (strv_extend(&arg_environment, optarg) < 0)
                                 return log_oom();
 
@@ -621,6 +621,10 @@ static int transient_scope_set_properties(sd_bus_message *m) {
         if (r < 0)
                 return r;
 
+        r = transient_cgroup_set_properties(m);
+        if (r < 0)
+                return r;
+
         r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
         if (r < 0)
                 return r;
@@ -878,7 +882,7 @@ static int start_transient_service(
                 (void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
 
                 if (!arg_quiet)
-                        log_info("Running as unit %s\nPress ^] three times within 1s to disconnect TTY.", service);
+                        log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service);
 
                 r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward);
                 if (r < 0)
@@ -896,7 +900,7 @@ static int start_transient_service(
                         fputc('\n', stdout);
 
         } else if (!arg_quiet)
-                log_info("Running as unit %s", service);
+                log_info("Running as unit: %s", service);
 
         return 0;
 }
@@ -1038,7 +1042,7 @@ static int start_transient_scope(
                 return r;
 
         if (!arg_quiet)
-                log_info("Running scope as unit %s", scope);
+                log_info("Running scope as unit: %s", scope);
 
         execvpe(argv[0], argv, env);
 
@@ -1189,9 +1193,9 @@ static int start_transient_timer(
         if (r < 0)
                 return r;
 
-        log_info("Running timer as unit %s", timer);
+        log_info("Running timer as unit: %s", timer);
         if (argv[0])
-                log_info("Will run service as unit %s", service);
+                log_info("Will run service as unit: %s", service);
 
         return 0;
 }
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
new file mode 100644 (file)
index 0000000..2b755ce
--- /dev/null
@@ -0,0 +1,1287 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "bus-internal.h"
+#include "bus-unit-util.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "env-util.h"
+#include "escape.h"
+#include "hashmap.h"
+#include "list.h"
+#include "locale-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "rlimit-util.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
+        assert(message);
+        assert(u);
+
+        u->machine = NULL;
+
+        return sd_bus_message_read(
+                        message,
+                        "(ssssssouso)",
+                        &u->id,
+                        &u->description,
+                        &u->load_state,
+                        &u->active_state,
+                        &u->sub_state,
+                        &u->following,
+                        &u->unit_path,
+                        &u->job_id,
+                        &u->job_type,
+                        &u->job_path);
+}
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
+        const char *eq, *field;
+        int r, rl;
+
+        assert(m);
+        assert(assignment);
+
+        eq = strchr(assignment, '=');
+        if (!eq) {
+                log_error("Not an assignment: %s", assignment);
+                return -EINVAL;
+        }
+
+        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        field = strndupa(assignment, eq - assignment);
+        eq++;
+
+        if (streq(field, "CPUQuota")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
+                else if (endswith(eq, "%")) {
+                        double percent;
+
+                        if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
+                                log_error("CPU quota '%s' invalid.", eq);
+                                return -EINVAL;
+                        }
+
+                        r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
+                } else {
+                        log_error("CPU quota needs to be in percent.");
+                        return -EINVAL;
+                }
+
+                goto finish;
+
+        } else if (streq(field, "EnvironmentFile")) {
+
+                r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
+                                          eq[0] == '-' ? eq + 1 : eq,
+                                          eq[0] == '-');
+                goto finish;
+
+        } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
+                char *n;
+                usec_t t;
+                size_t l;
+                r = parse_sec(eq, &t);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+
+                l = strlen(field);
+                n = newa(char, l + 2);
+                if (!n)
+                        return log_oom();
+
+                /* Change suffix Sec → USec */
+                strcpy(mempcpy(n, field, l - 3), "USec");
+                r = sd_bus_message_append(m, "sv", n, "t", t);
+                goto finish;
+        }
+
+        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        rl = rlimit_from_string(field);
+        if (rl >= 0) {
+                const char *sn;
+                struct rlimit l;
+
+                r = rlimit_parse(rl, eq, &l);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse resource limit: %s", eq);
+
+                r = sd_bus_message_append(m, "v", "t", l.rlim_max);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                sn = strjoina(field, "Soft");
+                r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
+
+        } else if (STR_IN_SET(field,
+                       "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
+                       "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
+                       "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
+                       "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+                       "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
+
+                r = parse_boolean(eq);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
+
+                r = sd_bus_message_append(m, "v", "b", r);
+
+        } else if (streq(field, "MemoryLimit")) {
+                uint64_t bytes;
+
+                if (isempty(eq) || streq(eq, "infinity"))
+                        bytes = (uint64_t) -1;
+                else {
+                        r = parse_size(eq, 1024, &bytes);
+                        if (r < 0) {
+                                log_error("Failed to parse bytes specification %s", assignment);
+                                return -EINVAL;
+                        }
+                }
+
+                r = sd_bus_message_append(m, "v", "t", bytes);
+
+        } else if (streq(field, "TasksMax")) {
+                uint64_t n;
+
+                if (isempty(eq) || streq(eq, "infinity"))
+                        n = (uint64_t) -1;
+                else {
+                        r = safe_atou64(eq, &n);
+                        if (r < 0) {
+                                log_error("Failed to parse maximum tasks specification %s", assignment);
+                                return -EINVAL;
+                        }
+                }
+
+                r = sd_bus_message_append(m, "v", "t", n);
+
+        } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
+                uint64_t u;
+
+                r = cg_cpu_shares_parse(eq, &u);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", u);
+
+        } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
+                uint64_t u;
+
+                r = cg_cpu_shares_parse(eq, &u);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", u);
+
+        } else if (STR_IN_SET(field,
+                              "User", "Group", "DevicePolicy", "KillMode",
+                              "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
+                              "StandardInput", "StandardOutput", "StandardError",
+                              "Description", "Slice", "Type", "WorkingDirectory",
+                              "RootDirectory", "SyslogIdentifier", "ProtectSystem",
+                              "ProtectHome"))
+                r = sd_bus_message_append(m, "v", "s", eq);
+
+        else if (streq(field, "SyslogLevel")) {
+                int level;
+
+                level = log_level_from_string(eq);
+                if (level < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", level);
+
+        } else if (streq(field, "SyslogFacility")) {
+                int facility;
+
+                facility = log_facility_unshifted_from_string(eq);
+                if (facility < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", facility);
+
+        } else if (streq(field, "DeviceAllow")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(ss)", 0);
+                else {
+                        const char *path, *rwm, *e;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                rwm = e+1;
+                        } else {
+                                path = eq;
+                                rwm = "";
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
+                }
+
+        } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(st)", 0);
+                else {
+                        const char *path, *bandwidth, *e;
+                        uint64_t bytes;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                bandwidth = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = parse_size(bandwidth, 1000, &bytes);
+                        if (r < 0) {
+                                log_error("Failed to parse byte value %s.", bandwidth);
+                                return -EINVAL;
+                        }
+
+                        r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
+                }
+
+        } else if (streq(field, "BlockIODeviceWeight")) {
+
+                if (isempty(eq))
+                        r = sd_bus_message_append(m, "v", "a(st)", 0);
+                else {
+                        const char *path, *weight, *e;
+                        uint64_t u;
+
+                        e = strchr(eq, ' ');
+                        if (e) {
+                                path = strndupa(eq, e - eq);
+                                weight = e+1;
+                        } else {
+                                log_error("Failed to parse %s value %s.", field, eq);
+                                return -EINVAL;
+                        }
+
+                        if (!path_startswith(path, "/dev")) {
+                                log_error("%s is not a device file in /dev.", path);
+                                return -EINVAL;
+                        }
+
+                        r = safe_atou64(weight, &u);
+                        if (r < 0) {
+                                log_error("Failed to parse %s value %s.", field, weight);
+                                return -EINVAL;
+                        }
+                        r = sd_bus_message_append(m, "v", "a(st)", path, u);
+                }
+
+        } else if (streq(field, "Nice")) {
+                int32_t i;
+
+                r = safe_atoi32(eq, &i);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", i);
+
+        } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
+                const char *p;
+
+                r = sd_bus_message_open_container(m, 'v', "as");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_open_container(m, 'a', "s");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                p = eq;
+
+                for (;;) {
+                        _cleanup_free_ char *word = NULL;
+
+                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
+                        if (r < 0) {
+                                log_error("Failed to parse Environment value %s", eq);
+                                return -EINVAL;
+                        }
+                        if (r == 0)
+                                break;
+
+                        if (streq(field, "Environment")) {
+                                if (!env_assignment_is_valid(word)) {
+                                        log_error("Invalid environment assignment: %s", word);
+                                        return -EINVAL;
+                                }
+                        } else {  /* PassEnvironment */
+                                if (!env_name_is_valid(word)) {
+                                        log_error("Invalid environment variable name: %s", word);
+                                        return -EINVAL;
+                                }
+                        }
+
+                        r = sd_bus_message_append_basic(m, 's', word);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_close_container(m);
+
+        } else if (streq(field, "KillSignal")) {
+                int sig;
+
+                sig = signal_from_string_try_harder(eq);
+                if (sig < 0) {
+                        log_error("Failed to parse %s value %s.", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", sig);
+
+        } else if (streq(field, "TimerSlackNSec")) {
+                nsec_t n;
+
+                r = parse_nsec(eq, &n);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", n);
+        } else if (streq(field, "OOMScoreAdjust")) {
+                int oa;
+
+                r = safe_atoi(eq, &oa);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s", field, eq);
+                        return -EINVAL;
+                }
+
+                if (!oom_score_adjust_is_valid(oa)) {
+                        log_error("OOM score adjust value out of range");
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "i", oa);
+        } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+                const char *p;
+
+                r = sd_bus_message_open_container(m, 'v', "as");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_open_container(m, 'a', "s");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                p = eq;
+
+                for (;;) {
+                        _cleanup_free_ char *word = NULL;
+                        int offset;
+
+                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+                        if (r < 0) {
+                                log_error("Failed to parse %s value %s", field, eq);
+                                return -EINVAL;
+                        }
+                        if (r == 0)
+                                break;
+
+                        if (!utf8_is_valid(word)) {
+                                log_error("Failed to parse %s value %s", field, eq);
+                                return -EINVAL;
+                        }
+
+                        offset = word[0] == '-';
+                        if (!path_is_absolute(word + offset)) {
+                                log_error("Failed to parse %s value %s", field, eq);
+                                return -EINVAL;
+                        }
+
+                        path_kill_slashes(word + offset);
+
+                        r = sd_bus_message_append_basic(m, 's', word);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_close_container(m);
+
+        } else if (streq(field, "RuntimeDirectory")) {
+                const char *p;
+
+                r = sd_bus_message_open_container(m, 'v', "as");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_open_container(m, 'a', "s");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                p = eq;
+
+                for (;;) {
+                        _cleanup_free_ char *word = NULL;
+
+                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+
+                        if (r == 0)
+                                break;
+
+                        r = sd_bus_message_append_basic(m, 's', word);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
+                r = sd_bus_message_close_container(m);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_close_container(m);
+
+        } else {
+                log_error("Unknown assignment %s.", assignment);
+                return -EINVAL;
+        }
+
+finish:
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_close_container(m);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return 0;
+}
+
+typedef struct BusWaitForJobs {
+        sd_bus *bus;
+        Set *jobs;
+
+        char *name;
+        char *result;
+
+        sd_bus_slot *slot_job_removed;
+        sd_bus_slot *slot_disconnected;
+} BusWaitForJobs;
+
+static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        assert(m);
+
+        log_error("Warning! D-Bus connection terminated.");
+        sd_bus_close(sd_bus_message_get_bus(m));
+
+        return 0;
+}
+
+static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        const char *path, *unit, *result;
+        BusWaitForJobs *d = userdata;
+        uint32_t id;
+        char *found;
+        int r;
+
+        assert(m);
+        assert(d);
+
+        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
+        if (r < 0) {
+                bus_log_parse_error(r);
+                return 0;
+        }
+
+        found = set_remove(d->jobs, (char*) path);
+        if (!found)
+                return 0;
+
+        free(found);
+
+        if (!isempty(result))
+                d->result = strdup(result);
+
+        if (!isempty(unit))
+                d->name = strdup(unit);
+
+        return 0;
+}
+
+void bus_wait_for_jobs_free(BusWaitForJobs *d) {
+        if (!d)
+                return;
+
+        set_free_free(d->jobs);
+
+        sd_bus_slot_unref(d->slot_disconnected);
+        sd_bus_slot_unref(d->slot_job_removed);
+
+        sd_bus_unref(d->bus);
+
+        free(d->name);
+        free(d->result);
+
+        free(d);
+}
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
+        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
+        int r;
+
+        assert(bus);
+        assert(ret);
+
+        d = new0(BusWaitForJobs, 1);
+        if (!d)
+                return -ENOMEM;
+
+        d->bus = sd_bus_ref(bus);
+
+        /* When we are a bus client we match by sender. Direct
+         * connections OTOH have no initialized sender field, and
+         * hence we ignore the sender then */
+        r = sd_bus_add_match(
+                        bus,
+                        &d->slot_job_removed,
+                        bus->bus_client ?
+                        "type='signal',"
+                        "sender='org.freedesktop.systemd1',"
+                        "interface='org.freedesktop.systemd1.Manager',"
+                        "member='JobRemoved',"
+                        "path='/org/freedesktop/systemd1'" :
+                        "type='signal',"
+                        "interface='org.freedesktop.systemd1.Manager',"
+                        "member='JobRemoved',"
+                        "path='/org/freedesktop/systemd1'",
+                        match_job_removed, d);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_add_match(
+                        bus,
+                        &d->slot_disconnected,
+                        "type='signal',"
+                        "sender='org.freedesktop.DBus.Local',"
+                        "interface='org.freedesktop.DBus.Local',"
+                        "member='Disconnected'",
+                        match_disconnected, d);
+        if (r < 0)
+                return r;
+
+        *ret = d;
+        d = NULL;
+
+        return 0;
+}
+
+static int bus_process_wait(sd_bus *bus) {
+        int r;
+
+        for (;;) {
+                r = sd_bus_process(bus, NULL);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        return 0;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
+        _cleanup_free_ char *dbus_path = NULL;
+
+        assert(d);
+        assert(d->name);
+        assert(result);
+
+        dbus_path = unit_dbus_path_from_name(d->name);
+        if (!dbus_path)
+                return -ENOMEM;
+
+        return sd_bus_get_property_string(d->bus,
+                                          "org.freedesktop.systemd1",
+                                          dbus_path,
+                                          "org.freedesktop.systemd1.Service",
+                                          "Result",
+                                          NULL,
+                                          result);
+}
+
+static const struct {
+        const char *result, *explanation;
+} explanations [] = {
+        { "resources",   "of unavailable resources or another system error" },
+        { "timeout",     "a timeout was exceeded" },
+        { "exit-code",   "the control process exited with error code" },
+        { "signal",      "a fatal signal was delivered to the control process" },
+        { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
+        { "watchdog",    "the service failed to send watchdog ping" },
+        { "start-limit", "start of the service was attempted too often" }
+};
+
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+        _cleanup_free_ char *service_shell_quoted = NULL;
+        const char *systemctl = "systemctl", *journalctl = "journalctl";
+
+        assert(service);
+
+        service_shell_quoted = shell_maybe_quote(service);
+
+        if (extra_args && extra_args[1]) {
+                _cleanup_free_ char *t;
+
+                t = strv_join((char**) extra_args, " ");
+                systemctl = strjoina("systemctl ", t ? : "<args>");
+                journalctl = strjoina("journalctl ", t ? : "<args>");
+        }
+
+        if (!isempty(result)) {
+                unsigned i;
+
+                for (i = 0; i < ELEMENTSOF(explanations); ++i)
+                        if (streq(result, explanations[i].result))
+                                break;
+
+                if (i < ELEMENTSOF(explanations)) {
+                        log_error("Job for %s failed because %s.\n"
+                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                                  service,
+                                  explanations[i].explanation,
+                                  systemctl,
+                                  service_shell_quoted ?: "<service>",
+                                  journalctl);
+                        goto finish;
+                }
+        }
+
+        log_error("Job for %s failed.\n"
+                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                  service,
+                  systemctl,
+                  service_shell_quoted ?: "<service>",
+                  journalctl);
+
+finish:
+        /* For some results maybe additional explanation is required */
+        if (streq_ptr(result, "start-limit"))
+                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
+                         "followed by \"%1$s start %2$s\" again.",
+                         systemctl,
+                         service_shell_quoted ?: "<service>");
+}
+
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        int r = 0;
+
+        assert(d->result);
+
+        if (!quiet) {
+                if (streq(d->result, "canceled"))
+                        log_error("Job for %s canceled.", strna(d->name));
+                else if (streq(d->result, "timeout"))
+                        log_error("Job for %s timed out.", strna(d->name));
+                else if (streq(d->result, "dependency"))
+                        log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
+                else if (streq(d->result, "invalid"))
+                        log_error("%s is not active, cannot reload.", strna(d->name));
+                else if (streq(d->result, "assert"))
+                        log_error("Assertion failed on job for %s.", strna(d->name));
+                else if (streq(d->result, "unsupported"))
+                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+                else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
+                        if (d->name) {
+                                int q;
+                                _cleanup_free_ char *result = NULL;
+
+                                q = bus_job_get_service_result(d, &result);
+                                if (q < 0)
+                                        log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
+
+                                log_job_error_with_service_result(d->name, result, extra_args);
+                        } else
+                                log_error("Job failed. See \"journalctl -xe\" for details.");
+                }
+        }
+
+        if (streq(d->result, "canceled"))
+                r = -ECANCELED;
+        else if (streq(d->result, "timeout"))
+                r = -ETIME;
+        else if (streq(d->result, "dependency"))
+                r = -EIO;
+        else if (streq(d->result, "invalid"))
+                r = -ENOEXEC;
+        else if (streq(d->result, "assert"))
+                r = -EPROTO;
+        else if (streq(d->result, "unsupported"))
+                r = -EOPNOTSUPP;
+        else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
+                r = -EIO;
+
+        return r;
+}
+
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        int r = 0;
+
+        assert(d);
+
+        while (!set_isempty(d->jobs)) {
+                int q;
+
+                q = bus_process_wait(d->bus);
+                if (q < 0)
+                        return log_error_errno(q, "Failed to wait for response: %m");
+
+                if (d->result) {
+                        q = check_wait_response(d, quiet, extra_args);
+                        /* Return the first error as it is most likely to be
+                         * meaningful. */
+                        if (q < 0 && r == 0)
+                                r = q;
+
+                        log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
+                }
+
+                d->name = mfree(d->name);
+                d->result = mfree(d->result);
+        }
+
+        return r;
+}
+
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
+        int r;
+
+        assert(d);
+
+        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
+        if (r < 0)
+                return r;
+
+        return set_put_strdup(d->jobs, path);
+}
+
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+        int r;
+
+        r = bus_wait_for_jobs_add(d, path);
+        if (r < 0)
+                return log_oom();
+
+        return bus_wait_for_jobs(d, quiet, NULL);
+}
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
+        const char *type, *path, *source;
+        int r;
+
+        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
+                /* We expect only "success" changes to be sent over the bus.
+                   Hence, reject anything negative. */
+                UnitFileChangeType ch = unit_file_change_type_from_string(type);
+
+                if (ch < 0) {
+                        log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
+                        continue;
+                }
+
+                r = unit_file_changes_add(changes, n_changes, ch, path, source);
+                if (r < 0)
+                        return r;
+        }
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        r = sd_bus_message_exit_container(m);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
+        return 0;
+}
+
+struct CGroupInfo {
+        char *cgroup_path;
+        bool is_const; /* If false, cgroup_path should be free()'d */
+
+        Hashmap *pids; /* PID → process name */
+        bool done;
+
+        struct CGroupInfo *parent;
+        LIST_FIELDS(struct CGroupInfo, siblings);
+        LIST_HEAD(struct CGroupInfo, children);
+        size_t n_children;
+};
+
+static bool IS_ROOT(const char *p) {
+        return isempty(p) || streq(p, "/");
+}
+
+static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
+        struct CGroupInfo *parent = NULL, *cg;
+        int r;
+
+        assert(cgroups);
+        assert(ret);
+
+        if (IS_ROOT(path))
+                path = "/";
+
+        cg = hashmap_get(cgroups, path);
+        if (cg) {
+                *ret = cg;
+                return 0;
+        }
+
+        if (!IS_ROOT(path)) {
+                const char *e, *pp;
+
+                e = strrchr(path, '/');
+                if (!e)
+                        return -EINVAL;
+
+                pp = strndupa(path, e - path);
+                if (!pp)
+                        return -ENOMEM;
+
+                r = add_cgroup(cgroups, pp, false, &parent);
+                if (r < 0)
+                        return r;
+        }
+
+        cg = new0(struct CGroupInfo, 1);
+        if (!cg)
+                return -ENOMEM;
+
+        if (is_const)
+                cg->cgroup_path = (char*) path;
+        else {
+                cg->cgroup_path = strdup(path);
+                if (!cg->cgroup_path) {
+                        free(cg);
+                        return -ENOMEM;
+                }
+        }
+
+        cg->is_const = is_const;
+        cg->parent = parent;
+
+        r = hashmap_put(cgroups, cg->cgroup_path, cg);
+        if (r < 0) {
+                if (!is_const)
+                        free(cg->cgroup_path);
+                free(cg);
+                return r;
+        }
+
+        if (parent) {
+                LIST_PREPEND(siblings, parent->children, cg);
+                parent->n_children++;
+        }
+
+        *ret = cg;
+        return 1;
+}
+
+static int add_process(
+                Hashmap *cgroups,
+                const char *path,
+                pid_t pid,
+                const char *name) {
+
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(cgroups);
+        assert(name);
+        assert(pid > 0);
+
+        r = add_cgroup(cgroups, path, true, &cg);
+        if (r < 0)
+                return r;
+
+        r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
+        if (r < 0)
+                return r;
+
+        return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
+}
+
+static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
+        assert(cgroups);
+        assert(cg);
+
+        while (cg->children)
+                remove_cgroup(cgroups, cg->children);
+
+        hashmap_remove(cgroups, cg->cgroup_path);
+
+        if (!cg->is_const)
+                free(cg->cgroup_path);
+
+        hashmap_free(cg->pids);
+
+        if (cg->parent)
+                LIST_REMOVE(siblings, cg->parent->children, cg);
+
+        free(cg);
+}
+
+static int cgroup_info_compare_func(const void *a, const void *b) {
+        const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b;
+
+        assert(x);
+        assert(y);
+
+        return strcmp(x->cgroup_path, y->cgroup_path);
+}
+
+static int dump_processes(
+                Hashmap *cgroups,
+                const char *cgroup_path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
+
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(prefix);
+
+        if (IS_ROOT(cgroup_path))
+                cgroup_path = "/";
+
+        cg = hashmap_get(cgroups, cgroup_path);
+        if (!cg)
+                return 0;
+
+        if (!hashmap_isempty(cg->pids)) {
+                const char *name;
+                size_t n = 0, i;
+                pid_t *pids;
+                void *pidp;
+                Iterator j;
+                int width;
+
+                /* Order processes by their PID */
+                pids = newa(pid_t, hashmap_size(cg->pids));
+
+                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
+                        pids[n++] = PTR_TO_PID(pidp);
+
+                assert(n == hashmap_size(cg->pids));
+                qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+
+                width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+                for (i = 0; i < n; i++) {
+                        _cleanup_free_ char *e = NULL;
+                        const char *special;
+                        bool more;
+
+                        name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
+                        assert(name);
+
+                        if (n_columns != 0) {
+                                unsigned k;
+
+                                k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+                                e = ellipsize(name, k, 100);
+                                if (e)
+                                        name = e;
+                        }
+
+                        more = i+1 < n || cg->children;
+                        special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT);
+
+                        fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
+                                prefix,
+                                special,
+                                width, pids[i],
+                                name);
+                }
+        }
+
+        if (cg->children) {
+                struct CGroupInfo **children, *child;
+                size_t n = 0, i;
+
+                /* Order subcgroups by their name */
+                children = newa(struct CGroupInfo*, cg->n_children);
+                LIST_FOREACH(siblings, child, cg->children)
+                        children[n++] = child;
+                assert(n == cg->n_children);
+                qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func);
+
+                n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
+
+                for (i = 0; i < n; i++) {
+                        _cleanup_free_ char *pp = NULL;
+                        const char *name, *special;
+                        bool more;
+
+                        child = children[i];
+
+                        name = strrchr(child->cgroup_path, '/');
+                        if (!name)
+                                return -EINVAL;
+                        name++;
+
+                        more = i+1 < n;
+                        special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT);
+
+                        fputs(prefix, stdout);
+                        fputs(special, stdout);
+                        fputs(name, stdout);
+                        fputc('\n', stdout);
+
+                        special = draw_special_char(more ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE);
+
+                        pp = strappend(prefix, special);
+                        if (!pp)
+                                return -ENOMEM;
+
+                        r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        cg->done = true;
+        return 0;
+}
+
+static int dump_extra_processes(
+                Hashmap *cgroups,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
+
+        _cleanup_free_ pid_t *pids = NULL;
+        _cleanup_hashmap_free_ Hashmap *names = NULL;
+        struct CGroupInfo *cg;
+        size_t n_allocated = 0, n = 0, k;
+        Iterator i;
+        int width, r;
+
+        /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
+         * combined, sorted, linear list. */
+
+        HASHMAP_FOREACH(cg, cgroups, i) {
+                const char *name;
+                void *pidp;
+                Iterator j;
+
+                if (cg->done)
+                        continue;
+
+                if (hashmap_isempty(cg->pids))
+                        continue;
+
+                r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
+                if (r < 0)
+                        return r;
+
+                if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
+                        return -ENOMEM;
+
+                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
+                        pids[n++] = PTR_TO_PID(pidp);
+
+                        r = hashmap_put(names, pidp, (void*) name);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (n == 0)
+                return 0;
+
+        qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+        width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+        for (k = 0; k < n; k++) {
+                _cleanup_free_ char *e = NULL;
+                const char *name;
+
+                name = hashmap_get(names, PID_TO_PTR(pids[k]));
+                assert(name);
+
+                if (n_columns != 0) {
+                        unsigned z;
+
+                        z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+                        e = ellipsize(name, z, 100);
+                        if (e)
+                                name = e;
+                }
+
+                fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
+                        prefix,
+                        draw_special_char(DRAW_TRIANGULAR_BULLET),
+                        width, pids[k],
+                        name);
+        }
+
+        return 0;
+}
+
+int unit_show_processes(
+                sd_bus *bus,
+                const char *unit,
+                const char *cgroup_path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags,
+                sd_bus_error *error) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        Hashmap *cgroups = NULL;
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(bus);
+        assert(unit);
+
+        if (flags & OUTPUT_FULL_WIDTH)
+                n_columns = 0;
+        else if (n_columns <= 0)
+                n_columns = columns();
+
+        prefix = strempty(prefix);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "GetUnitProcesses",
+                        error,
+                        &reply,
+                        "s",
+                        unit);
+        if (r < 0)
+                return r;
+
+        cgroups = hashmap_new(&string_hash_ops);
+        if (!cgroups)
+                return -ENOMEM;
+
+        r = sd_bus_message_enter_container(reply, 'a', "(sus)");
+        if (r < 0)
+                goto finish;
+
+        for (;;) {
+                const char *path = NULL, *name = NULL;
+                uint32_t pid;
+
+                r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
+                if (r < 0)
+                        goto finish;
+                if (r == 0)
+                        break;
+
+                r = add_process(cgroups, path, pid, name);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                goto finish;
+
+        r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
+        if (r < 0)
+                goto finish;
+
+        r = dump_extra_processes(cgroups, prefix, n_columns, flags);
+
+finish:
+        while ((cg = hashmap_first(cgroups)))
+               remove_cgroup(cgroups, cg);
+
+        hashmap_free(cgroups);
+
+        return r;
+}
diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h
new file mode 100644 (file)
index 0000000..c0c172f
--- /dev/null
@@ -0,0 +1,57 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "sd-bus.h"
+
+#include "output-mode.h"
+#include "install.h"
+
+typedef struct UnitInfo {
+        const char *machine;
+        const char *id;
+        const char *description;
+        const char *load_state;
+        const char *active_state;
+        const char *sub_state;
+        const char *following;
+        const char *unit_path;
+        uint32_t job_id;
+        const char *job_type;
+        const char *job_path;
+} UnitInfo;
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
+
+typedef struct BusWaitForJobs BusWaitForJobs;
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
+void bus_wait_for_jobs_free(BusWaitForJobs *d);
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
+
+int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);
index 90b312a1a7670773ae957e888f86833029a72026..4efbf3710f5855aac30e56c684221f231c33463f 100644 (file)
 #include "bus-label.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "cgroup-util.h"
 #include "def.h"
-#include "env-util.h"
 #include "escape.h"
-#include "extract-word.h"
 #include "fd-util.h"
-#include "hashmap.h"
-#include "install.h"
-#include "kdbus.h"
-#include "log.h"
-#include "macro.h"
 #include "missing.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "proc-cmdline.h"
-#include "process-util.h"
 #include "rlimit-util.h"
-#include "set.h"
-#include "signal-util.h"
 #include "stdio-util.h"
-#include "string-util.h"
 #include "strv.h"
-#include "syslog-util.h"
-#include "time-util.h"
-#include "unit-name.h"
 #include "user-util.h"
-#include "utf8.h"
-#include "util.h"
 
 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         sd_event *e = userdata;
@@ -712,7 +694,15 @@ int bus_connect_user_systemd(sd_bus **_bus) {
         return 0;
 }
 
-int bus_print_property(const char *name, sd_bus_message *property, bool all) {
+#define print_property(name, fmt, ...)                                  \
+        do {                                                            \
+                if (value)                                              \
+                        printf(fmt "\n", __VA_ARGS__);                  \
+                else                                                    \
+                        printf("%s=" fmt "\n", name, __VA_ARGS__);      \
+        } while(0)
+
+int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
         char type;
         const char *contents;
         int r;
@@ -740,7 +730,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         if (!escaped)
                                 return -ENOMEM;
 
-                        printf("%s=%s\n", name, escaped);
+                        print_property(name, "%s", escaped);
                 }
 
                 return 1;
@@ -753,7 +743,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                 if (r < 0)
                         return r;
 
-                printf("%s=%s\n", name, yes_no(b));
+                print_property(name, "%s", yes_no(b));
 
                 return 1;
         }
@@ -773,14 +763,14 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
 
                         t = format_timestamp(timestamp, sizeof(timestamp), u);
                         if (t || all)
-                                printf("%s=%s\n", name, strempty(t));
+                                print_property(name, "%s", strempty(t));
 
                 } else if (strstr(name, "USec")) {
                         char timespan[FORMAT_TIMESPAN_MAX];
 
-                        printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
+                        print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
                 } else
-                        printf("%s=%llu\n", name, (unsigned long long) u);
+                        print_property(name, "%"PRIu64, u);
 
                 return 1;
         }
@@ -792,7 +782,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                 if (r < 0)
                         return r;
 
-                printf("%s=%lld\n", name, (long long) i);
+                print_property(name, "%"PRIi64, i);
 
                 return 1;
         }
@@ -805,9 +795,9 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         return r;
 
                 if (strstr(name, "UMask") || strstr(name, "Mode"))
-                        printf("%s=%04o\n", name, u);
+                        print_property(name, "%04o", u);
                 else
-                        printf("%s=%u\n", name, (unsigned) u);
+                        print_property(name, "%"PRIu32, u);
 
                 return 1;
         }
@@ -819,7 +809,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                 if (r < 0)
                         return r;
 
-                printf("%s=%i\n", name, (int) i);
+                print_property(name, "%"PRIi32, i);
                 return 1;
         }
 
@@ -830,7 +820,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                 if (r < 0)
                         return r;
 
-                printf("%s=%g\n", name, d);
+                print_property(name, "%g", d);
                 return 1;
         }
 
@@ -846,7 +836,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
                                 _cleanup_free_ char *escaped = NULL;
 
-                                if (first)
+                                if (first && !value)
                                         printf("%s=", name);
 
                                 escaped = xescape(str, "\n ");
@@ -860,7 +850,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         if (r < 0)
                                 return r;
 
-                        if (first && all)
+                        if (first && all && !value)
                                 printf("%s=", name);
                         if (!first || all)
                                 puts("");
@@ -882,7 +872,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         if (all || n > 0) {
                                 unsigned int i;
 
-                                printf("%s=", name);
+                                if (!value)
+                                        printf("%s=", name);
 
                                 for (i = 0; i < n; i++)
                                         printf("%02x", u[i]);
@@ -903,7 +894,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
                         if (all || n > 0) {
                                 unsigned int i;
 
-                                printf("%s=", name);
+                                if (!value)
+                                        printf("%s=", name);
 
                                 for (i = 0; i < n; i++)
                                         printf("%08x", u[i]);
@@ -920,7 +912,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
         return 0;
 }
 
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
+int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
@@ -960,7 +952,7 @@ int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, ch
                         if (r < 0)
                                 return r;
 
-                        r = bus_print_property(name, reply, all);
+                        r = bus_print_property(name, reply, value, all);
                         if (r < 0)
                                 return r;
                         if (r == 0) {
@@ -1068,7 +1060,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
         }
 
         case SD_BUS_TYPE_UINT32: {
-                uint64_t u;
+                uint32_t u;
                 uint32_t *p = userdata;
 
                 r = sd_bus_message_read_basic(m, type, &u);
@@ -1373,844 +1365,6 @@ int bus_log_create_error(int r) {
         return log_error_errno(r, "Failed to create bus message: %m");
 }
 
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
-        assert(message);
-        assert(u);
-
-        u->machine = NULL;
-
-        return sd_bus_message_read(
-                        message,
-                        "(ssssssouso)",
-                        &u->id,
-                        &u->description,
-                        &u->load_state,
-                        &u->active_state,
-                        &u->sub_state,
-                        &u->following,
-                        &u->unit_path,
-                        &u->job_id,
-                        &u->job_type,
-                        &u->job_path);
-}
-
-int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
-        const char *eq, *field;
-        int r, rl;
-
-        assert(m);
-        assert(assignment);
-
-        eq = strchr(assignment, '=');
-        if (!eq) {
-                log_error("Not an assignment: %s", assignment);
-                return -EINVAL;
-        }
-
-        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        field = strndupa(assignment, eq - assignment);
-        eq++;
-
-        if (streq(field, "CPUQuota")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
-                else if (endswith(eq, "%")) {
-                        double percent;
-
-                        if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
-                                log_error("CPU quota '%s' invalid.", eq);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
-                } else {
-                        log_error("CPU quota needs to be in percent.");
-                        return -EINVAL;
-                }
-
-                goto finish;
-
-        } else if (streq(field, "EnvironmentFile")) {
-
-                r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
-                                          eq[0] == '-' ? eq + 1 : eq,
-                                          eq[0] == '-');
-                goto finish;
-
-        } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
-                char *n;
-                usec_t t;
-                size_t l;
-                r = parse_sec(eq, &t);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
-
-                l = strlen(field);
-                n = newa(char, l + 2);
-                if (!n)
-                        return log_oom();
-
-                /* Change suffix Sec → USec */
-                strcpy(mempcpy(n, field, l - 3), "USec");
-                r = sd_bus_message_append(m, "sv", n, "t", t);
-                goto finish;
-        }
-
-        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        rl = rlimit_from_string(field);
-        if (rl >= 0) {
-                const char *sn;
-                struct rlimit l;
-
-                r = rlimit_parse(rl, eq, &l);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse resource limit: %s", eq);
-
-                r = sd_bus_message_append(m, "v", "t", l.rlim_max);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                sn = strjoina(field, "Soft");
-                r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
-
-        } else if (STR_IN_SET(field,
-                       "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
-                       "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
-                       "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
-                       "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
-                       "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
-
-                r = parse_boolean(eq);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
-
-                r = sd_bus_message_append(m, "v", "b", r);
-
-        } else if (streq(field, "MemoryLimit")) {
-                uint64_t bytes;
-
-                if (isempty(eq) || streq(eq, "infinity"))
-                        bytes = (uint64_t) -1;
-                else {
-                        r = parse_size(eq, 1024, &bytes);
-                        if (r < 0) {
-                                log_error("Failed to parse bytes specification %s", assignment);
-                                return -EINVAL;
-                        }
-                }
-
-                r = sd_bus_message_append(m, "v", "t", bytes);
-
-        } else if (streq(field, "TasksMax")) {
-                uint64_t n;
-
-                if (isempty(eq) || streq(eq, "infinity"))
-                        n = (uint64_t) -1;
-                else {
-                        r = safe_atou64(eq, &n);
-                        if (r < 0) {
-                                log_error("Failed to parse maximum tasks specification %s", assignment);
-                                return -EINVAL;
-                        }
-                }
-
-                r = sd_bus_message_append(m, "v", "t", n);
-
-        } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
-                uint64_t u;
-
-                r = cg_cpu_shares_parse(eq, &u);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", u);
-
-        } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
-                uint64_t u;
-
-                r = cg_cpu_shares_parse(eq, &u);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", u);
-
-        } else if (STR_IN_SET(field,
-                              "User", "Group", "DevicePolicy", "KillMode",
-                              "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
-                              "StandardInput", "StandardOutput", "StandardError",
-                              "Description", "Slice", "Type", "WorkingDirectory",
-                              "RootDirectory", "SyslogIdentifier", "ProtectSystem",
-                              "ProtectHome"))
-                r = sd_bus_message_append(m, "v", "s", eq);
-
-        else if (streq(field, "SyslogLevel")) {
-                int level;
-
-                level = log_level_from_string(eq);
-                if (level < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "i", level);
-
-        } else if (streq(field, "SyslogFacility")) {
-                int facility;
-
-                facility = log_facility_unshifted_from_string(eq);
-                if (facility < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "i", facility);
-
-        } else if (streq(field, "DeviceAllow")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(ss)", 0);
-                else {
-                        const char *path, *rwm, *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                rwm = e+1;
-                        } else {
-                                path = eq;
-                                rwm = "";
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
-                }
-
-        } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *bandwidth, *e;
-                        uint64_t bytes;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                bandwidth = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = parse_size(bandwidth, 1000, &bytes);
-                        if (r < 0) {
-                                log_error("Failed to parse byte value %s.", bandwidth);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
-                }
-
-        } else if (streq(field, "BlockIODeviceWeight")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *weight, *e;
-                        uint64_t u;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                weight = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = safe_atou64(weight, &u);
-                        if (r < 0) {
-                                log_error("Failed to parse %s value %s.", field, weight);
-                                return -EINVAL;
-                        }
-                        r = sd_bus_message_append(m, "v", "a(st)", path, u);
-                }
-
-        } else if (streq(field, "Nice")) {
-                int32_t i;
-
-                r = safe_atoi32(eq, &i);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "i", i);
-
-        } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
-                const char *p;
-
-                r = sd_bus_message_open_container(m, 'v', "as");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_open_container(m, 'a', "s");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                p = eq;
-
-                for (;;) {
-                        _cleanup_free_ char *word = NULL;
-
-                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
-                        if (r < 0) {
-                                log_error("Failed to parse Environment value %s", eq);
-                                return -EINVAL;
-                        }
-                        if (r == 0)
-                                break;
-
-                        if (streq(field, "Environment")) {
-                                if (!env_assignment_is_valid(word)) {
-                                        log_error("Invalid environment assignment: %s", word);
-                                        return -EINVAL;
-                                }
-                        } else {  /* PassEnvironment */
-                                if (!env_name_is_valid(word)) {
-                                        log_error("Invalid environment variable name: %s", word);
-                                        return -EINVAL;
-                                }
-                        }
-
-                        r = sd_bus_message_append_basic(m, 's', word);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_close_container(m);
-
-        } else if (streq(field, "KillSignal")) {
-                int sig;
-
-                sig = signal_from_string_try_harder(eq);
-                if (sig < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "i", sig);
-
-        } else if (streq(field, "TimerSlackNSec")) {
-                nsec_t n;
-
-                r = parse_nsec(eq, &n);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", n);
-        } else if (streq(field, "OOMScoreAdjust")) {
-                int oa;
-
-                r = safe_atoi(eq, &oa);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s", field, eq);
-                        return -EINVAL;
-                }
-
-                if (!oom_score_adjust_is_valid(oa)) {
-                        log_error("OOM score adjust value out of range");
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "i", oa);
-        } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
-                const char *p;
-
-                r = sd_bus_message_open_container(m, 'v', "as");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_open_container(m, 'a', "s");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                p = eq;
-
-                for (;;) {
-                        _cleanup_free_ char *word = NULL;
-                        int offset;
-
-                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
-                        if (r < 0) {
-                                log_error("Failed to parse %s value %s", field, eq);
-                                return -EINVAL;
-                        }
-                        if (r == 0)
-                                break;
-
-                        if (!utf8_is_valid(word)) {
-                                log_error("Failed to parse %s value %s", field, eq);
-                                return -EINVAL;
-                        }
-
-                        offset = word[0] == '-';
-                        if (!path_is_absolute(word + offset)) {
-                                log_error("Failed to parse %s value %s", field, eq);
-                                return -EINVAL;
-                        }
-
-                        path_kill_slashes(word + offset);
-
-                        r = sd_bus_message_append_basic(m, 's', word);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_close_container(m);
-
-        } else if (streq(field, "RuntimeDirectory")) {
-                const char *p;
-
-                r = sd_bus_message_open_container(m, 'v', "as");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_open_container(m, 'a', "s");
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                p = eq;
-
-                for (;;) {
-                        _cleanup_free_ char *word = NULL;
-
-                        r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to parse %s value %s", field, eq);
-
-                        if (r == 0)
-                                break;
-
-                        r = sd_bus_message_append_basic(m, 's', word);
-                        if (r < 0)
-                                return bus_log_create_error(r);
-                }
-
-                r = sd_bus_message_close_container(m);
-                if (r < 0)
-                        return bus_log_create_error(r);
-
-                r = sd_bus_message_close_container(m);
-
-        } else {
-                log_error("Unknown assignment %s.", assignment);
-                return -EINVAL;
-        }
-
-finish:
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        r = sd_bus_message_close_container(m);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        return 0;
-}
-
-typedef struct BusWaitForJobs {
-        sd_bus *bus;
-        Set *jobs;
-
-        char *name;
-        char *result;
-
-        sd_bus_slot *slot_job_removed;
-        sd_bus_slot *slot_disconnected;
-} BusWaitForJobs;
-
-static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        assert(m);
-
-        log_error("Warning! D-Bus connection terminated.");
-        sd_bus_close(sd_bus_message_get_bus(m));
-
-        return 0;
-}
-
-static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        const char *path, *unit, *result;
-        BusWaitForJobs *d = userdata;
-        uint32_t id;
-        char *found;
-        int r;
-
-        assert(m);
-        assert(d);
-
-        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
-        if (r < 0) {
-                bus_log_parse_error(r);
-                return 0;
-        }
-
-        found = set_remove(d->jobs, (char*) path);
-        if (!found)
-                return 0;
-
-        free(found);
-
-        if (!isempty(result))
-                d->result = strdup(result);
-
-        if (!isempty(unit))
-                d->name = strdup(unit);
-
-        return 0;
-}
-
-void bus_wait_for_jobs_free(BusWaitForJobs *d) {
-        if (!d)
-                return;
-
-        set_free_free(d->jobs);
-
-        sd_bus_slot_unref(d->slot_disconnected);
-        sd_bus_slot_unref(d->slot_job_removed);
-
-        sd_bus_unref(d->bus);
-
-        free(d->name);
-        free(d->result);
-
-        free(d);
-}
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
-        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
-        int r;
-
-        assert(bus);
-        assert(ret);
-
-        d = new0(BusWaitForJobs, 1);
-        if (!d)
-                return -ENOMEM;
-
-        d->bus = sd_bus_ref(bus);
-
-        /* When we are a bus client we match by sender. Direct
-         * connections OTOH have no initialized sender field, and
-         * hence we ignore the sender then */
-        r = sd_bus_add_match(
-                        bus,
-                        &d->slot_job_removed,
-                        bus->bus_client ?
-                        "type='signal',"
-                        "sender='org.freedesktop.systemd1',"
-                        "interface='org.freedesktop.systemd1.Manager',"
-                        "member='JobRemoved',"
-                        "path='/org/freedesktop/systemd1'" :
-                        "type='signal',"
-                        "interface='org.freedesktop.systemd1.Manager',"
-                        "member='JobRemoved',"
-                        "path='/org/freedesktop/systemd1'",
-                        match_job_removed, d);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_add_match(
-                        bus,
-                        &d->slot_disconnected,
-                        "type='signal',"
-                        "sender='org.freedesktop.DBus.Local',"
-                        "interface='org.freedesktop.DBus.Local',"
-                        "member='Disconnected'",
-                        match_disconnected, d);
-        if (r < 0)
-                return r;
-
-        *ret = d;
-        d = NULL;
-
-        return 0;
-}
-
-static int bus_process_wait(sd_bus *bus) {
-        int r;
-
-        for (;;) {
-                r = sd_bus_process(bus, NULL);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        return 0;
-
-                r = sd_bus_wait(bus, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
-        _cleanup_free_ char *dbus_path = NULL;
-
-        assert(d);
-        assert(d->name);
-        assert(result);
-
-        dbus_path = unit_dbus_path_from_name(d->name);
-        if (!dbus_path)
-                return -ENOMEM;
-
-        return sd_bus_get_property_string(d->bus,
-                                          "org.freedesktop.systemd1",
-                                          dbus_path,
-                                          "org.freedesktop.systemd1.Service",
-                                          "Result",
-                                          NULL,
-                                          result);
-}
-
-static const struct {
-        const char *result, *explanation;
-} explanations [] = {
-        { "resources",   "a configured resource limit was exceeded" },
-        { "timeout",     "a timeout was exceeded" },
-        { "exit-code",   "the control process exited with error code" },
-        { "signal",      "a fatal signal was delivered to the control process" },
-        { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
-        { "watchdog",    "the service failed to send watchdog ping" },
-        { "start-limit", "start of the service was attempted too often" }
-};
-
-static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
-        _cleanup_free_ char *service_shell_quoted = NULL;
-        const char *systemctl = "systemctl", *journalctl = "journalctl";
-
-        assert(service);
-
-        service_shell_quoted = shell_maybe_quote(service);
-
-        if (extra_args && extra_args[1]) {
-                _cleanup_free_ char *t;
-
-                t = strv_join((char**) extra_args, " ");
-                systemctl = strjoina("systemctl ", t ?: "<args>", NULL);
-                journalctl = strjoina("journalctl ", t ?: "<args>", NULL);
-        }
-
-        if (!isempty(result)) {
-                unsigned i;
-
-                for (i = 0; i < ELEMENTSOF(explanations); ++i)
-                        if (streq(result, explanations[i].result))
-                                break;
-
-                if (i < ELEMENTSOF(explanations)) {
-                        log_error("Job for %s failed because %s.\n"
-                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                                  service,
-                                  explanations[i].explanation,
-                                  systemctl,
-                                  service_shell_quoted ?: "<service>",
-                                  journalctl);
-                        goto finish;
-                }
-        }
-
-        log_error("Job for %s failed.\n"
-                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                  service,
-                  systemctl,
-                  service_shell_quoted ?: "<service>",
-                  journalctl);
-
-finish:
-        /* For some results maybe additional explanation is required */
-        if (streq_ptr(result, "start-limit"))
-                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
-                         "followed by \"%1$s start %2$s\" again.",
-                         systemctl,
-                         service_shell_quoted ?: "<service>");
-}
-
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        int r = 0;
-
-        assert(d->result);
-
-        if (!quiet) {
-                if (streq(d->result, "canceled"))
-                        log_error("Job for %s canceled.", strna(d->name));
-                else if (streq(d->result, "timeout"))
-                        log_error("Job for %s timed out.", strna(d->name));
-                else if (streq(d->result, "dependency"))
-                        log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
-                else if (streq(d->result, "invalid"))
-                        log_error("%s is not active, cannot reload.", strna(d->name));
-                else if (streq(d->result, "assert"))
-                        log_error("Assertion failed on job for %s.", strna(d->name));
-                else if (streq(d->result, "unsupported"))
-                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
-                else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
-                        if (d->name) {
-                                int q;
-                                _cleanup_free_ char *result = NULL;
-
-                                q = bus_job_get_service_result(d, &result);
-                                if (q < 0)
-                                        log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
-
-                                log_job_error_with_service_result(d->name, result, extra_args);
-                        } else
-                                log_error("Job failed. See \"journalctl -xe\" for details.");
-                }
-        }
-
-        if (streq(d->result, "canceled"))
-                r = -ECANCELED;
-        else if (streq(d->result, "timeout"))
-                r = -ETIME;
-        else if (streq(d->result, "dependency"))
-                r = -EIO;
-        else if (streq(d->result, "invalid"))
-                r = -ENOEXEC;
-        else if (streq(d->result, "assert"))
-                r = -EPROTO;
-        else if (streq(d->result, "unsupported"))
-                r = -EOPNOTSUPP;
-        else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
-                r = -EIO;
-
-        return r;
-}
-
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        int r = 0;
-
-        assert(d);
-
-        while (!set_isempty(d->jobs)) {
-                int q;
-
-                q = bus_process_wait(d->bus);
-                if (q < 0)
-                        return log_error_errno(q, "Failed to wait for response: %m");
-
-                if (d->result) {
-                        q = check_wait_response(d, quiet, extra_args);
-                        /* Return the first error as it is most likely to be
-                         * meaningful. */
-                        if (q < 0 && r == 0)
-                                r = q;
-
-                        log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
-                }
-
-                d->name = mfree(d->name);
-                d->result = mfree(d->result);
-        }
-
-        return r;
-}
-
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
-        int r;
-
-        assert(d);
-
-        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        return set_put_strdup(d->jobs, path);
-}
-
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
-        int r;
-
-        r = bus_wait_for_jobs_add(d, path);
-        if (r < 0)
-                return log_oom();
-
-        return bus_wait_for_jobs(d, quiet, NULL);
-}
-
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
-        const char *type, *path, *source;
-        int r;
-
-        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
-                if (!quiet) {
-                        if (streq(type, "symlink"))
-                                log_info("Created symlink from %s to %s.", path, source);
-                        else
-                                log_info("Removed symlink %s.", path);
-                }
-
-                r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
-                if (r < 0)
-                        return r;
-        }
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_message_exit_container(m);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        return 0;
-}
-
 /**
  * bus_path_encode_unique() - encode unique object path
  * @b: bus connection or NULL
index fcda1b2c6c7638093596cc8dcd85db20aea71a9d..d792258ecd9e48bcfab9313a894f517dec31514c 100644 (file)
 #include <stdint.h>
 #include <sys/types.h>
 
-#include "sd-bus-vtable.h"
 #include "sd-bus.h"
 #include "sd-event.h"
 
 #include "hashmap.h"
-#include "install.h"
 #include "macro.h"
 #include "string-util.h"
-#include "time-util.h"
 
 typedef enum BusTransport {
         BUS_TRANSPORT_LOCAL,
@@ -78,8 +75,8 @@ int bus_connect_user_systemd(sd_bus **_bus);
 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
 
-int bus_print_property(const char *name, sd_bus_message *property, bool all);
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
+int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all);
+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);
 
@@ -126,22 +123,6 @@ assert_cc(sizeof(mode_t) == sizeof(uint32_t));
 int bus_log_parse_error(int r);
 int bus_log_create_error(int r);
 
-typedef struct UnitInfo {
-        const char *machine;
-        const char *id;
-        const char *description;
-        const char *load_state;
-        const char *active_state;
-        const char *sub_state;
-        const char *following;
-        const char *unit_path;
-        uint32_t job_id;
-        const char *job_type;
-        const char *job_path;
-} UnitInfo;
-
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
-
 #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type)              \
         int function(sd_bus *bus,                                       \
                      const char *path,                                  \
@@ -173,20 +154,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
         SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
         SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
 
-int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
-
-typedef struct BusWaitForJobs BusWaitForJobs;
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
-void bus_wait_for_jobs_free(BusWaitForJobs *d);
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
-
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
-
 int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
 int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
 
index f3039b23f741e4638a2ad729d34e260dd6158ccc..7539891bf2c6550cd82b0fb080fd716d78364977 100644 (file)
 #include "string-util.h"
 #include "terminal-util.h"
 
-static int compare(const void *a, const void *b) {
-        const pid_t *p = a, *q = b;
+static void show_pid_array(
+                pid_t pids[],
+                unsigned n_pids,
+                const char *prefix,
+                unsigned n_columns,
+                bool extra,
+                bool more,
+                OutputFlags flags) {
 
-        if (*p < *q)
-                return -1;
-        if (*p > *q)
-                return 1;
-        return 0;
-}
-
-static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
         unsigned i, j, pid_width;
 
         if (n_pids == 0)
                 return;
 
-        qsort(pids, n_pids, sizeof(pid_t), compare);
+        qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
 
         /* Filter duplicates */
         for (j = 0, i = 1; i < n_pids; i++) {
@@ -86,8 +84,13 @@ static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, un
         }
 }
 
+static int show_cgroup_one_by_path(
+                const char *path,
+                const char *prefix,
+                unsigned n_columns,
+                bool more,
+                OutputFlags flags) {
 
-static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
         char *fn;
         _cleanup_fclose_ FILE *f = NULL;
         size_t n = 0, n_allocated = 0;
@@ -107,7 +110,7 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
 
         while ((r = cg_read_pid(f, &pid)) > 0) {
 
-                if (!kernel_threads && is_kernel_thread(pid) > 0)
+                if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
                         continue;
 
                 if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
@@ -120,12 +123,17 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
         if (r < 0)
                 return r;
 
-        show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
+        show_pid_array(pids, n, prefix, n_columns, false, more, flags);
 
         return 0;
 }
 
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
+int show_cgroup_by_path(
+                const char *path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
+
         _cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
         _cleanup_closedir_ DIR *d = NULL;
         char *gn = NULL;
@@ -137,8 +145,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
         if (n_columns <= 0)
                 n_columns = columns();
 
-        if (!prefix)
-                prefix = "";
+        prefix = strempty(prefix);
 
         r = cg_mangle_path(path, &fn);
         if (r < 0)
@@ -160,7 +167,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
                         continue;
 
                 if (!shown_pids) {
-                        show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
+                        show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
                         shown_pids = true;
                 }
 
@@ -173,7 +180,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
                                         return -ENOMEM;
                         }
 
-                        show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
+                        show_cgroup_by_path(last, p1, n_columns-2, flags);
                         free(last);
                 }
 
@@ -185,7 +192,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
                 return r;
 
         if (!shown_pids)
-                show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
+                show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
 
         if (last) {
                 printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
@@ -196,13 +203,17 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
                                 return -ENOMEM;
                 }
 
-                show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
+                show_cgroup_by_path(last, p2, n_columns-2, flags);
         }
 
         return 0;
 }
 
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
+int show_cgroup(const char *controller,
+                const char *path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
         _cleanup_free_ char *p = NULL;
         int r;
 
@@ -212,10 +223,18 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
         if (r < 0)
                 return r;
 
-        return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
+        return show_cgroup_by_path(p, prefix, n_columns, flags);
 }
 
-static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) {
+static int show_extra_pids(
+                const char *controller,
+                const char *path,
+                const char *prefix,
+                unsigned n_columns,
+                const pid_t pids[],
+                unsigned n_pids,
+                OutputFlags flags) {
+
         _cleanup_free_ pid_t *copy = NULL;
         unsigned i, j;
         int r;
@@ -247,24 +266,39 @@ static int show_extra_pids(const char *controller, const char *path, const char
                 copy[j++] = pids[i];
         }
 
-        show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
+        show_pid_array(copy, j, prefix, n_columns, true, false, flags);
 
         return 0;
 }
 
-int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
+int show_cgroup_and_extra(
+                const char *controller,
+                const char *path,
+                const char *prefix,
+                unsigned n_columns,
+                const pid_t extra_pids[],
+                unsigned n_extra_pids,
+                OutputFlags flags) {
+
         int r;
 
         assert(path);
 
-        r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
+        r = show_cgroup(controller, path, prefix, n_columns, flags);
         if (r < 0)
                 return r;
 
         return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
 }
 
-int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
+int show_cgroup_and_extra_by_spec(
+                const char *spec,
+                const char *prefix,
+                unsigned n_columns,
+                const pid_t extra_pids[],
+                unsigned n_extra_pids,
+                OutputFlags flags) {
+
         _cleanup_free_ char *controller = NULL, *path = NULL;
         int r;
 
@@ -274,5 +308,5 @@ int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned
         if (r < 0)
                 return r;
 
-        return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
+        return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
 }
index 3ab7dfb33cca226b4faec6c7d369650261a383a9..5c1d6e6d986f253912471118d456af92acf1dcf5 100644 (file)
@@ -25,8 +25,8 @@
 #include "logs-show.h"
 #include "output-mode.h"
 
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags);
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags);
 
-int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
-int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
index bd0a1f483b54961f089d315a1b5378e7cbf0cc87..1141f9964f9ed8a7e8cd6c904341fd613c215a08 100644 (file)
@@ -732,7 +732,7 @@ int config_parse_strv(const char *unit,
         for (;;) {
                 char *word = NULL;
                 int r;
-                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
                 if (r == 0)
                         break;
                 if (r == -ENOMEM)
index cc1acd6f235e1697f788776bbde19a8173bed91b..b9cd952ac8b80288d1bcd586a61748f772e79549 100644 (file)
@@ -160,7 +160,7 @@ static int iterate_dir(
                 if (!de)
                         break;
 
-                if (hidden_file(de->d_name))
+                if (hidden_or_backup_file(de->d_name))
                         continue;
 
                 f = strjoin(path, "/", de->d_name, NULL);
index 0d3da2e6d2e25db96540ac2f08c90fada3f6ed68..ade2de7727f10eb78bb9955f1035e93014d11fb8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#warning "Temporary work-around for broken glibc vs. linux kernel header definitions"
+#warning "This really should be removed sooner rather than later, when this is fixed upstream"
+#define _NET_IF_H 1
+
 #include <alloca.h>
 #include <arpa/inet.h>
 #include <endian.h>
 #include <errno.h>
-#include <net/if.h>
 #include <stddef.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <net/if.h>
+#include <linux/if.h>
+#ifndef IFNAMSIZ
+#undef _NET_IF_H
+/* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */
+#include <net/if.h>
+#endif
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter/nf_nat.h>
 #include <linux/netfilter/xt_addrtype.h>
index ef8f485cae7d1fd479ef1f8988b2b060b546dd0a..f02d81504faac3d5e836f7d2fd0e60d5d0a1b64b 100644 (file)
@@ -45,6 +45,7 @@
 #include "mkdir.h"
 #include "path-lookup.h"
 #include "path-util.h"
+#include "rm-rf.h"
 #include "set.h"
 #include "special.h"
 #include "stat-util.h"
@@ -65,7 +66,28 @@ typedef struct {
         OrderedHashmap *have_processed;
 } InstallContext;
 
-static int in_search_path(const char *path, char **search) {
+static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
+
+bool unit_type_may_alias(UnitType type) {
+        return IN_SET(type,
+                      UNIT_SERVICE,
+                      UNIT_SOCKET,
+                      UNIT_TARGET,
+                      UNIT_DEVICE,
+                      UNIT_TIMER,
+                      UNIT_PATH);
+}
+
+bool unit_type_may_template(UnitType type) {
+        return IN_SET(type,
+                      UNIT_SERVICE,
+                      UNIT_SOCKET,
+                      UNIT_TARGET,
+                      UNIT_TIMER,
+                      UNIT_PATH);
+}
+
+static int in_search_path(const LookupPaths *p, const char *path) {
         _cleanup_free_ char *parent = NULL;
         char **i;
 
@@ -75,141 +97,141 @@ static int in_search_path(const char *path, char **search) {
         if (!parent)
                 return -ENOMEM;
 
-        STRV_FOREACH(i, search)
+        STRV_FOREACH(i, p->search_path)
                 if (path_equal(parent, *i))
                         return true;
 
         return false;
 }
 
-static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
-        char *p = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(ret);
+static const char* skip_root(const LookupPaths *p, const char *path) {
+        char *e;
 
-        /* This determines where we shall create or remove our
-         * installation ("configuration") symlinks */
+        assert(p);
+        assert(path);
 
-        switch (scope) {
+        if (!p->root_dir)
+                return path;
 
-        case UNIT_FILE_SYSTEM:
+        e = path_startswith(path, p->root_dir);
+        if (!e)
+                return NULL;
 
-                if (runtime)
-                        p = path_join(root_dir, "/run/systemd/system", NULL);
-                else
-                        p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL);
-                break;
+        /* Make sure the returned path starts with a slash */
+        if (e[0] != '/') {
+                if (e == path || e[-1] != '/')
+                        return NULL;
 
-        case UNIT_FILE_GLOBAL:
+                e--;
+        }
 
-                if (root_dir)
-                        return -EINVAL;
+        return e;
+}
 
-                if (runtime)
-                        p = strdup("/run/systemd/user");
-                else
-                        p = strdup(USER_CONFIG_UNIT_PATH);
-                break;
+static int path_is_generator(const LookupPaths *p, const char *path) {
+        _cleanup_free_ char *parent = NULL;
 
-        case UNIT_FILE_USER:
+        assert(p);
+        assert(path);
 
-                if (root_dir)
-                        return -EINVAL;
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
 
-                if (runtime)
-                        r = user_runtime_dir(&p);
-                else
-                        r = user_config_home(&p);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        return -ENOENT;
+        return path_equal_ptr(parent, p->generator) ||
+               path_equal_ptr(parent, p->generator_early) ||
+               path_equal_ptr(parent, p->generator_late);
+}
 
-                break;
+static int path_is_transient(const LookupPaths *p, const char *path) {
+        _cleanup_free_ char *parent = NULL;
 
-        default:
-                assert_not_reached("Bad scope");
-        }
+        assert(p);
+        assert(path);
 
-        if (!p)
+        parent = dirname_malloc(path);
+        if (!parent)
                 return -ENOMEM;
 
-        *ret = p;
-        return 0;
+        return path_equal_ptr(parent, p->transient);
 }
 
-static bool is_config_path(UnitFileScope scope, const char *path) {
-        int r;
+static int path_is_control(const LookupPaths *p, const char *path) {
+        _cleanup_free_ char *parent = NULL;
 
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(p);
         assert(path);
 
-        /* Checks whether the specified path is intended for
-         * configuration or is outside of it */
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
 
-        switch (scope) {
+        return path_equal_ptr(parent, p->persistent_control) ||
+               path_equal_ptr(parent, p->runtime_control);
+}
 
-        case UNIT_FILE_SYSTEM:
-        case UNIT_FILE_GLOBAL:
-                return path_startswith(path, "/etc") ||
-                        path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) ||
-                        path_startswith(path, "/run");
+static int path_is_config(const LookupPaths *p, const char *path) {
+        _cleanup_free_ char *parent = NULL;
 
+        assert(p);
+        assert(path);
 
-        case UNIT_FILE_USER: {
-                _cleanup_free_ char *p = NULL;
+        /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
+         * configuration from transient or generated units */
 
-                r = user_config_home(&p);
-                if (r < 0)
-                        return r;
-                if (r > 0 && path_startswith(path, p))
-                        return true;
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
 
-                p = mfree(p);
+        return path_equal_ptr(parent, p->persistent_config) ||
+               path_equal_ptr(parent, p->runtime_config);
+}
 
-                r = user_runtime_dir(&p);
-                if (r < 0)
-                        return r;
-                if (r > 0 && path_startswith(path, p))
-                        return true;
+static int path_is_runtime(const LookupPaths *p, const char *path) {
+        _cleanup_free_ char *parent = NULL;
+        const char *rpath;
 
-                return false;
-        }
+        assert(p);
+        assert(path);
 
-        default:
-                assert_not_reached("Bad scope");
-        }
-}
+        /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
+         * directories, as safety net. */
 
+        rpath = skip_root(p, path);
+        if (rpath && path_startswith(rpath, "/run"))
+                return true;
 
-static int verify_root_dir(UnitFileScope scope, const char **root_dir) {
-        int r;
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
 
-        assert(root_dir);
+        return path_equal_ptr(parent, p->runtime_config) ||
+               path_equal_ptr(parent, p->generator) ||
+               path_equal_ptr(parent, p->generator_early) ||
+               path_equal_ptr(parent, p->generator_late) ||
+               path_equal_ptr(parent, p->transient) ||
+               path_equal_ptr(parent, p->runtime_control);
+}
 
-        /* Verifies that the specified root directory to operate on
-         * makes sense. Reset it to NULL if it is the root directory
-         * or set to empty */
+static int path_is_vendor(const LookupPaths *p, const char *path) {
+        const char *rpath;
 
-        if (isempty(*root_dir) || path_equal(*root_dir, "/")) {
-                *root_dir = NULL;
+        assert(p);
+        assert(path);
+
+        rpath = skip_root(p, path);
+        if (!rpath)
                 return 0;
-        }
 
-        if (scope != UNIT_FILE_SYSTEM)
-                return -EINVAL;
+        if (path_startswith(rpath, "/usr"))
+                return true;
 
-        r = is_dir(*root_dir, true);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return -ENOTDIR;
+#ifdef HAVE_SPLIT_USR
+        if (path_startswith(rpath, "/lib"))
+                return true;
+#endif
 
-        return 0;
+        return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
 }
 
 int unit_file_changes_add(
@@ -219,8 +241,8 @@ int unit_file_changes_add(
                 const char *path,
                 const char *source) {
 
+        _cleanup_free_ char *p = NULL, *s = NULL;
         UnitFileChange *c;
-        unsigned i;
 
         assert(path);
         assert(!changes == !n_changes);
@@ -231,29 +253,22 @@ int unit_file_changes_add(
         c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
         if (!c)
                 return -ENOMEM;
-
         *changes = c;
-        i = *n_changes;
-
-        c[i].type = type;
-        c[i].path = strdup(path);
-        if (!c[i].path)
-                return -ENOMEM;
 
-        path_kill_slashes(c[i].path);
+        p = strdup(path);
+        if (source)
+                s = strdup(source);
 
-        if (source) {
-                c[i].source = strdup(source);
-                if (!c[i].source) {
-                        free(c[i].path);
-                        return -ENOMEM;
-                }
+        if (!p || (source && !s))
+                return -ENOMEM;
 
-                path_kill_slashes(c[i].path);
-        } else
-                c[i].source = NULL;
+        path_kill_slashes(p);
+        if (s)
+                path_kill_slashes(s);
 
-        *n_changes = i+1;
+        c[*n_changes] = (UnitFileChange) { type, p, s };
+        p = s = NULL;
+        (*n_changes) ++;
         return 0;
 }
 
@@ -262,9 +277,6 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
 
         assert(changes || n_changes == 0);
 
-        if (!changes)
-                return;
-
         for (i = 0; i < n_changes; i++) {
                 free(changes[i].path);
                 free(changes[i].source);
@@ -273,6 +285,70 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
         free(changes);
 }
 
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) {
+        unsigned i;
+        bool logged = false;
+
+        assert(changes || n_changes == 0);
+        /* If verb is not specified, errors are not allowed! */
+        assert(verb || r >= 0);
+
+        for (i = 0; i < n_changes; i++) {
+                assert(verb || changes[i].type >= 0);
+
+                switch(changes[i].type) {
+                case UNIT_FILE_SYMLINK:
+                        if (!quiet)
+                                log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
+                        break;
+                case UNIT_FILE_UNLINK:
+                        if (!quiet)
+                                log_info("Removed %s.", changes[i].path);
+                        break;
+                case UNIT_FILE_IS_MASKED:
+                        if (!quiet)
+                                log_info("Unit %s is masked, ignoring.", changes[i].path);
+                        break;
+                case -EEXIST:
+                        if (changes[i].source)
+                                log_error_errno(changes[i].type,
+                                                "Failed to %s unit, file %s already exists and is a symlink to %s.",
+                                                verb, changes[i].path, changes[i].source);
+                        else
+                                log_error_errno(changes[i].type,
+                                                "Failed to %s unit, file %s already exists.",
+                                                verb, changes[i].path);
+                        logged = true;
+                        break;
+                case -ERFKILL:
+                        log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
+                                        verb, changes[i].path);
+                        logged = true;
+                        break;
+                case -EADDRNOTAVAIL:
+                        log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
+                                        verb, changes[i].path);
+                        logged = true;
+                        break;
+                case -ELOOP:
+                        log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
+                                        verb, changes[i].path);
+                        logged = true;
+                        break;
+                default:
+                        assert(changes[i].type < 0);
+                        log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
+                                        verb, changes[i].path);
+                        logged = true;
+                }
+        }
+
+        if (r < 0 && !logged)
+                log_error_errno(r, "Failed to %s: %m.", verb);
+}
+
+
+
 static int create_symlink(
                 const char *old_path,
                 const char *new_path,
@@ -294,30 +370,42 @@ static int create_symlink(
 
         if (symlink(old_path, new_path) >= 0) {
                 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-                return 0;
+                return 1;
         }
 
-        if (errno != EEXIST)
+        if (errno != EEXIST) {
+                unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
                 return -errno;
+        }
 
         r = readlink_malloc(new_path, &dest);
-        if (r < 0)
+        if (r < 0) {
+                /* translate EINVAL (non-symlink exists) to EEXIST */
+                if (r == -EINVAL)
+                        r = -EEXIST;
+
+                unit_file_changes_add(changes, n_changes, r, new_path, NULL);
                 return r;
+        }
 
         if (path_equal(dest, old_path))
                 return 0;
 
-        if (!force)
+        if (!force) {
+                unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
                 return -EEXIST;
+        }
 
         r = symlink_atomic(old_path, new_path);
-        if (r < 0)
+        if (r < 0) {
+                unit_file_changes_add(changes, n_changes, r, new_path, NULL);
                 return r;
+        }
 
         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
         unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
 
-        return 0;
+        return 1;
 }
 
 static int mark_symlink_for_removal(
@@ -353,6 +441,7 @@ static int remove_marked_symlinks_fd(
                 int fd,
                 const char *path,
                 const char *config_path,
+                const LookupPaths *lp,
                 bool *restart,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
@@ -365,6 +454,7 @@ static int remove_marked_symlinks_fd(
         assert(fd >= 0);
         assert(path);
         assert(config_path);
+        assert(lp);
         assert(restart);
 
         d = fdopendir(fd);
@@ -400,12 +490,13 @@ static int remove_marked_symlinks_fd(
                         }
 
                         /* This will close nfd, regardless whether it succeeds or not */
-                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes);
+                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes);
                         if (q < 0 && r == 0)
                                 r = q;
 
                 } else if (de->d_type == DT_LNK) {
                         _cleanup_free_ char *p = NULL, *dest = NULL;
+                        const char *rp;
                         bool found;
                         int q;
 
@@ -415,42 +506,43 @@ static int remove_marked_symlinks_fd(
                         p = path_make_absolute(de->d_name, path);
                         if (!p)
                                 return -ENOMEM;
+                        path_kill_slashes(p);
 
                         q = readlink_malloc(p, &dest);
+                        if (q == -ENOENT)
+                                continue;
                         if (q < 0) {
-                                if (q == -ENOENT)
-                                        continue;
-
                                 if (r == 0)
                                         r = q;
                                 continue;
                         }
 
-                        /* We remove all links pointing to a file or
-                         * path that is marked, as well as all files
-                         * sharing the same name as a file that is
-                         * marked. */
+                        /* We remove all links pointing to a file or path that is marked, as well as all files sharing
+                         * the same name as a file that is marked. */
 
-                        found =
-                                set_contains(remove_symlinks_to, dest) ||
+                        found = set_contains(remove_symlinks_to, dest) ||
                                 set_contains(remove_symlinks_to, basename(dest)) ||
                                 set_contains(remove_symlinks_to, de->d_name);
 
                         if (!found)
                                 continue;
 
-                        if (unlink(p) < 0 && errno != ENOENT) {
+                        if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
                                 if (r == 0)
                                         r = -errno;
+                                unit_file_changes_add(changes, n_changes, -errno, p, NULL);
                                 continue;
                         }
 
-                        path_kill_slashes(p);
                         (void) rmdir_parents(p, config_path);
 
                         unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
 
-                        q = mark_symlink_for_removal(&remove_symlinks_to, p);
+                        /* Now, remember the full path (but with the root prefix removed) of
+                         * the symlink we just removed, and remove any symlinks to it, too. */
+
+                        rp = skip_root(lp, p);
+                        q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
                         if (q < 0)
                                 return q;
                         if (q > 0)
@@ -464,6 +556,7 @@ static int remove_marked_symlinks_fd(
 static int remove_marked_symlinks(
                 Set *remove_symlinks_to,
                 const char *config_path,
+                const LookupPaths *lp,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
@@ -472,6 +565,7 @@ static int remove_marked_symlinks(
         int r = 0;
 
         assert(config_path);
+        assert(lp);
 
         if (set_size(remove_symlinks_to) <= 0)
                 return 0;
@@ -489,7 +583,7 @@ static int remove_marked_symlinks(
                         return -errno;
 
                 /* This takes possession of cfd and closes it */
-                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes);
+                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes);
                 if (r == 0)
                         r = q;
         } while (restart);
@@ -503,6 +597,7 @@ static int find_symlinks_fd(
                 int fd,
                 const char *path,
                 const char *config_path,
+                const LookupPaths *lp,
                 bool *same_name_link) {
 
         _cleanup_closedir_ DIR *d = NULL;
@@ -513,6 +608,7 @@ static int find_symlinks_fd(
         assert(fd >= 0);
         assert(path);
         assert(config_path);
+        assert(lp);
         assert(same_name_link);
 
         d = fdopendir(fd);
@@ -546,7 +642,7 @@ static int find_symlinks_fd(
                         }
 
                         /* This will close nfd, regardless whether it succeeds or not */
-                        q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
+                        q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link);
                         if (q > 0)
                                 return 1;
                         if (r == 0)
@@ -624,6 +720,7 @@ static int find_symlinks(
                 const char *root_dir,
                 const char *name,
                 const char *config_path,
+                const LookupPaths *lp,
                 bool *same_name_link) {
 
         int fd;
@@ -640,29 +737,25 @@ static int find_symlinks(
         }
 
         /* This takes possession of fd and closes it */
-        return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
+        return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link);
 }
 
 static int find_symlinks_in_scope(
                 UnitFileScope scope,
-                const char *root_dir,
+                const LookupPaths *paths,
                 const char *name,
                 UnitFileState *state) {
 
-        _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
         bool same_name_link_runtime = false, same_name_link = false;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(paths);
         assert(name);
 
-        /* First look in the normal config path */
-        r = get_config_path(scope, false, root_dir, &normal_path);
-        if (r < 0)
-                return r;
-
-        r = find_symlinks(root_dir, name, normal_path, &same_name_link);
+        /* First look in the persistent config path */
+        r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link);
         if (r < 0)
                 return r;
         if (r > 0) {
@@ -671,11 +764,7 @@ static int find_symlinks_in_scope(
         }
 
         /* Then look in runtime config path */
-        r = get_config_path(scope, true, root_dir, &runtime_path);
-        if (r < 0)
-                return r;
-
-        r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime);
+        r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime);
         if (r < 0)
                 return r;
         if (r > 0) {
@@ -742,6 +831,30 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam
         return ordered_hashmap_get(c->will_process, name);
 }
 
+static int install_info_may_process(
+                UnitFileInstallInfo *i,
+                const LookupPaths *paths,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+        assert(i);
+        assert(paths);
+
+        /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
+         * not subject to enable/disable operations. */
+
+        if (i->type == UNIT_FILE_TYPE_MASKED) {
+                unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
+                return -ERFKILL;
+        }
+        if (path_is_generator(paths, i->path) ||
+            path_is_transient(paths, i->path)) {
+                unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
+                return -EADDRNOTAVAIL;
+        }
+
+        return 0;
+}
+
 static int install_info_add(
                 InstallContext *c,
                 const char *name,
@@ -804,18 +917,34 @@ fail:
         return r;
 }
 
-static int install_info_add_auto(
-                InstallContext *c,
-                const char *name_or_path,
-                UnitFileInstallInfo **ret) {
+static int config_parse_alias(
+                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) {
 
-        assert(c);
-        assert(name_or_path);
+        const char *name;
+        UnitType type;
 
-        if (path_is_absolute(name_or_path))
-                return install_info_add(c, NULL, name_or_path, ret);
-        else
-                return install_info_add(c, name_or_path, NULL, ret);
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        name = basename(filename);
+        type = unit_name_to_type(name);
+        if (!unit_type_may_alias(type))
+                return log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                  "Aliases are not allowed for %s units, ignoring.",
+                                  unit_type_to_string(type));
+
+        return config_parse_strv(unit, filename, line, section, section_line,
+                                 lvalue, ltype, rvalue, data, userdata);
 }
 
 static int config_parse_also(
@@ -874,6 +1003,7 @@ static int config_parse_default_instance(
                 void *userdata) {
 
         UnitFileInstallInfo *i = data;
+        const char *name;
         char *printed;
         int r;
 
@@ -881,6 +1011,15 @@ static int config_parse_default_instance(
         assert(lvalue);
         assert(rvalue);
 
+        name = basename(filename);
+        if (unit_name_is_valid(name, UNIT_NAME_INSTANCE))
+                /* When enabling an instance, we might be using a template unit file,
+                 * but we should ignore DefaultInstance silently. */
+                return 0;
+        if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
+                return log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                  "DefaultInstance only makes sense for template units, ignoring.");
+
         r = install_full_printf(i, rvalue, &printed);
         if (r < 0)
                 return r;
@@ -900,11 +1039,10 @@ static int unit_file_load(
                 InstallContext *c,
                 UnitFileInstallInfo *info,
                 const char *path,
-                const char *root_dir,
                 SearchFlags flags) {
 
         const ConfigTableItem items[] = {
-                { "Install", "Alias",           config_parse_strv,             0, &info->aliases           },
+                { "Install", "Alias",           config_parse_alias,            0, &info->aliases           },
                 { "Install", "WantedBy",        config_parse_strv,             0, &info->wanted_by         },
                 { "Install", "RequiredBy",      config_parse_strv,             0, &info->required_by       },
                 { "Install", "DefaultInstance", config_parse_default_instance, 0, info                     },
@@ -912,6 +1050,8 @@ static int unit_file_load(
                 {}
         };
 
+        const char *name;
+        UnitType type;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_close_ int fd = -1;
         struct stat st;
@@ -921,7 +1061,11 @@ static int unit_file_load(
         assert(info);
         assert(path);
 
-        path = prefix_roota(root_dir, path);
+        name = basename(path);
+        type = unit_name_to_type(name);
+        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
+            !unit_type_may_template(type))
+                return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
 
         if (!(flags & SEARCH_LOAD)) {
                 r = lstat(path, &st);
@@ -983,26 +1127,26 @@ static int unit_file_load_or_readlink(
                 const char *root_dir,
                 SearchFlags flags) {
 
-        _cleanup_free_ char *np = NULL;
+        _cleanup_free_ char *target = NULL;
         int r;
 
-        r = unit_file_load(c, info, path, root_dir, flags);
+        r = unit_file_load(c, info, path, flags);
         if (r != -ELOOP)
                 return r;
 
         /* This is a symlink, let's read it. */
 
-        r = readlink_and_make_absolute_root(root_dir, path, &np);
+        r = readlink_malloc(path, &target);
         if (r < 0)
                 return r;
 
-        if (path_equal(np, "/dev/null"))
+        if (path_equal(target, "/dev/null"))
                 info->type = UNIT_FILE_TYPE_MASKED;
         else {
                 const char *bn;
                 UnitType a, b;
 
-                bn = basename(np);
+                bn = basename(target);
 
                 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
 
@@ -1029,9 +1173,16 @@ static int unit_file_load_or_readlink(
                 if (a < 0 || b < 0 || a != b)
                         return -EINVAL;
 
+                if (path_is_absolute(target))
+                        /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
+                        info->symlink_target = prefix_root(root_dir, target);
+                else
+                        /* This is a relative path, take it relative to the dir the symlink is located in. */
+                        info->symlink_target = file_in_same_dir(path, target);
+                if (!info->symlink_target)
+                        return -ENOMEM;
+
                 info->type = UNIT_FILE_TYPE_SYMLINK;
-                info->symlink_target = np;
-                np = NULL;
         }
 
         return 0;
@@ -1041,7 +1192,6 @@ static int unit_file_search(
                 InstallContext *c,
                 UnitFileInstallInfo *info,
                 const LookupPaths *paths,
-                const char *root_dir,
                 SearchFlags flags) {
 
         char **p;
@@ -1056,18 +1206,18 @@ static int unit_file_search(
                 return 0;
 
         if (info->path)
-                return unit_file_load_or_readlink(c, info, info->path, root_dir, flags);
+                return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
 
         assert(info->name);
 
-        STRV_FOREACH(p, paths->unit_path) {
+        STRV_FOREACH(p, paths->search_path) {
                 _cleanup_free_ char *path = NULL;
 
                 path = strjoin(*p, "/", info->name, NULL);
                 if (!path)
                         return -ENOMEM;
 
-                r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+                r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
                 if (r < 0) {
                         if (r != -ENOENT)
                                 return r;
@@ -1090,14 +1240,14 @@ static int unit_file_search(
                 if (r < 0)
                         return r;
 
-                STRV_FOREACH(p, paths->unit_path) {
+                STRV_FOREACH(p, paths->search_path) {
                         _cleanup_free_ char *path = NULL;
 
                         path = strjoin(*p, "/", template, NULL);
                         if (!path)
                                 return -ENOMEM;
 
-                        r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+                        r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
                         if (r < 0) {
                                 if (r != -ENOENT)
                                         return r;
@@ -1143,7 +1293,6 @@ static int install_info_follow(
 static int install_info_traverse(
                 UnitFileScope scope,
                 InstallContext *c,
-                const char *root_dir,
                 const LookupPaths *paths,
                 UnitFileInstallInfo *start,
                 SearchFlags flags,
@@ -1157,7 +1306,7 @@ static int install_info_traverse(
         assert(start);
         assert(c);
 
-        r = unit_file_search(c, start, paths, root_dir, flags);
+        r = unit_file_search(c, start, paths, flags);
         if (r < 0)
                 return r;
 
@@ -1168,10 +1317,15 @@ static int install_info_traverse(
                 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
                         return -ELOOP;
 
-                if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path))
-                        return -ELOOP;
+                if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
+                        r = path_is_config(paths, i->path);
+                        if (r < 0)
+                                return r;
+                        if (r > 0)
+                                return -ELOOP;
+                }
 
-                r = install_info_follow(c, i, root_dir, flags);
+                r = install_info_follow(c, i, paths->root_dir, flags);
                 if (r < 0) {
                         _cleanup_free_ char *buffer = NULL;
                         const char *bn;
@@ -1205,7 +1359,7 @@ static int install_info_traverse(
                         if (r < 0)
                                 return r;
 
-                        r = unit_file_search(c, i, paths, root_dir, flags);
+                        r = unit_file_search(c, i, paths, flags);
                         if (r < 0)
                                 return r;
                 }
@@ -1219,10 +1373,28 @@ static int install_info_traverse(
         return 0;
 }
 
+static int install_info_add_auto(
+                InstallContext *c,
+                const LookupPaths *paths,
+                const char *name_or_path,
+                UnitFileInstallInfo **ret) {
+
+        assert(c);
+        assert(name_or_path);
+
+        if (path_is_absolute(name_or_path)) {
+                const char *pp;
+
+                pp = prefix_roota(paths->root_dir, name_or_path);
+
+                return install_info_add(c, NULL, pp, ret);
+        } else
+                return install_info_add(c, name_or_path, NULL, ret);
+}
+
 static int install_info_discover(
                 UnitFileScope scope,
                 InstallContext *c,
-                const char *root_dir,
                 const LookupPaths *paths,
                 const char *name,
                 SearchFlags flags,
@@ -1235,15 +1407,16 @@ static int install_info_discover(
         assert(paths);
         assert(name);
 
-        r = install_info_add_auto(c, name, &i);
+        r = install_info_add_auto(c, paths, name, &i);
         if (r < 0)
                 return r;
 
-        return install_info_traverse(scope, c, root_dir, paths, i, flags, ret);
+        return install_info_traverse(scope, c, paths, i, flags, ret);
 }
 
 static int install_info_symlink_alias(
                 UnitFileInstallInfo *i,
+                const LookupPaths *paths,
                 const char *config_path,
                 bool force,
                 UnitFileChange **changes,
@@ -1253,10 +1426,12 @@ static int install_info_symlink_alias(
         int r = 0, q;
 
         assert(i);
+        assert(paths);
         assert(config_path);
 
         STRV_FOREACH(s, i->aliases) {
                 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
+                const char *rp;
 
                 q = install_full_printf(i, *s, &dst);
                 if (q < 0)
@@ -1266,7 +1441,9 @@ static int install_info_symlink_alias(
                 if (!alias_path)
                         return -ENOMEM;
 
-                q = create_symlink(i->path, alias_path, force, changes, n_changes);
+                rp = skip_root(paths, i->path);
+
+                q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes);
                 if (r == 0)
                         r = q;
         }
@@ -1276,10 +1453,10 @@ static int install_info_symlink_alias(
 
 static int install_info_symlink_wants(
                 UnitFileInstallInfo *i,
+                const LookupPaths *paths,
                 const char *config_path,
                 char **list,
                 const char *suffix,
-                bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
@@ -1289,6 +1466,7 @@ static int install_info_symlink_wants(
         int r = 0, q;
 
         assert(i);
+        assert(paths);
         assert(config_path);
 
         if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
@@ -1309,6 +1487,7 @@ static int install_info_symlink_wants(
 
         STRV_FOREACH(s, list) {
                 _cleanup_free_ char *path = NULL, *dst = NULL;
+                const char *rp;
 
                 q = install_full_printf(i, *s, &dst);
                 if (q < 0)
@@ -1323,7 +1502,9 @@ static int install_info_symlink_wants(
                 if (!path)
                         return -ENOMEM;
 
-                q = create_symlink(i->path, path, force, changes, n_changes);
+                rp = skip_root(paths, i->path);
+
+                q = create_symlink(rp ?: i->path, path, true, changes, n_changes);
                 if (r == 0)
                         r = q;
         }
@@ -1335,12 +1516,12 @@ static int install_info_symlink_link(
                 UnitFileInstallInfo *i,
                 const LookupPaths *paths,
                 const char *config_path,
-                const char *root_dir,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
         _cleanup_free_ char *path = NULL;
+        const char *rp;
         int r;
 
         assert(i);
@@ -1348,22 +1529,25 @@ static int install_info_symlink_link(
         assert(config_path);
         assert(i->path);
 
-        r = in_search_path(i->path, paths->unit_path);
-        if (r != 0)
+        r = in_search_path(paths, i->path);
+        if (r < 0)
                 return r;
+        if (r > 0)
+                return 0;
 
         path = strjoin(config_path, "/", i->name, NULL);
         if (!path)
                 return -ENOMEM;
 
-        return create_symlink(i->path, path, force, changes, n_changes);
+        rp = skip_root(paths, i->path);
+
+        return create_symlink(rp ?: i->path, path, force, changes, n_changes);
 }
 
 static int install_info_apply(
                 UnitFileInstallInfo *i,
                 const LookupPaths *paths,
                 const char *config_path,
-                const char *root_dir,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
@@ -1377,18 +1561,19 @@ static int install_info_apply(
         if (i->type != UNIT_FILE_TYPE_REGULAR)
                 return 0;
 
-        r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
+        r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
 
-        q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
+        q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
         if (r == 0)
                 r = q;
 
-        q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
+        q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
         if (r == 0)
                 r = q;
 
-        q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
-        if (r == 0)
+        q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
+        /* Do not count links to the unit file towards the "carries_install_info" count */
+        if (r == 0 && q < 0)
                 r = q;
 
         return r;
@@ -1399,7 +1584,6 @@ static int install_context_apply(
                 InstallContext *c,
                 const LookupPaths *paths,
                 const char *config_path,
-                const char *root_dir,
                 bool force,
                 SearchFlags flags,
                 UnitFileChange **changes,
@@ -1427,19 +1611,19 @@ static int install_context_apply(
                 if (q < 0)
                         return q;
 
-                r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL);
+                r = install_info_traverse(scope, c, paths, i, flags, NULL);
                 if (r < 0)
                         return r;
 
                 if (i->type != UNIT_FILE_TYPE_REGULAR)
                         continue;
 
-                q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
+                q = install_info_apply(i, paths, config_path, force, changes, n_changes);
                 if (r >= 0) {
                         if (q < 0)
                                 r = q;
                         else
-                                r+= q;
+                                r += q;
                 }
         }
 
@@ -1451,8 +1635,7 @@ static int install_context_mark_for_removal(
                 InstallContext *c,
                 const LookupPaths *paths,
                 Set **remove_symlinks_to,
-                const char *config_path,
-                const char *root_dir) {
+                const char *config_path) {
 
         UnitFileInstallInfo *i;
         int r;
@@ -1476,7 +1659,7 @@ static int install_context_mark_for_removal(
                 if (r < 0)
                         return r;
 
-                r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
+                r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
                 if (r < 0)
                         return r;
 
@@ -1500,20 +1683,19 @@ int unit_file_mask(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
-        _cleanup_free_ char *prefix = NULL;
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        const char *config_path;
         char **i;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = get_config_path(scope, runtime, root_dir, &prefix);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(i, files) {
                 _cleanup_free_ char *path = NULL;
@@ -1525,7 +1707,7 @@ int unit_file_mask(
                         continue;
                 }
 
-                path = path_make_absolute(*i, prefix);
+                path = path_make_absolute(*i, config_path);
                 if (!path)
                         return -ENOMEM;
 
@@ -1545,23 +1727,22 @@ int unit_file_unmask(
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-        _cleanup_free_ char *config_path = NULL;
         _cleanup_free_ char **todo = NULL;
         size_t n_todo = 0, n_allocated = 0;
+        const char *config_path;
         char **i;
         int r, q;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(i, files) {
                 _cleanup_free_ char *path = NULL;
@@ -1592,24 +1773,31 @@ int unit_file_unmask(
         r = 0;
         STRV_FOREACH(i, todo) {
                 _cleanup_free_ char *path = NULL;
+                const char *rp;
 
                 path = path_make_absolute(*i, config_path);
                 if (!path)
                         return -ENOMEM;
 
                 if (unlink(path) < 0) {
-                        if (errno != -ENOENT && r >= 0)
-                                r = -errno;
-                } else {
-                        q = mark_symlink_for_removal(&remove_symlinks_to, path);
-                        if (q < 0)
-                                return q;
+                        if (errno != ENOENT) {
+                                if (r >= 0)
+                                        r = -errno;
+                                unit_file_changes_add(changes, n_changes, -errno, path, NULL);
+                        }
 
-                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+                        continue;
                 }
+
+                unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+                rp = skip_root(&paths, path);
+                q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
+                if (q < 0)
+                        return q;
         }
 
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
         if (r >= 0)
                 r = q;
 
@@ -1626,26 +1814,20 @@ int unit_file_link(
                 unsigned *n_changes) {
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        _cleanup_free_ char *config_path = NULL;
         _cleanup_free_ char **todo = NULL;
         size_t n_todo = 0, n_allocated = 0;
+        const char *config_path;
         char **i;
         int r, q;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(i, files) {
                 _cleanup_free_ char *full = NULL;
@@ -1659,7 +1841,7 @@ int unit_file_link(
                 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                full = prefix_root(root_dir, *i);
+                full = prefix_root(paths.root_dir, *i);
                 if (!full)
                         return -ENOMEM;
 
@@ -1672,7 +1854,7 @@ int unit_file_link(
                 if (!S_ISREG(st.st_mode))
                         return -ENOTTY;
 
-                q = in_search_path(*i, paths.unit_path);
+                q = in_search_path(&paths, *i);
                 if (q < 0)
                         return q;
                 if (q > 0)
@@ -1688,13 +1870,15 @@ int unit_file_link(
 
         r = 0;
         STRV_FOREACH(i, todo) {
-                _cleanup_free_ char *path = NULL;
+                _cleanup_free_ char *new_path = NULL;
+                const char *old_path;
 
-                path = path_make_absolute(basename(*i), config_path);
-                if (!path)
+                old_path = skip_root(&paths, *i);
+                new_path = path_make_absolute(basename(*i), config_path);
+                if (!new_path)
                         return -ENOMEM;
 
-                q = create_symlink(*i, path, force, changes, n_changes);
+                q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes);
                 if (q < 0 && r >= 0)
                         r = q;
         }
@@ -1702,6 +1886,182 @@ int unit_file_link(
         return r;
 }
 
+static int path_shall_revert(const LookupPaths *paths, const char *path) {
+        int r;
+
+        assert(paths);
+        assert(path);
+
+        /* Checks whether the path is one where the drop-in directories shall be removed. */
+
+        r = path_is_config(paths, path);
+        if (r != 0)
+                return r;
+
+        r = path_is_control(paths, path);
+        if (r != 0)
+                return r;
+
+        return path_is_transient(paths, path);
+}
+
+int unit_file_revert(
+                UnitFileScope scope,
+                const char *root_dir,
+                char **files,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+        /* _cleanup_(install_context_done) InstallContext c = {}; */
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_strv_free_ char **todo = NULL;
+        size_t n_todo = 0, n_allocated = 0;
+        char **i;
+        int r, q;
+
+        /* Puts a unit file back into vendor state. This means:
+         *
+         * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
+         *    added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
+         *
+         * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
+         *    "config", but not in "transient" or "control" or even "generated").
+         *
+         * We remove all that in both the runtime and the persistent directories, if that applies.
+         */
+
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, files) {
+                bool has_vendor = false;
+                char **p;
+
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+                        return -EINVAL;
+
+                STRV_FOREACH(p, paths.search_path) {
+                        _cleanup_free_ char *path = NULL, *dropin = NULL;
+                        struct stat st;
+
+                        path = path_make_absolute(*i, *p);
+                        if (!path)
+                                return -ENOMEM;
+
+                        r = lstat(path, &st);
+                        if (r < 0) {
+                                if (errno != ENOENT)
+                                        return -errno;
+                        } else if (S_ISREG(st.st_mode)) {
+                                /* Check if there's a vendor version */
+                                r = path_is_vendor(&paths, path);
+                                if (r < 0)
+                                        return r;
+                                if (r > 0)
+                                        has_vendor = true;
+                        }
+
+                        dropin = strappend(path, ".d");
+                        if (!dropin)
+                                return -ENOMEM;
+
+                        r = lstat(dropin, &st);
+                        if (r < 0) {
+                                if (errno != ENOENT)
+                                        return -errno;
+                        } else if (S_ISDIR(st.st_mode)) {
+                                /* Remove the drop-ins */
+                                r = path_shall_revert(&paths, dropin);
+                                if (r < 0)
+                                        return r;
+                                if (r > 0) {
+                                        if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                                                return -ENOMEM;
+
+                                        todo[n_todo++] = dropin;
+                                        dropin = NULL;
+                                }
+                        }
+                }
+
+                if (!has_vendor)
+                        continue;
+
+                /* OK, there's a vendor version, hence drop all configuration versions */
+                STRV_FOREACH(p, paths.search_path) {
+                        _cleanup_free_ char *path = NULL;
+                        struct stat st;
+
+                        path = path_make_absolute(*i, *p);
+                        if (!path)
+                                return -ENOMEM;
+
+                        r = lstat(path, &st);
+                        if (r < 0) {
+                                if (errno != ENOENT)
+                                        return -errno;
+                        } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+                                r = path_is_config(&paths, path);
+                                if (r < 0)
+                                        return r;
+                                if (r > 0) {
+                                        if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                                                return -ENOMEM;
+
+                                        todo[n_todo++] = path;
+                                        path = NULL;
+                                }
+                        }
+                }
+        }
+
+        strv_uniq(todo);
+
+        r = 0;
+        STRV_FOREACH(i, todo) {
+                _cleanup_strv_free_ char **fs = NULL;
+                const char *rp;
+                char **j;
+
+                (void) get_files_in_directory(*i, &fs);
+
+                q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
+                if (q < 0 && q != -ENOENT && r >= 0) {
+                        r = q;
+                        continue;
+                }
+
+                STRV_FOREACH(j, fs) {
+                        _cleanup_free_ char *t = NULL;
+
+                        t = strjoin(*i, "/", *j, NULL);
+                        if (!t)
+                                return -ENOMEM;
+
+                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
+                }
+
+                unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
+
+                rp = skip_root(&paths, *i);
+                q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
+                if (q < 0)
+                        return q;
+        }
+
+        q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
+        if (r >= 0)
+                r = q;
+
+        q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
+        if (r >= 0)
+                r = q;
+
+        return r;
+}
+
 int unit_file_add_dependency(
                 UnitFileScope scope,
                 bool runtime,
@@ -1715,8 +2075,8 @@ int unit_file_add_dependency(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        _cleanup_free_ char *config_path = NULL;
         UnitFileInstallInfo *i, *target_info;
+        const char *config_path;
         char **f;
         int r;
 
@@ -1730,34 +2090,30 @@ int unit_file_add_dependency(
         if (!unit_name_is_valid(target, UNIT_NAME_ANY))
                 return -EINVAL;
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
-        r = get_config_path(scope, runtime, root_dir, &config_path);
+        r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
         if (r < 0)
                 return r;
-
-        r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
+        r = install_info_may_process(target_info, &paths, changes, n_changes);
         if (r < 0)
                 return r;
-        if (target_info->type == UNIT_FILE_TYPE_MASKED)
-                return -ESHUTDOWN;
 
         assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
 
         STRV_FOREACH(f, files) {
                 char ***l;
 
-                r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+                r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+                if (r < 0)
+                        return r;
+                r = install_info_may_process(i, &paths, changes, n_changes);
                 if (r < 0)
                         return r;
-                if (i->type == UNIT_FILE_TYPE_MASKED)
-                        return -ESHUTDOWN;
 
                 assert(i->type == UNIT_FILE_TYPE_REGULAR);
 
@@ -1776,7 +2132,7 @@ int unit_file_add_dependency(
                         return -ENOMEM;
         }
 
-        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
+        return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
 }
 
 int unit_file_enable(
@@ -1790,7 +2146,7 @@ int unit_file_enable(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        _cleanup_free_ char *config_path = NULL;
+        const char *config_path;
         UnitFileInstallInfo *i;
         char **f;
         int r;
@@ -1798,24 +2154,19 @@ int unit_file_enable(
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(f, files) {
-                r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i);
+                r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i);
+                if (r < 0)
+                        return r;
+                r = install_info_may_process(i, &paths, changes, n_changes);
                 if (r < 0)
                         return r;
-                if (i->type == UNIT_FILE_TYPE_MASKED)
-                        return -ESHUTDOWN;
 
                 assert(i->type == UNIT_FILE_TYPE_REGULAR);
         }
@@ -1825,7 +2176,7 @@ int unit_file_enable(
            is useful to determine whether the passed files had any
            installation data at all. */
 
-        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+        return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes);
 }
 
 int unit_file_disable(
@@ -1838,25 +2189,19 @@ int unit_file_disable(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        _cleanup_free_ char *config_path = NULL;
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+        const char *config_path;
         char **i;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(i, files) {
                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
@@ -1867,11 +2212,11 @@ int unit_file_disable(
                         return r;
         }
 
-        r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir);
+        r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
         if (r < 0)
                 return r;
 
-        return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
 }
 
 int unit_file_reenable(
@@ -1912,41 +2257,34 @@ int unit_file_set_default(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        _cleanup_free_ char *config_path = NULL;
         UnitFileInstallInfo *i;
-        const char *path;
+        const char *new_path, *old_path;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        if (unit_name_to_type(name) != UNIT_TARGET)
+        if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
                 return -EINVAL;
         if (streq(name, SPECIAL_DEFAULT_TARGET))
                 return -EINVAL;
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = install_info_discover(scope, &c, &paths, name, 0, &i);
         if (r < 0)
                 return r;
-
-        r = get_config_path(scope, false, root_dir, &config_path);
-        if (r < 0)
-                return r;
-
-        r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i);
+        r = install_info_may_process(i, &paths, changes, n_changes);
         if (r < 0)
                 return r;
-        if (i->type == UNIT_FILE_TYPE_MASKED)
-                return -ESHUTDOWN;
 
-        path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
+        old_path = skip_root(&paths, i->path);
+        new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
 
-        return create_symlink(i->path, path, force, changes, n_changes);
+        return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes);
 }
 
 int unit_file_get_default(
@@ -1964,19 +2302,16 @@ int unit_file_get_default(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
         if (r < 0)
                 return r;
-
-        r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+        r = install_info_may_process(i, &paths, NULL, 0);
         if (r < 0)
                 return r;
-        if (i->type == UNIT_FILE_TYPE_MASKED)
-                return -ESHUTDOWN;
 
         n = strdup(i->name);
         if (!n)
@@ -1986,9 +2321,8 @@ int unit_file_get_default(
         return 0;
 }
 
-int unit_file_lookup_state(
+static int unit_file_lookup_state(
                 UnitFileScope scope,
-                const char *root_dir,
                 const LookupPaths *paths,
                 const char *name,
                 UnitFileState *ret) {
@@ -2004,11 +2338,7 @@ int unit_file_lookup_state(
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
-        r = verify_root_dir(scope, &root_dir);
-        if (r < 0)
-                return r;
-
-        r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+        r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
         if (r < 0)
                 return r;
 
@@ -2019,11 +2349,31 @@ int unit_file_lookup_state(
         switch (i->type) {
 
         case UNIT_FILE_TYPE_MASKED:
-                state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                r = path_is_runtime(paths, i->path);
+                if (r < 0)
+                        return r;
+
+                state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
                 break;
 
         case UNIT_FILE_TYPE_REGULAR:
-                r = find_symlinks_in_scope(scope, root_dir, i->name, &state);
+                r = path_is_generator(paths, i->path);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        state = UNIT_FILE_GENERATED;
+                        break;
+                }
+
+                r = path_is_transient(paths, i->path);
+                if (r < 0)
+                        return r;
+                if (r > 0) {
+                        state = UNIT_FILE_TRANSIENT;
+                        break;
+                }
+
+                r = find_symlinks_in_scope(scope, paths, i->name, &state);
                 if (r < 0)
                         return r;
                 if (r == 0) {
@@ -2058,15 +2408,30 @@ int unit_file_get_state(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        return unit_file_lookup_state(scope, &paths, name, ret);
+}
+
+int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
+        _cleanup_(install_context_done) InstallContext c = {};
+        int r;
+
+        assert(paths);
+        assert(name);
+
+        if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+                return -EINVAL;
+
+        r = install_info_discover(scope, &c, paths, name, 0, NULL);
+        if (r == -ENOENT)
+                return 0;
         if (r < 0)
                 return r;
 
-        return unit_file_lookup_state(scope, root_dir, &paths, name, ret);
+        return 1;
 }
 
 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
@@ -2078,10 +2443,6 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        r = verify_root_dir(scope, &root_dir);
-        if (r < 0)
-                return r;
-
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
@@ -2164,7 +2525,6 @@ static int execute_preset(
                 InstallContext *minus,
                 const LookupPaths *paths,
                 const char *config_path,
-                const char *root_dir,
                 char **files,
                 UnitFilePresetMode mode,
                 bool force,
@@ -2181,11 +2541,11 @@ static int execute_preset(
         if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
                 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
 
-                r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir);
+                r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
                 if (r < 0)
                         return r;
 
-                r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+                r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
         } else
                 r = 0;
 
@@ -2193,12 +2553,12 @@ static int execute_preset(
                 int q;
 
                 /* Returns number of symlinks that where supposed to be installed. */
-                q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+                q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
                 if (r >= 0) {
                         if (q < 0)
                                 r = q;
                         else
-                                r+= q;
+                                r += q;
                 }
         }
 
@@ -2210,9 +2570,10 @@ static int preset_prepare_one(
                 InstallContext *plus,
                 InstallContext *minus,
                 LookupPaths *paths,
-                const char *root_dir,
                 UnitFilePresetMode mode,
-                const char *name) {
+                const char *name,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
 
         UnitFileInstallInfo *i;
         int r;
@@ -2221,19 +2582,20 @@ static int preset_prepare_one(
             install_info_find(minus, name))
                 return 0;
 
-        r = unit_file_query_preset(scope, root_dir, name);
+        r = unit_file_query_preset(scope, paths->root_dir, name);
         if (r < 0)
                 return r;
 
         if (r > 0) {
-                r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+                r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
                 if (r < 0)
                         return r;
 
-                if (i->type == UNIT_FILE_TYPE_MASKED)
-                        return -ESHUTDOWN;
+                r = install_info_may_process(i, paths, changes, n_changes);
+                if (r < 0)
+                        return r;
         } else
-                r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+                r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
 
         return r;
 }
@@ -2250,7 +2612,7 @@ int unit_file_preset(
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        _cleanup_free_ char *config_path = NULL;
+        const char *config_path;
         char **i;
         int r;
 
@@ -2258,28 +2620,22 @@ int unit_file_preset(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(mode < _UNIT_FILE_PRESET_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
-        if (r < 0)
-                return r;
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
         STRV_FOREACH(i, files) {
                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i);
+                r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, changes, n_changes);
                 if (r < 0)
                         return r;
         }
 
-        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes);
+        return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
 }
 
 int unit_file_preset_all(
@@ -2293,7 +2649,7 @@ int unit_file_preset_all(
 
         _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        _cleanup_free_ char *config_path = NULL;
+        const char *config_path = NULL;
         char **i;
         int r;
 
@@ -2301,28 +2657,17 @@ int unit_file_preset_all(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(mode < _UNIT_FILE_PRESET_MAX);
 
-        r = verify_root_dir(scope, &root_dir);
-        if (r < 0)
-                return r;
-
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                return r;
+        config_path = runtime ? paths.runtime_config : paths.persistent_config;
 
-        STRV_FOREACH(i, paths.unit_path) {
+        STRV_FOREACH(i, paths.search_path) {
                 _cleanup_closedir_ DIR *d = NULL;
-                _cleanup_free_ char *units_dir;
                 struct dirent *de;
 
-                units_dir = path_join(root_dir, *i, NULL);
-                if (!units_dir)
-                        return -ENOMEM;
-
-                d = opendir(units_dir);
+                d = opendir(*i);
                 if (!d) {
                         if (errno == ENOENT)
                                 continue;
@@ -2340,13 +2685,17 @@ int unit_file_preset_all(
                         if (!IN_SET(de->d_type, DT_LNK, DT_REG))
                                 continue;
 
-                        r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name);
+                        /* we don't pass changes[] in, because we want to handle errors on our own */
+                        r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, NULL, 0);
+                        if (r == -ERFKILL)
+                                r = unit_file_changes_add(changes, n_changes,
+                                                          UNIT_FILE_IS_MASKED, de->d_name, NULL);
                         if (r < 0)
                                 return r;
                 }
         }
 
-        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes);
+        return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
 }
 
 static void unit_file_list_free_one(UnitFileList *f) {
@@ -2371,7 +2720,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
 int unit_file_get_list(
                 UnitFileScope scope,
                 const char *root_dir,
-                Hashmap *h) {
+                Hashmap *h,
+                char **states,
+                char **patterns) {
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         char **i;
@@ -2381,24 +2732,15 @@ int unit_file_get_list(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(h);
 
-        r = verify_root_dir(scope, &root_dir);
-        if (r < 0)
-                return r;
-
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = lookup_paths_init(&paths, scope, 0, root_dir);
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, paths.unit_path) {
+        STRV_FOREACH(i, paths.search_path) {
                 _cleanup_closedir_ DIR *d = NULL;
-                _cleanup_free_ char *units_dir;
                 struct dirent *de;
 
-                units_dir = path_join(root_dir, *i, NULL);
-                if (!units_dir)
-                        return -ENOMEM;
-
-                d = opendir(units_dir);
+                d = opendir(*i);
                 if (!d) {
                         if (errno == ENOENT)
                                 continue;
@@ -2412,6 +2754,9 @@ int unit_file_get_list(
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
+                        if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
+                                continue;
+
                         if (hashmap_get(h, de->d_name))
                                 continue;
 
@@ -2424,14 +2769,18 @@ int unit_file_get_list(
                         if (!f)
                                 return -ENOMEM;
 
-                        f->path = path_make_absolute(de->d_name, units_dir);
+                        f->path = path_make_absolute(de->d_name, *i);
                         if (!f->path)
                                 return -ENOMEM;
 
-                        r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state);
+                        r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
                         if (r < 0)
                                 f->state = UNIT_FILE_BAD;
 
+                        if (!strv_isempty(states) &&
+                            !strv_contains(states, unit_file_state_to_string(f->state)))
+                                continue;
+
                         r = hashmap_put(h, basename(f->path), f);
                         if (r < 0)
                                 return r;
@@ -2453,6 +2802,8 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
         [UNIT_FILE_STATIC] = "static",
         [UNIT_FILE_DISABLED] = "disabled",
         [UNIT_FILE_INDIRECT] = "indirect",
+        [UNIT_FILE_GENERATED] = "generated",
+        [UNIT_FILE_TRANSIENT] = "transient",
         [UNIT_FILE_BAD] = "bad",
 };
 
@@ -2461,6 +2812,7 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
         [UNIT_FILE_SYMLINK] = "symlink",
         [UNIT_FILE_UNLINK] = "unlink",
+        [UNIT_FILE_IS_MASKED] = "masked",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
index c1a43e23e70d147a45f5a1b20fc032a5dc8f62c8..5812447c5ba4a306bbd123f4899b2e34d3a09817 100644 (file)
@@ -54,6 +54,8 @@ enum UnitFileState {
         UNIT_FILE_STATIC,
         UNIT_FILE_DISABLED,
         UNIT_FILE_INDIRECT,
+        UNIT_FILE_GENERATED,
+        UNIT_FILE_TRANSIENT,
         UNIT_FILE_BAD,
         _UNIT_FILE_STATE_MAX,
         _UNIT_FILE_STATE_INVALID = -1
@@ -70,16 +72,29 @@ enum UnitFilePresetMode {
 enum UnitFileChangeType {
         UNIT_FILE_SYMLINK,
         UNIT_FILE_UNLINK,
+        UNIT_FILE_IS_MASKED,
         _UNIT_FILE_CHANGE_TYPE_MAX,
-        _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+        _UNIT_FILE_CHANGE_INVALID = INT_MIN
 };
 
+/* type can either one of the UnitFileChangeTypes listed above, or a negative error.
+ * If source is specified, it should be the contents of the path symlink.
+ * In case of an error, source should be the existing symlink contents or NULL
+ */
 struct UnitFileChange {
-        UnitFileChangeType type;
+        int type; /* UnitFileChangeType or bust */
         char *path;
         char *source;
 };
 
+static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, unsigned n_changes) {
+        unsigned i;
+        for (i = 0; i < n_changes; i++)
+                if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK))
+                        return true;
+        return false;
+}
+
 struct UnitFileList {
         char *path;
         UnitFileState state;
@@ -123,31 +138,115 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
         return !strv_isempty(i->also);
 }
 
-int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
-
-int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret);
+bool unit_type_may_alias(UnitType type) _const_;
+bool unit_type_may_template(UnitType type) _const_;
+
+int unit_file_enable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_disable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_reenable(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_preset(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                UnitFilePresetMode mode,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_preset_all(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                UnitFilePresetMode mode,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_mask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_unmask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_link(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_revert(
+                UnitFileScope scope,
+                const char *root_dir,
+                char **files,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_set_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                const char *file,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+int unit_file_get_default(
+                UnitFileScope scope,
+                const char *root_dir,
+                char **name);
+int unit_file_add_dependency(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                const char *target,
+                UnitDependency dep,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes);
+
 int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
+int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name);
 
-int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
+int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
 Hashmap* unit_file_list_free(Hashmap *h);
 
 int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet);
 
 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
 
 const char *unit_file_state_to_string(UnitFileState s) _const_;
 UnitFileState unit_file_state_from_string(const char *s) _pure_;
+/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
 
 const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_;
 UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_;
index e2d2931c51a773a9c15b13496e4cab50b9a3fca7..9351b85eed8e1205da445ea36d753691a9545f93 100644 (file)
@@ -287,7 +287,10 @@ static int output_short(
                 if (r < 0)
                         return r;
         }
-
+        if (r == -EBADMSG) {
+                log_debug_errno(r, "Skipping message we can't read: %m");
+                return 0;
+        }
         if (r < 0)
                 return log_error_errno(r, "Failed to get journal fields: %m");
 
@@ -344,16 +347,22 @@ static int output_short(
 
                 t = (time_t) (x / USEC_PER_SEC);
 
-                switch(mode) {
+                switch (mode) {
+
+                case OUTPUT_SHORT_UNIX:
+                        r = snprintf(buf, sizeof(buf), "%10llu.%06llu", (unsigned long long) t, (unsigned long long) (x % USEC_PER_SEC));
+                        break;
+
                 case OUTPUT_SHORT_ISO:
                         r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
                         break;
+
                 case OUTPUT_SHORT_PRECISE:
                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
                         if (r > 0)
-                                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
-                                         ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
+                                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
                         break;
+
                 default:
                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
                 }
@@ -367,6 +376,12 @@ static int output_short(
                 n += strlen(buf);
         }
 
+        if (hostname && (flags & OUTPUT_NO_HOSTNAME)) {
+                /* Suppress display of the hostname if this is requested. */
+                hostname = NULL;
+                hostname_len = 0;
+        }
+
         if (hostname && shall_print(hostname, hostname_len, flags)) {
                 fprintf(f, " %.*s", (int) hostname_len, hostname);
                 n += hostname_len + 1;
@@ -894,6 +909,7 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
         [OUTPUT_SHORT_ISO] = output_short,
         [OUTPUT_SHORT_PRECISE] = output_short,
         [OUTPUT_SHORT_MONOTONIC] = output_short,
+        [OUTPUT_SHORT_UNIX] = output_short,
         [OUTPUT_VERBOSE] = output_verbose,
         [OUTPUT_EXPORT] = output_export,
         [OUTPUT_JSON] = output_json,
@@ -1040,8 +1056,8 @@ static int show_journal(FILE *f,
 }
 
 int add_matches_for_unit(sd_journal *j, const char *unit) {
+        const char *m1, *m2, *m3, *m4;
         int r;
-        char *m1, *m2, *m3, *m4;
 
         assert(j);
         assert(unit);
@@ -1073,7 +1089,9 @@ int add_matches_for_unit(sd_journal *j, const char *unit) {
         );
 
         if (r == 0 && endswith(unit, ".slice")) {
-                char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+                const char *m5;
+
+                m5 = strjoina("_SYSTEMD_SLICE=", unit);
 
                 /* Show all messages belonging to a slice */
                 (void)(
@@ -1123,7 +1141,9 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
         );
 
         if (r == 0 && endswith(unit, ".slice")) {
-                char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+                const char *m5;
+
+                m5 = strjoina("_SYSTEMD_SLICE=", unit);
 
                 /* Show all messages belonging to a slice */
                 (void)(
@@ -1288,18 +1308,3 @@ int show_journal_by_unit(
 
         return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
 }
-
-static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
-        [OUTPUT_SHORT] = "short",
-        [OUTPUT_SHORT_ISO] = "short-iso",
-        [OUTPUT_SHORT_PRECISE] = "short-precise",
-        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
-        [OUTPUT_VERBOSE] = "verbose",
-        [OUTPUT_EXPORT] = "export",
-        [OUTPUT_JSON] = "json",
-        [OUTPUT_JSON_PRETTY] = "json-pretty",
-        [OUTPUT_JSON_SSE] = "json-sse",
-        [OUTPUT_CAT] = "cat"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
index 9765a24ff24bd971de4bb815a0843a7c26f87baa..66434408812d62bdca81843cb25c16d6320d882e 100644 (file)
@@ -68,6 +68,3 @@ void json_escape(
                 const char* p,
                 size_t l,
                 OutputFlags flags);
-
-const char* output_mode_to_string(OutputMode m) _const_;
-OutputMode output_mode_from_string(const char *s) _pure_;
index d2f1c4a40c7d17f6fbff6e50b57bbf4a516d59c9..66f58ecd924a97e8f1e8a2ff4da2083fbed5824a 100644 (file)
@@ -401,8 +401,7 @@ int image_remove(Image *i) {
 
         assert(i);
 
-        if (path_equal(i->path, "/") ||
-            path_startswith(i->path, "/usr"))
+        if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
                 return -EROFS;
 
         settings = image_settings_path(i);
@@ -424,7 +423,7 @@ int image_remove(Image *i) {
 
         case IMAGE_DIRECTORY:
                 /* Allow deletion of read-only directories */
-                (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+                (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
                 r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
                 if (r < 0)
                         return r;
@@ -474,8 +473,7 @@ int image_rename(Image *i, const char *new_name) {
         if (!image_name_is_valid(new_name))
                 return -EINVAL;
 
-        if (path_equal(i->path, "/") ||
-            path_startswith(i->path, "/usr"))
+        if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
                 return -EROFS;
 
         settings = image_settings_path(i);
@@ -507,7 +505,7 @@ int image_rename(Image *i, const char *new_name) {
                 (void) read_attr_path(i->path, &file_attr);
 
                 if (file_attr & FS_IMMUTABLE_FL)
-                        (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+                        (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
 
                 /* fall through */
 
@@ -540,7 +538,7 @@ int image_rename(Image *i, const char *new_name) {
 
         /* Restore the immutable bit, if it was set before */
         if (file_attr & FS_IMMUTABLE_FL)
-                (void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
+                (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
 
         free(i->path);
         i->path = new_path;
@@ -605,13 +603,21 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
 
         case IMAGE_SUBVOLUME:
         case IMAGE_DIRECTORY:
+                /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
+                 * directory.*/
+
                 new_path = strjoina("/var/lib/machines/", new_name);
 
                 r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+                if (r == -EOPNOTSUPP) {
+                        /* No btrfs snapshots supported, create a normal directory then. */
 
-                /* Enable "subtree" quotas for the copy, if we didn't
-                 * copy any quota from the source. */
-                (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+                        r = copy_directory(i->path, new_path, false);
+                        if (r >= 0)
+                                (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+                } else if (r >= 0)
+                        /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
+                        (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
 
                 break;
 
@@ -642,8 +648,7 @@ int image_read_only(Image *i, bool b) {
         int r;
         assert(i);
 
-        if (path_equal(i->path, "/") ||
-            path_startswith(i->path, "/usr"))
+        if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
                 return -EROFS;
 
         /* Make sure we don't interfere with a running nspawn */
@@ -673,7 +678,7 @@ int image_read_only(Image *i, bool b) {
                    a read-only subvolume, but at least something, and
                    we can read the value back.*/
 
-                r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
+                r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
                 if (r < 0)
                         return r;
 
@@ -751,8 +756,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
 int image_set_limit(Image *i, uint64_t referenced_max) {
         assert(i);
 
-        if (path_equal(i->path, "/") ||
-            path_startswith(i->path, "/usr"))
+        if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
                 return -EROFS;
 
         if (i->type != IMAGE_SUBVOLUME)
index 31b720d50cc5619d93c969b0a0ade9495342d044..7410168c4feeb7106f97df81885d4d545e36db51 100644 (file)
@@ -25,6 +25,8 @@
 #include "hashmap.h"
 #include "lockfile-util.h"
 #include "macro.h"
+#include "path-util.h"
+#include "string-util.h"
 #include "time-util.h"
 
 typedef enum ImageType {
@@ -75,3 +77,27 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
 int image_name_lock(const char *name, int operation, LockFile *ret);
 
 int image_set_limit(Image *i, uint64_t referenced_max);
+
+static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
+        assert(i);
+
+        return i->name && i->name[0] == '.';
+}
+
+static inline bool IMAGE_IS_VENDOR(const struct Image *i) {
+        assert(i);
+
+        return i->path && path_startswith(i->path, "/usr");
+}
+
+static inline bool IMAGE_IS_HOST(const struct Image *i) {
+        assert(i);
+
+        if (i->name && streq(i->name, ".host"))
+                return true;
+
+        if (i->path && path_equal(i->path, "/"))
+                return true;
+
+        return false;
+}
diff --git a/src/shared/output-mode.c b/src/shared/output-mode.c
new file mode 100644 (file)
index 0000000..bec53ee
--- /dev/null
@@ -0,0 +1,37 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2012 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "output-mode.h"
+#include "string-table.h"
+
+static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
+        [OUTPUT_SHORT] = "short",
+        [OUTPUT_SHORT_ISO] = "short-iso",
+        [OUTPUT_SHORT_PRECISE] = "short-precise",
+        [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
+        [OUTPUT_SHORT_UNIX] = "short-unix",
+        [OUTPUT_VERBOSE] = "verbose",
+        [OUTPUT_EXPORT] = "export",
+        [OUTPUT_JSON] = "json",
+        [OUTPUT_JSON_PRETTY] = "json-pretty",
+        [OUTPUT_JSON_SSE] = "json-sse",
+        [OUTPUT_CAT] = "cat"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
index c5470e7c1b1af145c1f39746df8a7ceca3fc4070..f37189e57fff9389808391e55a93fa4305879a80 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "macro.h"
+
 typedef enum OutputMode {
         OUTPUT_SHORT,
         OUTPUT_SHORT_ISO,
         OUTPUT_SHORT_PRECISE,
         OUTPUT_SHORT_MONOTONIC,
+        OUTPUT_SHORT_UNIX,
         OUTPUT_VERBOSE,
         OUTPUT_EXPORT,
         OUTPUT_JSON,
@@ -34,6 +37,9 @@ typedef enum OutputMode {
         _OUTPUT_MODE_INVALID = -1
 } OutputMode;
 
+/* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the
+ * logs output, others only to the process tree output. */
+
 typedef enum OutputFlags {
         OUTPUT_SHOW_ALL       = 1 << 0,
         OUTPUT_FOLLOW         = 1 << 1,
@@ -43,4 +49,9 @@ typedef enum OutputFlags {
         OUTPUT_CATALOG        = 1 << 5,
         OUTPUT_BEGIN_NEWLINE  = 1 << 6,
         OUTPUT_UTC            = 1 << 7,
+        OUTPUT_KERNEL_THREADS = 1 << 8,
+        OUTPUT_NO_HOSTNAME    = 1 << 9,
 } OutputFlags;
+
+const char* output_mode_to_string(OutputMode m) _const_;
+OutputMode output_mode_from_string(const char *s) _pure_;
index 5410620725331167e8800bba9af77e8afdec8799..ca593b6963dd635901b504db94ffd8ca3f513736 100644 (file)
 #include "install.h"
 #include "log.h"
 #include "macro.h"
+#include "mkdir.h"
 #include "path-lookup.h"
 #include "path-util.h"
+#include "rm-rf.h"
+#include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
-int user_config_home(char **config_home) {
+static int user_runtime_dir(char **ret, const char *suffix) {
         const char *e;
-        char *r;
+        char *j;
 
-        e = getenv("XDG_CONFIG_HOME");
-        if (e) {
-                r = strappend(e, "/systemd/user");
-                if (!r)
-                        return -ENOMEM;
-
-                *config_home = r;
-                return 1;
-        } else {
-                const char *home;
+        assert(ret);
+        assert(suffix);
 
-                home = getenv("HOME");
-                if (home) {
-                        r = strappend(home, "/.config/systemd/user");
-                        if (!r)
-                                return -ENOMEM;
+        e = getenv("XDG_RUNTIME_DIR");
+        if (!e)
+                return -ENXIO;
 
-                        *config_home = r;
-                        return 1;
-                }
-        }
+        j = strappend(e, suffix);
+        if (!j)
+                return -ENOMEM;
 
+        *ret = j;
         return 0;
 }
 
-int user_runtime_dir(char **runtime_dir) {
+static int user_config_dir(char **ret, const char *suffix) {
         const char *e;
-        char *r;
+        char *j;
 
-        e = getenv("XDG_RUNTIME_DIR");
-        if (e) {
-                r = strappend(e, "/systemd/user");
-                if (!r)
-                        return -ENOMEM;
+        assert(ret);
+
+        e = getenv("XDG_CONFIG_HOME");
+        if (e)
+                j = strappend(e, suffix);
+        else {
+                const char *home;
 
-                *runtime_dir = r;
-                return 1;
+                home = getenv("HOME");
+                if (!home)
+                        return -ENXIO;
+
+                j = strjoin(home, "/.config", suffix, NULL);
         }
 
+        if (!j)
+                return -ENOMEM;
+
+        *ret = j;
         return 0;
 }
 
-static int user_data_home_dir(char **dir, const char *suffix) {
+static int user_data_dir(char **ret, const char *suffix) {
         const char *e;
-        char *res;
+        char *j;
+
+        assert(ret);
+        assert(suffix);
 
         /* We don't treat /etc/xdg/systemd here as the spec
          * suggests because we assume that that is a link to
@@ -88,27 +93,33 @@ static int user_data_home_dir(char **dir, const char *suffix) {
 
         e = getenv("XDG_DATA_HOME");
         if (e)
-                res = strappend(e, suffix);
+                j = strappend(e, suffix);
         else {
                 const char *home;
 
                 home = getenv("HOME");
-                if (home)
-                        res = strjoin(home, "/.local/share", suffix, NULL);
-                else
-                        return 0;
+                if (!home)
+                        return -ENXIO;
+
+
+                j = strjoin(home, "/.local/share", suffix, NULL);
         }
-        if (!res)
+        if (!j)
                 return -ENOMEM;
 
-        *dir = res;
-        return 0;
+        *ret = j;
+        return 1;
 }
 
 static char** user_dirs(
+                const char *persistent_config,
+                const char *runtime_config,
                 const char *generator,
                 const char *generator_early,
-                const char *generator_late) {
+                const char *generator_late,
+                const char *transient,
+                const char *persistent_control,
+                const char *runtime_control) {
 
         const char * const config_unit_paths[] = {
                 USER_CONFIG_UNIT_PATH,
@@ -116,8 +127,6 @@ static char** user_dirs(
                 NULL
         };
 
-        const char * const runtime_unit_path = "/run/systemd/user";
-
         const char * const data_unit_paths[] = {
                 "/usr/local/lib/systemd/user",
                 "/usr/local/share/systemd/user",
@@ -128,8 +137,8 @@ static char** user_dirs(
         };
 
         const char *e;
-        _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
         _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
+        _cleanup_free_ char *data_home = NULL;
         _cleanup_free_ char **res = NULL;
         char **tmp;
         int r;
@@ -143,12 +152,6 @@ static char** user_dirs(
          * as data, and allow overriding as configuration.
          */
 
-        if (user_config_home(&config_home) < 0)
-                return NULL;
-
-        if (user_runtime_dir(&runtime_dir) < 0)
-                return NULL;
-
         e = getenv("XDG_CONFIG_DIRS");
         if (e) {
                 config_dirs = strv_split(e, ":");
@@ -156,8 +159,8 @@ static char** user_dirs(
                         return NULL;
         }
 
-        r = user_data_home_dir(&data_home, "/systemd/user");
-        if (r < 0)
+        r = user_data_dir(&data_home, "/systemd/user");
+        if (r < 0 && r != -ENXIO)
                 return NULL;
 
         e = getenv("XDG_DATA_DIRS");
@@ -171,35 +174,36 @@ static char** user_dirs(
                 return NULL;
 
         /* Now merge everything we found. */
-        if (generator_early)
-                if (strv_extend(&res, generator_early) < 0)
-                        return NULL;
+        if (strv_extend(&res, persistent_control) < 0)
+                return NULL;
 
-        if (config_home)
-                if (strv_extend(&res, config_home) < 0)
-                        return NULL;
+        if (strv_extend(&res, runtime_control) < 0)
+                return NULL;
+
+        if (strv_extend(&res, transient) < 0)
+                return NULL;
+
+        if (strv_extend(&res, generator_early) < 0)
+                return NULL;
 
         if (!strv_isempty(config_dirs))
                 if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
                         return NULL;
 
-        if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
+        if (strv_extend(&res, persistent_config) < 0)
                 return NULL;
 
-        if (runtime_dir)
-                if (strv_extend(&res, runtime_dir) < 0)
-                        return NULL;
+        if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
+                return NULL;
 
-        if (strv_extend(&res, runtime_unit_path) < 0)
+        if (strv_extend(&res, runtime_config) < 0)
                 return NULL;
 
-        if (generator)
-                if (strv_extend(&res, generator) < 0)
-                        return NULL;
+        if (strv_extend(&res, generator) < 0)
+                return NULL;
 
-        if (data_home)
-                if (strv_extend(&res, data_home) < 0)
-                        return NULL;
+        if (strv_extend(&res, data_home) < 0)
+                return NULL;
 
         if (!strv_isempty(data_dirs))
                 if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
@@ -208,9 +212,8 @@ static char** user_dirs(
         if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
                 return NULL;
 
-        if (generator_late)
-                if (strv_extend(&res, generator_late) < 0)
-                        return NULL;
+        if (strv_extend(&res, generator_late) < 0)
+                return NULL;
 
         if (path_strv_make_absolute_cwd(res) < 0)
                 return NULL;
@@ -220,58 +223,298 @@ static char** user_dirs(
         return tmp;
 }
 
-char **generator_paths(ManagerRunningAs running_as) {
-        if (running_as == MANAGER_USER)
-                return strv_new("/run/systemd/user-generators",
-                                "/etc/systemd/user-generators",
-                                "/usr/local/lib/systemd/user-generators",
-                                USER_GENERATOR_PATH,
-                                NULL);
-        else
-                return strv_new("/run/systemd/system-generators",
-                                "/etc/systemd/system-generators",
-                                "/usr/local/lib/systemd/system-generators",
-                                SYSTEM_GENERATOR_PATH,
-                                NULL);
+static int acquire_generator_dirs(
+                UnitFileScope scope,
+                char **generator,
+                char **generator_early,
+                char **generator_late) {
+
+        _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
+        const char *prefix;
+
+        assert(generator);
+        assert(generator_early);
+        assert(generator_late);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:
+                prefix = "/run/systemd/";
+                break;
+
+        case UNIT_FILE_USER: {
+                const char *e;
+
+                e = getenv("XDG_RUNTIME_DIR");
+                if (!e)
+                        return -ENXIO;
+
+                prefix = strjoina(e, "/systemd/");
+                break;
+        }
+
+        case UNIT_FILE_GLOBAL:
+                return -EOPNOTSUPP;
+
+        default:
+                assert_not_reached("Hmm, unexpected scope value.");
+        }
+
+        x = strappend(prefix, "generator");
+        if (!x)
+                return -ENOMEM;
+
+        y = strappend(prefix, "generator.early");
+        if (!y)
+                return -ENOMEM;
+
+        z = strappend(prefix, "generator.late");
+        if (!z)
+                return -ENOMEM;
+
+        *generator = x;
+        *generator_early = y;
+        *generator_late = z;
+
+        x = y = z = NULL;
+        return 0;
+}
+
+static int acquire_transient_dir(UnitFileScope scope, char **ret) {
+        assert(ret);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM: {
+                char *transient;
+
+                transient = strdup("/run/systemd/transient");
+                if (!transient)
+                        return -ENOMEM;
+
+                *ret = transient;
+                return 0;
+        }
+
+        case UNIT_FILE_USER:
+                return user_runtime_dir(ret, "/systemd/transient");
+
+        case UNIT_FILE_GLOBAL:
+                return -EOPNOTSUPP;
+
+        default:
+                assert_not_reached("Hmm, unexpected scope value.");
+        }
+}
+
+static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
+        _cleanup_free_ char *a = NULL, *b = NULL;
+        int r;
+
+        assert(persistent);
+        assert(runtime);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:
+                a = strdup(SYSTEM_CONFIG_UNIT_PATH);
+                b = strdup("/run/systemd/system");
+                break;
+
+        case UNIT_FILE_GLOBAL:
+                a = strdup(USER_CONFIG_UNIT_PATH);
+                b = strdup("/run/systemd/user");
+                break;
+
+        case UNIT_FILE_USER:
+                r = user_config_dir(&a, "/systemd/user");
+                if (r < 0)
+                        return r;
+
+                r = user_runtime_dir(runtime, "/systemd/user");
+                if (r < 0)
+                        return r;
+
+                *persistent = a;
+                a = NULL;
+
+                return 0;
+
+        default:
+                assert_not_reached("Hmm, unexpected scope value.");
+        }
+
+        if (!a || !b)
+                return -ENOMEM;
+
+        *persistent = a;
+        *runtime = b;
+        a = b = NULL;
+
+        return 0;
+}
+
+static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
+        _cleanup_free_ char *a = NULL;
+        int r;
+
+        assert(persistent);
+        assert(runtime);
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:  {
+                _cleanup_free_ char *b = NULL;
+
+                a = strdup("/etc/systemd/system.control");
+                if (!a)
+                        return -ENOMEM;
+
+                b = strdup("/run/systemd/system.control");
+                if (!b)
+                        return -ENOMEM;
+
+                *runtime = b;
+                b = NULL;
+
+                break;
+        }
+
+        case UNIT_FILE_USER:
+                r = user_config_dir(&a, "/systemd/system.control");
+                if (r < 0)
+                        return r;
+
+                r = user_runtime_dir(runtime, "/systemd/system.control");
+                if (r < 0)
+                        return r;
+
+                break;
+
+        case UNIT_FILE_GLOBAL:
+                return -EOPNOTSUPP;
+
+        default:
+                assert_not_reached("Hmm, unexpected scope value.");
+        }
+
+        *persistent = a;
+        a = NULL;
+
+        return 0;
+}
+
+static int patch_root_prefix(char **p, const char *root_dir) {
+        char *c;
+
+        assert(p);
+
+        if (!*p)
+                return 0;
+
+        c = prefix_root(root_dir, *p);
+        if (!c)
+                return -ENOMEM;
+
+        free(*p);
+        *p = c;
+
+        return 0;
+}
+
+static int patch_root_prefix_strv(char **l, const char *root_dir) {
+        char **i;
+        int r;
+
+        if (!root_dir)
+                return 0;
+
+        STRV_FOREACH(i, l) {
+                r = patch_root_prefix(i, root_dir);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
 }
 
 int lookup_paths_init(
                 LookupPaths *p,
-                ManagerRunningAs running_as,
-                bool personal,
-                const char *root_dir,
-                const char *generator,
-                const char *generator_early,
-                const char *generator_late) {
-
-        const char *e;
+                UnitFileScope scope,
+                LookupPathsFlags flags,
+                const char *root_dir) {
+
+        _cleanup_free_ char
+                *root = NULL,
+                *persistent_config = NULL, *runtime_config = NULL,
+                *generator = NULL, *generator_early = NULL, *generator_late = NULL,
+                *transient = NULL,
+                *persistent_control = NULL, *runtime_control = NULL;
         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
+        _cleanup_strv_free_ char **paths = NULL;
+        const char *e;
         int r;
 
         assert(p);
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        if (!isempty(root_dir) && !path_equal(root_dir, "/")) {
+                if (scope == UNIT_FILE_USER)
+                        return -EINVAL;
+
+                r = is_dir(root_dir, true);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -ENOTDIR;
 
-        /* First priority is whatever has been passed to us via env
-         * vars */
+                root = strdup(root_dir);
+                if (!root)
+                        return -ENOMEM;
+        }
+
+        r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
+        if (r < 0 && r != -ENXIO)
+                return r;
+
+        if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
+                r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
+                if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+                        return r;
+        }
+
+        r = acquire_transient_dir(scope, &transient);
+        if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+                return r;
+
+        r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
+        if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+                return r;
+
+        /* First priority is whatever has been passed to us via env vars */
         e = getenv("SYSTEMD_UNIT_PATH");
         if (e) {
-                if (endswith(e, ":")) {
-                        e = strndupa(e, strlen(e) - 1);
+                const char *k;
+
+                k = endswith(e, ":");
+                if (k) {
+                        e = strndupa(e, k - e);
                         append = true;
                 }
 
                 /* FIXME: empty components in other places should be
                  * rejected. */
 
-                r = path_split_and_make_absolute(e, &p->unit_path);
+                r = path_split_and_make_absolute(e, &paths);
                 if (r < 0)
                         return r;
-        } else
-                p->unit_path = NULL;
+        }
 
-        if (!p->unit_path || append) {
+        if (!paths || append) {
                 /* Let's figure something out. */
 
-                _cleanup_strv_free_ char **unit_path;
+                _cleanup_strv_free_ char **add = NULL;
 
                 /* For the user units we include share/ in the search
                  * path in order to comply with the XDG basedir spec.
@@ -279,17 +522,45 @@ int lookup_paths_init(
                  * we include /lib in the search path for the system
                  * stuff but avoid it for user stuff. */
 
-                if (running_as == MANAGER_USER) {
-                        if (personal)
-                                unit_path = user_dirs(generator, generator_early, generator_late);
-                        else
-                                unit_path = strv_new(
+                switch (scope) {
+
+                case UNIT_FILE_SYSTEM:
+                        add = strv_new(
+                                        /* If you modify this you also want to modify
+                                         * systemdsystemunitpath= in systemd.pc.in! */
+                                        STRV_IFNOTNULL(persistent_control),
+                                        STRV_IFNOTNULL(runtime_control),
+                                        STRV_IFNOTNULL(transient),
+                                        STRV_IFNOTNULL(generator_early),
+                                        persistent_config,
+                                        SYSTEM_CONFIG_UNIT_PATH,
+                                        "/etc/systemd/system",
+                                        runtime_config,
+                                        "/run/systemd/system",
+                                        STRV_IFNOTNULL(generator),
+                                        "/usr/local/lib/systemd/system",
+                                        SYSTEM_DATA_UNIT_PATH,
+                                        "/usr/lib/systemd/system",
+#ifdef HAVE_SPLIT_USR
+                                        "/lib/systemd/system",
+#endif
+                                        STRV_IFNOTNULL(generator_late),
+                                        NULL);
+                        break;
+
+                case UNIT_FILE_GLOBAL:
+                        add = strv_new(
                                         /* If you modify this you also want to modify
                                          * systemduserunitpath= in systemd.pc.in, and
                                          * the arrays in user_dirs() above! */
+                                        STRV_IFNOTNULL(persistent_control),
+                                        STRV_IFNOTNULL(runtime_control),
+                                        STRV_IFNOTNULL(transient),
                                         STRV_IFNOTNULL(generator_early),
+                                        persistent_config,
                                         USER_CONFIG_UNIT_PATH,
                                         "/etc/systemd/user",
+                                        runtime_config,
                                         "/run/systemd/user",
                                         STRV_IFNOTNULL(generator),
                                         "/usr/local/lib/systemd/user",
@@ -299,143 +570,253 @@ int lookup_paths_init(
                                         "/usr/share/systemd/user",
                                         STRV_IFNOTNULL(generator_late),
                                         NULL);
-                } else
-                        unit_path = strv_new(
-                                /* If you modify this you also want to modify
-                                 * systemdsystemunitpath= in systemd.pc.in! */
-                                STRV_IFNOTNULL(generator_early),
-                                SYSTEM_CONFIG_UNIT_PATH,
-                                "/etc/systemd/system",
-                                "/run/systemd/system",
-                                STRV_IFNOTNULL(generator),
-                                "/usr/local/lib/systemd/system",
-                                SYSTEM_DATA_UNIT_PATH,
-                                "/usr/lib/systemd/system",
-#ifdef HAVE_SPLIT_USR
-                                "/lib/systemd/system",
-#endif
-                                STRV_IFNOTNULL(generator_late),
-                                NULL);
+                        break;
+
+                case UNIT_FILE_USER:
+                        add = user_dirs(persistent_config, runtime_config,
+                                        generator, generator_early, generator_late,
+                                        transient,
+                                        persistent_config, runtime_control);
+                        break;
 
-                if (!unit_path)
+                default:
+                        assert_not_reached("Hmm, unexpected scope?");
+                }
+
+                if (!add)
                         return -ENOMEM;
 
-                r = strv_extend_strv(&p->unit_path, unit_path, false);
-                if (r < 0)
-                        return r;
+                if (paths) {
+                        r = strv_extend_strv(&paths, add, true);
+                        if (r < 0)
+                                return r;
+                } else {
+                        /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
+                         * and don't have to copy anything */
+                        paths = add;
+                        add = NULL;
+                }
         }
 
-        if (!path_strv_resolve_uniq(p->unit_path, root_dir))
+        r = patch_root_prefix(&persistent_config, root);
+        if (r < 0)
+                return r;
+        r = patch_root_prefix(&runtime_config, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix(&generator, root);
+        if (r < 0)
+                return r;
+        r = patch_root_prefix(&generator_early, root);
+        if (r < 0)
+                return r;
+        r = patch_root_prefix(&generator_late, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix(&transient, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix(&persistent_control, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix(&runtime_control, root);
+        if (r < 0)
+                return r;
+
+        r = patch_root_prefix_strv(paths, root);
+        if (r < 0)
                 return -ENOMEM;
 
-        if (!strv_isempty(p->unit_path)) {
-                _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
-                if (!t)
-                        return -ENOMEM;
-                log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
-        } else {
-                log_debug("Ignoring unit files.");
-                p->unit_path = strv_free(p->unit_path);
-        }
+        p->search_path = strv_uniq(paths);
+        paths = NULL;
 
-        if (running_as == MANAGER_SYSTEM) {
-#ifdef HAVE_SYSV_COMPAT
-                /* /etc/init.d/ compatibility does not matter to users */
+        p->persistent_config = persistent_config;
+        p->runtime_config = runtime_config;
+        persistent_config = runtime_config = NULL;
 
-                e = getenv("SYSTEMD_SYSVINIT_PATH");
-                if (e) {
-                        r = path_split_and_make_absolute(e, &p->sysvinit_path);
-                        if (r < 0)
-                                return r;
-                } else
-                        p->sysvinit_path = NULL;
+        p->generator = generator;
+        p->generator_early = generator_early;
+        p->generator_late = generator_late;
+        generator = generator_early = generator_late = NULL;
 
-                if (strv_isempty(p->sysvinit_path)) {
-                        strv_free(p->sysvinit_path);
+        p->transient = transient;
+        transient = NULL;
 
-                        p->sysvinit_path = strv_new(
-                                        SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
-                                        NULL);
-                        if (!p->sysvinit_path)
-                                return -ENOMEM;
-                }
+        p->persistent_control = persistent_control;
+        p->runtime_control = runtime_control;
+        persistent_control = runtime_control = NULL;
 
-                e = getenv("SYSTEMD_SYSVRCND_PATH");
-                if (e) {
-                        r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
-                        if (r < 0)
-                                return r;
-                } else
-                        p->sysvrcnd_path = NULL;
+        p->root_dir = root;
+        root = NULL;
 
-                if (strv_isempty(p->sysvrcnd_path)) {
-                        strv_free(p->sysvrcnd_path);
+        return 0;
+}
 
-                        p->sysvrcnd_path = strv_new(
-                                        SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
-                                        NULL);
-                        if (!p->sysvrcnd_path)
-                                return -ENOMEM;
+void lookup_paths_free(LookupPaths *p) {
+        if (!p)
+                return;
+
+        p->search_path = strv_free(p->search_path);
+
+        p->persistent_config = mfree(p->persistent_config);
+        p->runtime_config = mfree(p->runtime_config);
+
+        p->generator = mfree(p->generator);
+        p->generator_early = mfree(p->generator_early);
+        p->generator_late = mfree(p->generator_late);
+
+        p->transient = mfree(p->transient);
+
+        p->persistent_control = mfree(p->persistent_control);
+        p->runtime_control = mfree(p->runtime_control);
+
+        p->root_dir = mfree(p->root_dir);
+}
+
+int lookup_paths_reduce(LookupPaths *p) {
+        _cleanup_free_ struct stat *stats = NULL;
+        size_t n_stats = 0, allocated = 0;
+        unsigned c = 0;
+        int r;
+
+        assert(p);
+
+        /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
+         * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
+         * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
+         * account when following symlinks. When we have no root path set this restriction does not apply however. */
+
+        if (!p->search_path)
+                return 0;
+
+        while (p->search_path[c]) {
+                struct stat st;
+                unsigned k;
+
+                if (p->root_dir)
+                        r = lstat(p->search_path[c], &st);
+                else
+                        r = stat(p->search_path[c], &st);
+                if (r < 0) {
+                        if (errno == ENOENT)
+                                goto remove_item;
+
+                        /* If something we don't grok happened, let's better leave it in. */
+                        log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
+                        c++;
+                        continue;
                 }
 
-                if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
-                        return -ENOMEM;
+                for (k = 0; k < n_stats; k++) {
+                        if (stats[k].st_dev == st.st_dev &&
+                            stats[k].st_ino == st.st_ino)
+                                break;
+                }
+
+                if (k < n_stats) /* Is there already an entry with the same device/inode? */
+                        goto remove_item;
 
-                if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
+                if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
                         return -ENOMEM;
 
-                if (!strv_isempty(p->sysvinit_path)) {
-                        _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
-                        if (!t)
-                                return -ENOMEM;
-                        log_debug("Looking for SysV init scripts in:\n\t%s", t);
-                } else {
-                        log_debug("Ignoring SysV init scripts.");
-                        p->sysvinit_path = strv_free(p->sysvinit_path);
-                }
+                stats[n_stats++] = st;
+                c++;
+                continue;
 
-                if (!strv_isempty(p->sysvrcnd_path)) {
-                        _cleanup_free_ char *t =
-                                strv_join(p->sysvrcnd_path, "\n\t");
-                        if (!t)
-                                return -ENOMEM;
+        remove_item:
+                free(p->search_path[c]);
+                memmove(p->search_path + c,
+                        p->search_path + c + 1,
+                        (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
+        }
 
-                        log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
-                } else {
-                        log_debug("Ignoring SysV rcN.d links.");
-                        p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
-                }
-#else
-                log_debug("SysV init scripts and rcN.d links support disabled");
-#endif
+        if (strv_isempty(p->search_path)) {
+                log_debug("Ignoring unit files.");
+                p->search_path = strv_free(p->search_path);
+        } else {
+                _cleanup_free_ char *t;
+
+                t = strv_join(p->search_path, "\n\t");
+                if (!t)
+                        return -ENOMEM;
+
+                log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
         }
 
         return 0;
 }
 
-void lookup_paths_free(LookupPaths *p) {
+int lookup_paths_mkdir_generator(LookupPaths *p) {
+        int r, q;
+
         assert(p);
 
-        p->unit_path = strv_free(p->unit_path);
+        if (!p->generator || !p->generator_early || !p->generator_late)
+                return -EINVAL;
 
-#ifdef HAVE_SYSV_COMPAT
-        p->sysvinit_path = strv_free(p->sysvinit_path);
-        p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
-#endif
+        r = mkdir_p_label(p->generator, 0755);
+
+        q = mkdir_p_label(p->generator_early, 0755);
+        if (q < 0 && r >= 0)
+                r = q;
+
+        q = mkdir_p_label(p->generator_late, 0755);
+        if (q < 0 && r >= 0)
+                r = q;
+
+        return r;
 }
 
-int lookup_paths_init_from_scope(LookupPaths *paths,
-                                 UnitFileScope scope,
-                                 const char *root_dir) {
-        assert(paths);
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
+void lookup_paths_trim_generator(LookupPaths *p) {
+        assert(p);
 
-        zero(*paths);
+        /* Trim empty dirs */
+
+        if (p->generator)
+                (void) rmdir(p->generator);
+        if (p->generator_early)
+                (void) rmdir(p->generator_early);
+        if (p->generator_late)
+                (void) rmdir(p->generator_late);
+}
+
+void lookup_paths_flush_generator(LookupPaths *p) {
+        assert(p);
 
-        return lookup_paths_init(paths,
-                                 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
-                                 scope == UNIT_FILE_USER,
-                                 root_dir,
-                                 NULL, NULL, NULL);
+        /* Flush the generated unit files in full */
+
+        if (p->generator)
+                (void) rm_rf(p->generator, REMOVE_ROOT);
+        if (p->generator_early)
+                (void) rm_rf(p->generator_early, REMOVE_ROOT);
+        if (p->generator_late)
+                (void) rm_rf(p->generator_late, REMOVE_ROOT);
+}
+
+char **generator_binary_paths(UnitFileScope scope) {
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:
+                return strv_new("/run/systemd/system-generators",
+                                "/etc/systemd/system-generators",
+                                "/usr/local/lib/systemd/system-generators",
+                                SYSTEM_GENERATOR_PATH,
+                                NULL);
+
+        case UNIT_FILE_GLOBAL:
+        case UNIT_FILE_USER:
+                return strv_new("/run/systemd/user-generators",
+                                "/etc/systemd/user-generators",
+                                "/usr/local/lib/systemd/user-generators",
+                                USER_GENERATOR_PATH,
+                                NULL);
+
+        default:
+                assert_not_reached("Hmm, unexpected scope.");
+        }
 }
index 26c83d61111224f4f266260951ff326cc8991fe8..f9bb2fe2374b450e1c067b280c74cdb73b0131ed 100644 (file)
 ***/
 
 #include <stdbool.h>
-#include "macro.h"
 
-typedef struct LookupPaths {
-        char **unit_path;
-#ifdef HAVE_SYSV_COMPAT
-        char **sysvinit_path;
-        char **sysvrcnd_path;
-#endif
-} LookupPaths;
-
-typedef enum ManagerRunningAs {
-        MANAGER_SYSTEM,
-        MANAGER_USER,
-        _MANAGER_RUNNING_AS_MAX,
-        _MANAGER_RUNNING_AS_INVALID = -1
-} ManagerRunningAs;
-
-int user_config_home(char **config_home);
-int user_runtime_dir(char **runtime_dir);
-
-char **generator_paths(ManagerRunningAs running_as);
-
-int lookup_paths_init(LookupPaths *p,
-                      ManagerRunningAs running_as,
-                      bool personal,
-                      const char *root_dir,
-                      const char *generator,
-                      const char *generator_early,
-                      const char *generator_late);
+typedef struct LookupPaths LookupPaths;
 
 #include "install.h"
+#include "macro.h"
+
+typedef enum LookupPathsFlags {
+        LOOKUP_PATHS_EXCLUDE_GENERATED = 1,
+} LookupPathsFlags;
+
+struct LookupPaths {
+        /* Where we look for unit files. This includes the individual special paths below, but also any vendor
+         * supplied, static unit file paths. */
+        char **search_path;
+
+        /* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin
+         * shall place his own unit files. */
+        char *persistent_config;
+        char *runtime_config;
+
+        /* Where to place generated unit files (i.e. those a "generator" tool generated). Note the special semantics of
+         * this directory: the generators are flushed each time a "systemctl daemon-reload" is issued. The user should
+         * not alter these directories directly. */
+        char *generator;
+        char *generator_early;
+        char *generator_late;
 
-int lookup_paths_init_from_scope(LookupPaths *paths,
-                                 UnitFileScope scope,
-                                 const char *root_dir);
+        /* Where to place transient unit files (i.e. those created dynamically via the bus API). Note the special
+         * semantics of this directory: all units created transiently have their unit files removed as the transient
+         * unit is unloaded. The user should not alter this directory directly. */
+        char *transient;
+
+        /* Where the snippets created by "systemctl set-property" are placed. Note that for transient units, the
+         * snippets are placed in the transient directory though (see above). The user should not alter this directory
+         * directly. */
+        char *persistent_control;
+        char *runtime_control;
+
+        /* The root directory prepended to all items above, or NULL */
+        char *root_dir;
+};
+
+int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
+
+int lookup_paths_reduce(LookupPaths *p);
+
+int lookup_paths_mkdir_generator(LookupPaths *p);
+void lookup_paths_trim_generator(LookupPaths *p);
+void lookup_paths_flush_generator(LookupPaths *p);
 
 void lookup_paths_free(LookupPaths *p);
 #define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free)
+
+char **generator_binary_paths(UnitFileScope scope);
index 35aa60101fb033947609a29ebe36fc2787c40a44..f00624d0f20ad20ea09708c5fc0ca068b8e422d3 100644 (file)
@@ -28,6 +28,7 @@
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
@@ -231,6 +232,9 @@ static bool enough_memory_for_hibernation(void) {
         size_t size = 0, used = 0;
         int r;
 
+        if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+                return true;
+
         r = hibernation_partition_size(&size, &used);
         if (r < 0)
                 return false;
index cf3c8ad5a346680961a80a895d5d244a932bf4f0..7dae4d14fe22648a64fcfb3f3ef2fdd84cc0b135 100644 (file)
@@ -44,6 +44,10 @@ int polkit_agent_open(void) {
         if (agent_pid > 0)
                 return 0;
 
+        /* Clients that run as root don't need to activate/query polkit */
+        if (geteuid() == 0)
+                return 0;
+
         /* We check STDIN here, not STDOUT, since this is about input,
          * not output */
         if (!isatty(STDIN_FILENO))
diff --git a/src/shared/tests.c b/src/shared/tests.c
new file mode 100644 (file)
index 0000000..4091162
--- /dev/null
@@ -0,0 +1,33 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <util.h>
+
+#include "tests.h"
+
+char* setup_fake_runtime_dir(void) {
+        char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
+
+        assert_se(mkdtemp(t));
+        assert_se(setenv("XDG_RUNTIME_DIR", t, 1) >= 0);
+        assert_se(p = strdup(t));
+
+        return p;
+}
diff --git a/src/shared/tests.h b/src/shared/tests.h
new file mode 100644 (file)
index 0000000..93f0901
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+char* setup_fake_runtime_dir(void);
index 2afb7bad1a5ed6162d21523f222c21a27788a6ce..9af25e22a43825fb1fffba9295777f2ab17aa1bf 100644 (file)
@@ -39,6 +39,7 @@
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-message.h"
+#include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
@@ -103,6 +104,7 @@ static bool arg_no_pager = false;
 static bool arg_no_wtmp = false;
 static bool arg_no_wall = false;
 static bool arg_no_reload = false;
+static bool arg_value = false;
 static bool arg_show_types = false;
 static bool arg_ignore_inhibitors = false;
 static bool arg_dry = false;
@@ -323,6 +325,8 @@ static int compare_unit_info(const void *a, const void *b) {
 }
 
 static bool output_show_unit(const UnitInfo *u, char **patterns) {
+        assert(u);
+
         if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
                 return false;
 
@@ -340,6 +344,12 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
         if (arg_all)
                 return true;
 
+        /* Note that '--all' is not purely a state filter, but also a
+         * filter that hides units that "follow" other units (which is
+         * used for device units that appear under different names). */
+        if (!isempty(u->following))
+                return false;
+
         if (!strv_isempty(arg_states))
                 return true;
 
@@ -348,7 +358,7 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
         if (u->job_id > 0)
                 return true;
 
-        if (streq(u->active_state, "inactive") || u->following[0])
+        if (streq(u->active_state, "inactive"))
                 return false;
 
         return true;
@@ -531,6 +541,7 @@ static int get_unit_list(
         size_t size = c;
         int r;
         UnitInfo u;
+        bool fallback = false;
 
         assert(bus);
         assert(unit_infos);
@@ -542,8 +553,7 @@ static int get_unit_list(
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        "ListUnitsFiltered");
-
+                        "ListUnitsByPatterns");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -551,7 +561,34 @@ static int get_unit_list(
         if (r < 0)
                 return bus_log_create_error(r);
 
+        r = sd_bus_message_append_strv(m, patterns);
+        if (r < 0)
+                return bus_log_create_error(r);
+
         r = sd_bus_call(bus, m, 0, &error, &reply);
+        if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                /* Fallback to legacy ListUnitsFiltered method */
+                fallback = true;
+                log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
+                m = sd_bus_message_unref(m);
+                sd_bus_error_free(&error);
+
+                r = sd_bus_message_new_method_call(
+                                bus,
+                                &m,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "ListUnitsFiltered");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, arg_states);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+        }
         if (r < 0)
                 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
 
@@ -562,7 +599,7 @@ static int get_unit_list(
         while ((r = bus_parse_unit_info(reply, &u)) > 0) {
                 u.machine = machine;
 
-                if (!output_show_unit(&u, patterns))
+                if (!output_show_unit(&u, fallback ? patterns : NULL))
                         continue;
 
                 if (!GREEDY_REALLOC(*unit_infos, size, c+1))
@@ -1272,7 +1309,9 @@ static int compare_unit_file_list(const void *a, const void *b) {
         return strcasecmp(basename(u->path), basename(v->path));
 }
 
-static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
+static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
+        assert(u);
+
         if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
                 return false;
 
@@ -1287,8 +1326,8 @@ static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
                         return false;
         }
 
-        if (!strv_isempty(arg_states) &&
-            !strv_find(arg_states, unit_file_state_to_string(u->state)))
+        if (!strv_isempty(states) &&
+            !strv_find(states, unit_file_state_to_string(u->state)))
                 return false;
 
         return true;
@@ -1361,6 +1400,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
         const char *state;
         char *path;
         int r;
+        bool fallback = false;
 
         pager_open(arg_no_pager, false);
 
@@ -1374,7 +1414,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                 if (!h)
                         return log_oom();
 
-                r = unit_file_get_list(arg_scope, arg_root, h);
+                r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
                 if (r < 0) {
                         unit_file_list_free(h);
                         return log_error_errno(r, "Failed to get unit file list: %m");
@@ -1389,7 +1429,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                 }
 
                 HASHMAP_FOREACH(u, h, i) {
-                        if (!output_show_unit_file(u, strv_skip(argv, 1)))
+                        if (!output_show_unit_file(u, NULL, NULL))
                                 continue;
 
                         units[c++] = *u;
@@ -1399,6 +1439,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                 assert(c <= n_units);
                 hashmap_free(h);
         } else {
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 sd_bus *bus;
 
@@ -1406,15 +1447,44 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return r;
 
-                r = sd_bus_call_method(
+                r = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                "ListUnitFiles",
-                                &error,
-                                &reply,
-                                NULL);
+                                "ListUnitFilesByPatterns");
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, arg_states);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                r = sd_bus_call(bus, m, 0, &error, &reply);
+                if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                        /* Fallback to legacy ListUnitFiles method */
+                        fallback = true;
+                        log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
+                        m = sd_bus_message_unref(m);
+                        sd_bus_error_free(&error);
+
+                        r = sd_bus_message_new_method_call(
+                                        bus,
+                                        &m,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "ListUnitFiles");
+                        if (r < 0)
+                                return bus_log_create_error(r);
+
+                        r = sd_bus_call(bus, m, 0, &error, &reply);
+                }
                 if (r < 0)
                         return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
 
@@ -1432,7 +1502,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
                                 unit_file_state_from_string(state)
                         };
 
-                        if (output_show_unit_file(&units[c], strv_skip(argv, 1)))
+                        if (output_show_unit_file(&units[c],
+                            fallback ? arg_states : NULL,
+                            fallback ? strv_skip(argv, 1) : NULL))
                                 c++;
 
                 }
@@ -1896,13 +1968,13 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
                         printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state);
 
                 if (m->is_host)
-                        printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n",
+                        printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
                                (int) (namelen - (sizeof(" (host)")-1)), strna(m->name),
                                on_state, statelen, strna(m->state), off_state,
                                on_failed, failedlen, m->n_failed_units, off_failed,
                                jobslen, m->n_jobs);
                 else
-                        printf("%-*s %s%-*s%s %s%*u%s %*u\n",
+                        printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
                                namelen, strna(m->name),
                                on_state, statelen, strna(m->state), off_state,
                                on_failed, failedlen, m->n_failed_units, off_failed,
@@ -1983,19 +2055,6 @@ static int get_default(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
-static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
-        unsigned i;
-
-        assert(changes || n_changes == 0);
-
-        for (i = 0; i < n_changes; i++) {
-                if (changes[i].type == UNIT_FILE_SYMLINK)
-                        log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
-                else
-                        log_info("Removed symlink %s.", changes[i].path);
-        }
-}
-
 static int set_default(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *unit = NULL;
         int r;
@@ -2012,14 +2071,9 @@ static int set_default(int argc, char *argv[], void *userdata) {
                 unsigned n_changes = 0;
 
                 r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to set default target: %m");
-
-                if (!arg_quiet)
-                        dump_unit_file_changes(changes, n_changes);
-
+                unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
                 unit_file_changes_free(changes, n_changes);
-                r = 0;
+                return r;
         } else {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -2294,7 +2348,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
         assert(unit_name);
         assert(unit_path);
 
-        STRV_FOREACH(p, lp->unit_path) {
+        STRV_FOREACH(p, lp->search_path) {
                 _cleanup_free_ char *path;
 
                 path = path_join(arg_root, *p, unit_name);
@@ -2394,7 +2448,7 @@ static int unit_find_paths(
                 }
 
                 if (dropin_paths) {
-                        r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, &dropins);
+                        r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins);
                         if (r < 0)
                                 return r;
                 }
@@ -3108,7 +3162,7 @@ static int set_exit_code(uint8_t code) {
                         NULL,
                         "y", code);
         if (r < 0)
-                return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+                return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
 
         return 0;
 }
@@ -3135,7 +3189,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
                 return r;
 
         if (a == ACTION_REBOOT && argc > 1) {
-                r = update_reboot_param_file(argv[1]);
+                r = update_reboot_parameter_and_warn(argv[1]);
                 if (r < 0)
                         return r;
 
@@ -3253,7 +3307,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
 
         /* --fail was specified */
         if (streq(arg_job_mode, "fail"))
-                kill_who = strjoina(arg_kill_who, "-fail", NULL);
+                kill_who = strjoina(arg_kill_who, "-fail");
 
         r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
         if (r < 0)
@@ -3445,6 +3499,7 @@ typedef struct UnitStatusInfo {
 } UnitStatusInfo;
 
 static void print_status_info(
+                sd_bus *bus,
                 UnitStatusInfo *i,
                 bool *ellipsized) {
 
@@ -3455,6 +3510,7 @@ static void print_status_info(
         char since2[FORMAT_TIMESTAMP_MAX], *s2;
         const char *path;
         char **t, **t2;
+        int r;
 
         assert(i);
 
@@ -3727,25 +3783,26 @@ static void print_status_info(
                 printf("      CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
         }
 
-        if (i->control_group &&
-            (i->main_pid > 0 || i->control_pid > 0 ||
-             (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
+        if (i->control_group)
+                printf("   CGroup: %s\n", i->control_group);
+
+        {
+                _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+                static const char prefix[] = "           ";
                 unsigned c;
 
-                printf("   CGroup: %s\n", i->control_group);
+                c = columns();
+                if (c > sizeof(prefix) - 1)
+                        c -= sizeof(prefix) - 1;
+                else
+                        c = 0;
 
-                if (IN_SET(arg_transport,
-                           BUS_TRANSPORT_LOCAL,
-                           BUS_TRANSPORT_MACHINE)) {
+                r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
+                if (r == -EBADR) {
                         unsigned k = 0;
                         pid_t extra[2];
-                        static const char prefix[] = "           ";
 
-                        c = columns();
-                        if (c > sizeof(prefix) - 1)
-                                c -= sizeof(prefix) - 1;
-                        else
-                                c = 0;
+                        /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
 
                         if (i->main_pid > 0)
                                 extra[k++] = i->main_pid;
@@ -3753,8 +3810,9 @@ static void print_status_info(
                         if (i->control_pid > 0)
                                 extra[k++] = i->control_pid;
 
-                        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
-                }
+                        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
+                } else if (r < 0)
+                        log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
         }
 
         if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
@@ -4116,6 +4174,14 @@ skip:
         return 0;
 }
 
+#define print_prop(name, fmt, ...)                                      \
+        do {                                                            \
+                if (arg_value)                                          \
+                        printf(fmt "\n", __VA_ARGS__);                  \
+                else                                                    \
+                        printf("%s=" fmt "\n", name, __VA_ARGS__);      \
+        } while(0)
+
 static int print_property(const char *name, sd_bus_message *m, const char *contents) {
         int r;
 
@@ -4143,9 +4209,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         if (u > 0)
-                                printf("%s=%"PRIu32"\n", name, u);
+                                print_prop(name, "%"PRIu32, u);
                         else if (arg_all)
-                                printf("%s=\n", name);
+                                print_prop(name, "%s", "");
 
                         return 0;
 
@@ -4157,7 +4223,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         if (arg_all || !isempty(s))
-                                printf("%s=%s\n", name, s);
+                                print_prop(name, "%s", s);
 
                         return 0;
 
@@ -4169,7 +4235,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         if (arg_all || !isempty(a) || !isempty(b))
-                                printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
+                                print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
 
                         return 0;
                 } else if (streq_ptr(name, "SystemCallFilter")) {
@@ -4196,8 +4262,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 bool first = true;
                                 char **i;
 
-                                fputs(name, stdout);
-                                fputc('=', stdout);
+                                if (!arg_value) {
+                                        fputs(name, stdout);
+                                        fputc('=', stdout);
+                                }
 
                                 if (!whitelist)
                                         fputc('~', stdout);
@@ -4229,7 +4297,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
-                                printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
+                                print_prop("EnvironmentFile", "%s (ignore_errors=%s)\n", path, yes_no(ignore));
 
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -4248,7 +4316,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                printf("%s=%s\n", type, path);
+                                print_prop(type, "%s", path);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4266,7 +4334,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                printf("Listen%s=%s\n", type, path);
+                                if (arg_value)
+                                        puts(path);
+                                else
+                                        printf("Listen%s=%s\n", type, path);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4287,10 +4358,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                         while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
                                 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
 
-                                printf("%s={ value=%s ; next_elapse=%s }\n",
-                                       base,
-                                       format_timespan(timespan1, sizeof(timespan1), value, 0),
-                                       format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
+                                print_prop(base, "{ value=%s ; next_elapse=%s }",
+                                           format_timespan(timespan1, sizeof(timespan1), value, 0),
+                                           format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
                         }
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -4314,18 +4384,18 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
 
                                 tt = strv_join(info.argv, " ");
 
-                                printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }\n",
-                                       name,
-                                       strna(info.path),
-                                       strna(tt),
-                                       yes_no(info.ignore),
-                                       strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
-                                       strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
-                                       info.pid,
-                                       sigchld_code_to_string(info.code),
-                                       info.status,
-                                       info.code == CLD_EXITED ? "" : "/",
-                                       strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+                                print_prop(name,
+                                           "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+                                           strna(info.path),
+                                           strna(tt),
+                                           yes_no(info.ignore),
+                                           strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+                                           strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+                                           info.pid,
+                                           sigchld_code_to_string(info.code),
+                                           info.status,
+                                           info.code == CLD_EXITED ? "" : "/",
+                                           strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
 
                                 free(info.path);
                                 strv_free(info.argv);
@@ -4346,7 +4416,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
-                                printf("%s=%s %s\n", name, strna(path), strna(rwm));
+                                print_prop(name, "%s %s", strna(path), strna(rwm));
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4365,7 +4435,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
-                                printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
+                                print_prop(name, "%s %"PRIu64, strna(path), weight);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4384,7 +4454,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
-                                printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
+                                print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4398,7 +4468,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                 break;
         }
 
-        r = bus_print_property(name, m, arg_all);
+        r = bus_print_property(name, m, arg_value, arg_all);
         if (r < 0)
                 return bus_log_parse_error(r);
 
@@ -4503,7 +4573,7 @@ static int show_one(
                 if (streq(verb, "help"))
                         show_unit_help(&info);
                 else
-                        print_status_info(&info, ellipsized);
+                        print_status_info(bus, &info, ellipsized);
         }
 
         strv_free(info.documentation);
@@ -4637,8 +4707,8 @@ static int show_system_status(sd_bus *bus) {
         printf("    State: %s%s%s\n",
                on, strna(mi.state), off);
 
-        printf("     Jobs: %u queued\n", mi.n_jobs);
-        printf("   Failed: %u units\n", mi.n_failed_units);
+        printf("     Jobs: %" PRIu32 " queued\n", mi.n_jobs);
+        printf("   Failed: %" PRIu32 " units\n", mi.n_failed_units);
 
         printf("    Since: %s; %s\n",
                format_timestamp(since2, sizeof(since2), mi.timestamp),
@@ -4657,7 +4727,7 @@ static int show_system_status(sd_bus *bus) {
                 else
                         c = 0;
 
-                show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
+                show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
         }
 
         return 0;
@@ -4767,34 +4837,6 @@ static int show(int argc, char *argv[], void *userdata) {
         return ret;
 }
 
-static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
-        int r;
-
-        assert(user_home);
-        assert(user_runtime);
-        assert(lp);
-
-        if (arg_scope == UNIT_FILE_USER) {
-                r = user_config_home(user_home);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
-                else if (r == 0)
-                        return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
-
-                r = user_runtime_dir(user_runtime);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
-                else if (r == 0)
-                        return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
-        }
-
-        r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
-        if (r < 0)
-                return log_error_errno(r, "Failed to query unit lookup paths: %m");
-
-        return 0;
-}
-
 static int cat_file(const char *filename, bool newline) {
         _cleanup_close_ int fd;
 
@@ -4813,8 +4855,6 @@ static int cat_file(const char *filename, bool newline) {
 }
 
 static int cat(int argc, char *argv[], void *userdata) {
-        _cleanup_free_ char *user_home = NULL;
-        _cleanup_free_ char *user_runtime = NULL;
         _cleanup_lookup_paths_free_ LookupPaths lp = {};
         _cleanup_strv_free_ char **names = NULL;
         char **name;
@@ -4827,9 +4867,9 @@ static int cat(int argc, char *argv[], void *userdata) {
                 return -EINVAL;
         }
 
-        r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
+        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to determine unit paths: %m");
 
         r = acquire_bus(BUS_MANAGER, &bus);
         if (r < 0)
@@ -4976,7 +5016,7 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
                  * reply */
                 r = 0;
         else if (r < 0)
-                return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+                return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
 
         return r < 0 ? r : 0;
 }
@@ -5240,8 +5280,10 @@ static int enable_sysv_units(const char *verb, char **args) {
         int r = 0;
 
 #if defined(HAVE_SYSV_COMPAT)
-        unsigned f = 0;
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        unsigned f = 0;
+
+        /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
 
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return 0;
@@ -5255,24 +5297,28 @@ static int enable_sysv_units(const char *verb, char **args) {
                         "is-enabled"))
                 return 0;
 
-        /* Processes all SysV units, and reshuffles the array so that
-         * afterwards only the native units remain */
-
-        r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
+        r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
         if (r < 0)
                 return r;
 
         r = 0;
         while (args[f]) {
-                const char *name;
+
+                const char *argv[] = {
+                        ROOTLIBEXECDIR "/systemd-sysv-install",
+                        NULL,
+                        NULL,
+                        NULL,
+                        NULL,
+                };
+
                 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
                 bool found_native = false, found_sysv;
+                siginfo_t status;
+                const char *name;
                 unsigned c = 1;
-                const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
-                char **k;
-                int j;
                 pid_t pid;
-                siginfo_t status;
+                int j;
 
                 name = args[f++];
 
@@ -5282,21 +5328,13 @@ static int enable_sysv_units(const char *verb, char **args) {
                 if (path_is_absolute(name))
                         continue;
 
-                STRV_FOREACH(k, paths.unit_path) {
-                        _cleanup_free_ char *path = NULL;
-
-                        path = path_join(arg_root, *k, name);
-                        if (!path)
-                                return log_oom();
-
-                        found_native = access(path, F_OK) >= 0;
-                        if (found_native)
-                                break;
-                }
+                j = unit_file_exists(arg_scope, &paths, name);
+                if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
+                        return log_error_errno(j, "Failed to lookup unit file state: %m");
+                found_native = j != 0;
 
-                /* If we have both a native unit and a SysV script,
-                 * enable/disable them both (below); for is-enabled, prefer the
-                 * native unit */
+                /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
+                 * prefer the native unit */
                 if (found_native && streq(verb, "is-enabled"))
                         continue;
 
@@ -5310,9 +5348,9 @@ static int enable_sysv_units(const char *verb, char **args) {
                         continue;
 
                 if (found_native)
-                        log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
+                        log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
                 else
-                        log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
+                        log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
 
                 if (!isempty(arg_root))
                         argv[c++] = q = strappend("--root=", arg_root);
@@ -5325,7 +5363,7 @@ static int enable_sysv_units(const char *verb, char **args) {
                 if (!l)
                         return log_oom();
 
-                log_info("Executing %s", l);
+                log_info("Executing: %s", l);
 
                 pid = fork();
                 if (pid < 0)
@@ -5337,7 +5375,7 @@ static int enable_sysv_units(const char *verb, char **args) {
                         (void) reset_signal_mask();
 
                         execv(argv[0], (char**) argv);
-                        log_error_errno(r, "Failed to execute %s: %m", argv[0]);
+                        log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
                         _exit(EXIT_FAILURE);
                 }
 
@@ -5359,9 +5397,11 @@ static int enable_sysv_units(const char *verb, char **args) {
                                 }
 
                         } else if (status.si_status != 0)
-                                return -EINVAL;
-                } else
+                                return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
+                } else {
+                        log_error("Unexpected waitid() result.");
                         return -EPROTO;
+                }
 
                 if (found_native)
                         continue;
@@ -5419,6 +5459,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
         int carries_install_info = -1;
+        bool ignore_carries_install_info = false;
         int r;
 
         if (!argv[1])
@@ -5432,8 +5473,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        /* If the operation was fully executed by the SysV compat,
-         * let's finish early */
+        /* If the operation was fully executed by the SysV compat, let's finish early */
         if (strv_isempty(names))
                 return 0;
 
@@ -5450,28 +5490,24 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                         r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
                 else if (streq(verb, "preset")) {
                         r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
-                        carries_install_info = r;
                 } else if (streq(verb, "mask"))
                         r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
                 else if (streq(verb, "unmask"))
                         r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
+                else if (streq(verb, "revert"))
+                        r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
                 else
                         assert_not_reached("Unknown verb");
 
-                if (r == -ESHUTDOWN)
-                        return log_error_errno(r, "Unit file is masked.");
+                unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
                 if (r < 0)
-                        return log_error_errno(r, "Operation failed: %m");
-
-                if (!arg_quiet)
-                        dump_unit_file_changes(changes, n_changes);
-
+                        return r;
                 r = 0;
         } else {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                int expect_carries_install_info = false;
-                bool send_force = true, send_preset_mode = false;
+                bool expect_carries_install_info = false;
+                bool send_runtime = true, send_force = true, send_preset_mode = false;
                 const char *method;
                 sd_bus *bus;
 
@@ -5501,11 +5537,15 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                                 method = "PresetUnitFiles";
 
                         expect_carries_install_info = true;
+                        ignore_carries_install_info = true;
                 } else if (streq(verb, "mask"))
                         method = "MaskUnitFiles";
                 else if (streq(verb, "unmask")) {
                         method = "UnmaskUnitFiles";
                         send_force = false;
+                } else if (streq(verb, "revert")) {
+                        method = "RevertUnitFiles";
+                        send_runtime = send_force = false;
                 } else
                         assert_not_reached("Unknown verb");
 
@@ -5529,9 +5569,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                                 return bus_log_create_error(r);
                 }
 
-                r = sd_bus_message_append(m, "b", arg_runtime);
-                if (r < 0)
-                        return bus_log_create_error(r);
+                if (send_runtime) {
+                        r = sd_bus_message_append(m, "b", arg_runtime);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
 
                 if (send_force) {
                         r = sd_bus_message_append(m, "b", arg_force);
@@ -5541,7 +5583,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
 
                 r = sd_bus_call(bus, m, 0, &error, &reply);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+                        return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
 
                 if (expect_carries_install_info) {
                         r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5560,16 +5602,19 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                         r = 0;
         }
 
-        if (carries_install_info == 0)
-                log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
-                            "using systemctl.\n"
+        if (carries_install_info == 0 && !ignore_carries_install_info)
+                log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
+                            "settings in the [Install] section, and DefaultInstance for template units).\n"
+                            "This means they are not meant to be enabled using systemctl.\n"
                             "Possible reasons for having this kind of units are:\n"
                             "1) A unit may be statically enabled by being symlinked from another unit's\n"
                             "   .wants/ or .requires/ directory.\n"
                             "2) A unit's purpose may be to act as a helper for some other unit which has\n"
                             "   a requirement dependency on it.\n"
                             "3) A unit may be started when needed via activation (socket, path, timer,\n"
-                            "   D-Bus, udev, scripted systemctl call, ...).\n");
+                            "   D-Bus, udev, scripted systemctl call, ...).\n"
+                            "4) In case of template units, the unit is meant to be enabled with some\n"
+                            "   instance name specified.");
 
         if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
                 char *new_args[n_changes + 2];
@@ -5624,16 +5669,9 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
                 unsigned n_changes = 0;
 
                 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
-                if (r == -ESHUTDOWN)
-                        return log_error_errno(r, "Unit file is masked.");
-                if (r < 0)
-                        return log_error_errno(r, "Can't add dependency: %m");
-
-                if (!arg_quiet)
-                        dump_unit_file_changes(changes, n_changes);
-
+                unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
                 unit_file_changes_free(changes, n_changes);
-
+                return r;
         } else {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -5665,39 +5703,29 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
 
                 r = sd_bus_call(bus, m, 0, &error, &reply);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+                        return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
 
                 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
                 if (r < 0)
                         return r;
 
-                if (!arg_no_reload)
-                        r = daemon_reload(argc, argv, userdata);
-                else
-                        r = 0;
+                if (arg_no_reload)
+                        return 0;
+                return daemon_reload(argc, argv, userdata);
         }
-
-        return r;
 }
 
 static int preset_all(int argc, char *argv[], void *userdata) {
-        UnitFileChange *changes = NULL;
-        unsigned n_changes = 0;
         int r;
 
         if (install_client_side()) {
+                UnitFileChange *changes = NULL;
+                unsigned n_changes = 0;
 
                 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
-                if (r < 0) {
-                        log_error_errno(r, "Operation failed: %m");
-                        goto finish;
-                }
-
-                if (!arg_quiet)
-                        dump_unit_file_changes(changes, n_changes);
-
-                r = 0;
-
+                unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
+                unit_file_changes_free(changes, n_changes);
+                return r;
         } else {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -5722,22 +5750,16 @@ static int preset_all(int argc, char *argv[], void *userdata) {
                                 arg_runtime,
                                 arg_force);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+                        return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
 
                 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
                 if (r < 0)
                         return r;
 
-                if (!arg_no_reload)
-                        r = daemon_reload(argc, argv, userdata);
-                else
-                        r = 0;
+                if (arg_no_reload)
+                        return 0;
+                return daemon_reload(argc, argv, userdata);
         }
-
-finish:
-        unit_file_changes_free(changes, n_changes);
-
-        return r;
 }
 
 static int unit_is_enabled(int argc, char *argv[], void *userdata) {
@@ -5770,7 +5792,8 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                                    UNIT_FILE_ENABLED,
                                    UNIT_FILE_ENABLED_RUNTIME,
                                    UNIT_FILE_STATIC,
-                                   UNIT_FILE_INDIRECT))
+                                   UNIT_FILE_INDIRECT,
+                                   UNIT_FILE_GENERATED))
                                 enabled = true;
 
                         if (!arg_quiet)
@@ -5805,7 +5828,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
+                        if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
                                 enabled = true;
 
                         if (!arg_quiet)
@@ -5813,7 +5836,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                 }
         }
 
-        return !enabled;
+        return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 static int is_system_running(int argc, char *argv[], void *userdata) {
@@ -5883,52 +5906,32 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
         return 0;
 }
 
-static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
-        _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
+static int get_file_to_edit(
+                const LookupPaths *paths,
+                const char *name,
+                char **ret_path) {
+
+        _cleanup_free_ char *path = NULL, *run = NULL;
 
         assert(name);
         assert(ret_path);
 
-        switch (arg_scope) {
-                case UNIT_FILE_SYSTEM:
-                        path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
-                        if (arg_runtime)
-                                run = path_join(arg_root, "/run/systemd/system/", name);
-                        break;
-                case UNIT_FILE_GLOBAL:
-                        path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
-                        if (arg_runtime)
-                                run = path_join(arg_root, "/run/systemd/user/", name);
-                        break;
-                case UNIT_FILE_USER:
-                        assert(user_home);
-                        assert(user_runtime);
-
-                        path = path_join(arg_root, user_home, name);
-                        if (arg_runtime) {
-                                path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
-                                if (!path2)
-                                        return log_oom();
-                                run = path_join(arg_root, user_runtime, name);
-                        }
-                        break;
-                default:
-                        assert_not_reached("Invalid scope");
-        }
-        if (!path || (arg_runtime && !run))
+        path = strjoin(paths->persistent_config, "/", name, NULL);
+        if (!path)
                 return log_oom();
 
+        if (arg_runtime) {
+                run = strjoin(paths->runtime_config, name, NULL);
+                if (!run)
+                        return log_oom();
+        }
+
         if (arg_runtime) {
                 if (access(path, F_OK) >= 0) {
                         log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
                         return -EEXIST;
                 }
 
-                if (path2 && access(path2, F_OK) >= 0) {
-                        log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
-                        return -EEXIST;
-                }
-
                 *ret_path = run;
                 run = NULL;
         } else {
@@ -5939,7 +5942,12 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
         return 0;
 }
 
-static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
+static int unit_file_create_dropin(
+                const LookupPaths *paths,
+                const char *unit_name,
+                char **ret_new_path,
+                char **ret_tmp_path) {
+
         char *tmp_new_path, *tmp_tmp_path, *ending;
         int r;
 
@@ -5948,7 +5956,7 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
         assert(ret_tmp_path);
 
         ending = strjoina(unit_name, ".d/override.conf");
-        r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
+        r = get_file_to_edit(paths, ending, &tmp_new_path);
         if (r < 0)
                 return r;
 
@@ -5965,10 +5973,9 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
 }
 
 static int unit_file_create_copy(
+                const LookupPaths *paths,
                 const char *unit_name,
                 const char *fragment_path,
-                const char *user_home,
-                const char *user_runtime,
                 char **ret_new_path,
                 char **ret_tmp_path) {
 
@@ -5980,7 +5987,7 @@ static int unit_file_create_copy(
         assert(ret_new_path);
         assert(ret_tmp_path);
 
-        r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
+        r = get_file_to_edit(paths, unit_name, &tmp_new_path);
         if (r < 0)
                 return r;
 
@@ -6095,8 +6102,6 @@ static int run_editor(char **paths) {
 }
 
 static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
-        _cleanup_free_ char *user_home = NULL;
-        _cleanup_free_ char *user_runtime = NULL;
         _cleanup_lookup_paths_free_ LookupPaths lp = {};
         char **name;
         int r;
@@ -6104,13 +6109,12 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
         assert(names);
         assert(paths);
 
-        r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
+        r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
         if (r < 0)
                 return r;
 
         STRV_FOREACH(name, names) {
-                _cleanup_free_ char *path = NULL;
-                char *new_path, *tmp_path;
+                _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL;
 
                 r = unit_find_paths(bus, *name, &lp, &path, NULL);
                 if (r < 0)
@@ -6124,15 +6128,16 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                 }
 
                 if (arg_full)
-                        r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
+                        r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
                 else
-                        r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
+                        r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path);
                 if (r < 0)
                         return r;
 
                 r = strv_push_pair(paths, new_path, tmp_path);
                 if (r < 0)
                         return log_oom();
+                new_path = tmp_path = NULL;
         }
 
         return 0;
@@ -6243,6 +6248,7 @@ static void systemctl_help(void) {
                "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
                "                      queueing a new job\n"
                "     --show-types     When showing sockets, explicitly show their type\n"
+               "     --value          When showing properties, only print the value\n"
                "  -i --ignore-inhibitors\n"
                "                      When shutting down or sleeping, ignore inhibitors\n"
                "     --kill-who=WHO   Who to send signal to\n"
@@ -6310,6 +6316,8 @@ static void systemctl_help(void) {
                "  unmask NAME...                  Unmask one or more units\n"
                "  link PATH...                    Link one or more units files into\n"
                "                                  the search path\n"
+               "  revert NAME...                  Revert one or more unit files to vendor\n"
+               "                                  version\n"
                "  add-wants TARGET NAME...        Add 'Wants' dependency for the target\n"
                "                                  on specified one or more units\n"
                "  add-requires TARGET NAME...     Add 'Requires' dependency for the target\n"
@@ -6494,6 +6502,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_SHOW_TYPES,
                 ARG_IRREVERSIBLE,
                 ARG_IGNORE_DEPENDENCIES,
+                ARG_VALUE,
                 ARG_VERSION,
                 ARG_USER,
                 ARG_SYSTEM,
@@ -6535,6 +6544,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "irreversible",        no_argument,       NULL, ARG_IRREVERSIBLE        }, /* compatibility only */
                 { "ignore-dependencies", no_argument,       NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
                 { "ignore-inhibitors",   no_argument,       NULL, 'i'                     },
+                { "value",               no_argument,       NULL, ARG_VALUE               },
                 { "user",                no_argument,       NULL, ARG_USER                },
                 { "system",              no_argument,       NULL, ARG_SYSTEM              },
                 { "global",              no_argument,       NULL, ARG_GLOBAL              },
@@ -6686,6 +6696,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_show_types = true;
                         break;
 
+                case ARG_VALUE:
+                        arg_value = true;
+                        break;
+
                 case ARG_JOB_MODE:
                         arg_job_mode = optarg;
                         break;
@@ -6731,7 +6745,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        r = parse_path_argument_and_warn(optarg, false, &arg_root);
                         if (r < 0)
                                 return r;
                         break;
@@ -6972,7 +6986,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 }
 
         if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
-                r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
+                r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
                 if (r < 0)
                         return r;
         } else if (optind < argc) {
@@ -7427,6 +7441,7 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "mask",                  2,        VERB_ANY, 0,             enable_unit       },
                 { "unmask",                2,        VERB_ANY, 0,             enable_unit       },
                 { "link",                  2,        VERB_ANY, 0,             enable_unit       },
+                { "revert",                2,        VERB_ANY, 0,             enable_unit       },
                 { "switch-root",           2,        VERB_ANY, VERB_NOCHROOT, switch_root       },
                 { "list-dependencies",     VERB_ANY, 2,        VERB_NOCHROOT, list_dependencies },
                 { "set-default",           2,        2,        0,             set_default       },
@@ -7473,6 +7488,7 @@ static int start_with_fallback(void) {
 }
 
 static int halt_now(enum action a) {
+        int r;
 
         /* The kernel will automaticall flush ATA disks and suchlike
          * on reboot(), but the file systems need to be synce'd
@@ -7499,9 +7515,14 @@ static int halt_now(enum action a) {
         case ACTION_REBOOT: {
                 _cleanup_free_ char *param = NULL;
 
-                if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+                r = read_one_line_file("/run/systemd/reboot-param", &param);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to read reboot parameter file: %m");
+
+                if (!isempty(param)) {
                         log_info("Rebooting with argument '%s'.", param);
                         (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
+                        log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
                 }
 
                 log_info("Rebooting.");
index ef45370505dad6422cdaa762a9efc8de03989128..374ff8774e8b8c089690e9fa4a1ac2c3b0ba7e53 100644 (file)
@@ -98,6 +98,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
                            size_t addr_len, uint16_t arp_type);
 int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
                                  const uint8_t *data, size_t data_len);
+int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, uint32_t iaid,
+                                 uint16_t duid_type, uint8_t *duid, size_t duid_len);
 int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
                                  const uint8_t **data, size_t *data_len);
 int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
index 1bedc941aa8670de337c741b6e71faf3e0a73468..4604cb6382f0b8e571813f384df8c0aaa7901f17 100644 (file)
@@ -85,8 +85,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
 int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
 int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
                             size_t addr_len, uint16_t arp_type);
-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
-                             size_t duid_len);
+int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t duid_type,
+                             uint8_t *duid, size_t duid_len);
+int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid);
 int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled);
 int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled);
 int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
index d4c6f409cd3737e80d1d80b29eedad0334e4114a..9c36b271573d256af16b8c720bc60d1e5d0677da 100644 (file)
@@ -67,10 +67,11 @@ typedef struct sd_journal sd_journal;
 
 /* Open flags */
 enum {
-        SD_JOURNAL_LOCAL_ONLY = 1,
-        SD_JOURNAL_RUNTIME_ONLY = 2,
-        SD_JOURNAL_SYSTEM = 4,
-        SD_JOURNAL_CURRENT_USER = 8,
+        SD_JOURNAL_LOCAL_ONLY   = 1 << 0,
+        SD_JOURNAL_RUNTIME_ONLY = 1 << 1,
+        SD_JOURNAL_SYSTEM       = 1 << 2,
+        SD_JOURNAL_CURRENT_USER = 1 << 3,
+        SD_JOURNAL_OS_ROOT      = 1 << 4,
 
         SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */
 };
@@ -84,8 +85,10 @@ enum {
 
 int sd_journal_open(sd_journal **ret, int flags);
 int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
+int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags);
 int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
-int sd_journal_open_container(sd_journal **ret, const char *machine, int flags);
+int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags);
+int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); /* deprecated */
 void sd_journal_close(sd_journal *j);
 
 int sd_journal_previous(sd_journal *j);
index 4f2a3b50c087fcf7f32779b18c9acfb909ab4cd5..5772d5794a19380f67906606e6a374500b030633 100644 (file)
@@ -33,20 +33,18 @@ _SD_BEGIN_DECLARATIONS;
 typedef struct sd_lldp sd_lldp;
 typedef struct sd_lldp_neighbor sd_lldp_neighbor;
 
-#define SD_LLDP_MULTICAST_ADDR     { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-
 /* IEEE 802.3AB Clause 9: TLV Types */
 enum {
-        SD_LLDP_TYPE_END                  =   0,
-        SD_LLDP_TYPE_CHASSIS_ID           =   1,
-        SD_LLDP_TYPE_PORT_ID              =   2,
-        SD_LLDP_TYPE_TTL                  =   3,
-        SD_LLDP_TYPE_PORT_DESCRIPTION     =   4,
-        SD_LLDP_TYPE_SYSTEM_NAME          =   5,
-        SD_LLDP_TYPE_SYSTEM_DESCRIPTION   =   6,
-        SD_LLDP_TYPE_SYSTEM_CAPABILITIES  =   7,
-        SD_LLDP_TYPE_MGMT_ADDRESS         =   8,
-        SD_LLDP_TYPE_PRIVATE              =   127,
+        SD_LLDP_TYPE_END                 = 0,
+        SD_LLDP_TYPE_CHASSIS_ID          = 1,
+        SD_LLDP_TYPE_PORT_ID             = 2,
+        SD_LLDP_TYPE_TTL                 = 3,
+        SD_LLDP_TYPE_PORT_DESCRIPTION    = 4,
+        SD_LLDP_TYPE_SYSTEM_NAME         = 5,
+        SD_LLDP_TYPE_SYSTEM_DESCRIPTION  = 6,
+        SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
+        SD_LLDP_TYPE_MGMT_ADDRESS        = 8,
+        SD_LLDP_TYPE_PRIVATE             = 127,
 };
 
 /* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
@@ -63,28 +61,28 @@ enum {
 
 /* IEEE 802.3AB Clause 9.5.3: Port subtype */
 enum {
-        SD_LLDP_PORT_SUBTYPE_RESERVED           = 0,
-        SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS    = 1,
-        SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT     = 2,
-        SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS        = 3,
-        SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS    = 4,
-        SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME     = 5,
-        SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID   = 6,
-        SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED   = 7,
+        SD_LLDP_PORT_SUBTYPE_RESERVED         = 0,
+        SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS  = 1,
+        SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT   = 2,
+        SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS      = 3,
+        SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS  = 4,
+        SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME   = 5,
+        SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
+        SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
 };
 
 enum {
-        SD_LLDP_SYSTEM_CAPABILITIES_OTHER        = 1 << 0,
-        SD_LLDP_SYSTEM_CAPABILITIES_REPEATER     = 1 << 1,
-        SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE       = 1 << 2,
-        SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP      = 1 << 3,
-        SD_LLDP_SYSTEM_CAPABILITIES_ROUTER       = 1 << 4,
-        SD_LLDP_SYSTEM_CAPABILITIES_PHONE        = 1 << 5,
-        SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS       = 1 << 6,
-        SD_LLDP_SYSTEM_CAPABILITIES_STATION      = 1 << 7,
-        SD_LLDP_SYSTEM_CAPABILITIES_CVLAN        = 1 << 8,
-        SD_LLDP_SYSTEM_CAPABILITIES_SVLAN        = 1 << 9,
-        SD_LLDP_SYSTEM_CAPABILITIES_TPMR         = 1 << 10,
+        SD_LLDP_SYSTEM_CAPABILITIES_OTHER    = 1 << 0,
+        SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
+        SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE   = 1 << 2,
+        SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP  = 1 << 3,
+        SD_LLDP_SYSTEM_CAPABILITIES_ROUTER   = 1 << 4,
+        SD_LLDP_SYSTEM_CAPABILITIES_PHONE    = 1 << 5,
+        SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS   = 1 << 6,
+        SD_LLDP_SYSTEM_CAPABILITIES_STATION  = 1 << 7,
+        SD_LLDP_SYSTEM_CAPABILITIES_CVLAN    = 1 << 8,
+        SD_LLDP_SYSTEM_CAPABILITIES_SVLAN    = 1 << 9,
+        SD_LLDP_SYSTEM_CAPABILITIES_TPMR     = 1 << 10,
 };
 
 #define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
@@ -100,18 +98,17 @@ enum {
           SD_LLDP_SYSTEM_CAPABILITIES_SVLAN|                            \
           SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
 
-
 #define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
 #define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
 
 enum {
-        SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID            = 1,
-        SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID   = 2,
-        SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME               = 3,
-        SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY       = 4,
-        SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST        = 5,
-        SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID          = 6,
-        SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION        = 7,
+        SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID          = 1,
+        SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
+        SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME             = 3,
+        SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY     = 4,
+        SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST      = 5,
+        SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID        = 6,
+        SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION      = 7,
 };
 
 typedef enum sd_lldp_event {
index 59e1a3e92199e9f00a865cf486d3d1443816241b..fe4bbeeb75ff15d8bdc4e8da34b5f95b93e39424 100644 (file)
@@ -729,14 +729,50 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
         return 0;
 }
 
+static int acquire_search_path(const char *def, const char *envvar, char ***ret) {
+        _cleanup_strv_free_ char **l = NULL;
+        const char *e;
+        int r;
+
+        assert(def);
+        assert(envvar);
+
+        e = getenv(envvar);
+        if (e) {
+                r = path_split_and_make_absolute(e, &l);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to make $%s search path absolute: %m", envvar);
+        }
+
+        if (strv_isempty(l)) {
+                strv_free(l);
+
+                l = strv_new(def, NULL);
+                if (!l)
+                        return log_oom();
+        }
+
+        if (!path_strv_resolve_uniq(l, NULL))
+                return log_oom();
+
+        *ret = l;
+        l = NULL;
+
+        return 0;
+}
+
 static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
+        _cleanup_strv_free_ char **sysvinit_path = NULL;
         char **path;
         int r;
 
         assert(lp);
-        assert(all_services);
 
-        STRV_FOREACH(path, lp->sysvinit_path) {
+        r = acquire_search_path(SYSTEM_SYSVINIT_PATH, "SYSTEMD_SYSVINIT_PATH", &sysvinit_path);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(path, sysvinit_path) {
                 _cleanup_closedir_ DIR *d = NULL;
                 struct dirent *de;
 
@@ -770,11 +806,11 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                         if (hashmap_contains(all_services, name))
                                 continue;
 
-                        r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL);
-                        if (r < 0 && r != -ENOENT) {
+                        r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name);
+                        if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) {
                                 log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
                                 continue;
-                        } else if (r >= 0) {
+                        } else if (r != 0) {
                                 log_debug("Native unit for %s already exists, skipping.", name);
                                 continue;
                         }
@@ -806,6 +842,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
 static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
         Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
         _cleanup_set_free_ Set *shutdown_services = NULL;
+        _cleanup_strv_free_ char **sysvrcnd_path = NULL;
         SysvStub *service;
         unsigned i;
         Iterator j;
@@ -814,7 +851,11 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
 
         assert(lp);
 
-        STRV_FOREACH(p, lp->sysvrcnd_path) {
+        r = acquire_search_path(SYSTEM_SYSVRCND_PATH, "SYSTEMD_SYSVRCND_PATH", &sysvrcnd_path);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(p, sysvrcnd_path) {
                 for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
 
                         _cleanup_closedir_ DIR *d = NULL;
@@ -963,7 +1004,7 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
-        r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
+        r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
         if (r < 0) {
                 log_error_errno(r, "Failed to find lookup paths: %m");
                 goto finish;
index ad15075a5b49d55f987d7f024891ffbbdebddbda..4eb8fcd77340048785b9d66b4436bdbe3f722fe4 100644 (file)
@@ -21,7 +21,9 @@
 
 #include "macro.h"
 #include "manager.h"
+#include "rm-rf.h"
 #include "test-helper.h"
+#include "tests.h"
 #include "unit.h"
 
 static int test_cgroup_mask(void) {
@@ -33,7 +35,7 @@ static int test_cgroup_mask(void) {
 
         /* Prepare the manager. */
         assert_se(set_unit_path(TEST_DIR) >= 0);
-        r = manager_new(MANAGER_USER, true, &m);
+        r = manager_new(UNIT_FILE_USER, true, &m);
         if (r == -EPERM || r == -EACCES) {
                 puts("manager_new: Permission denied. Skipping test.");
                 return EXIT_TEST_SKIP;
@@ -107,7 +109,11 @@ static int test_cgroup_mask(void) {
 }
 
 int main(int argc, char* argv[]) {
+        _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
         int rc = 0;
+
+        assert_se(runtime_dir = setup_fake_runtime_dir());
         TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
+
         return rc;
 }
index cb437754b4dc3667e5731b85d14148b40dd8e6fb..68154fc4e82efa40b06eb3ece23367554fb933bb 100644 (file)
@@ -95,6 +95,8 @@ static void test_copy_tree(void) {
         char **links = STRV_MAKE("link", "file",
                                  "link2", "dir1/file");
         char **p, **link;
+        const char *unixsockp;
+        struct stat st;
 
         log_info("%s", __func__);
 
@@ -102,26 +104,34 @@ static void test_copy_tree(void) {
         (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
 
         STRV_FOREACH(p, files) {
-                char *f = strjoina(original_dir, *p);
+                _cleanup_free_ char *f;
+
+                assert_se(f = strappend(original_dir, *p));
 
                 assert_se(mkdir_parents(f, 0755) >= 0);
                 assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0);
         }
 
         STRV_FOREACH_PAIR(link, p, links) {
-                char *f = strjoina(original_dir, *p);
-                char *l = strjoina(original_dir, *link);
+                _cleanup_free_ char *f, *l;
+
+                assert_se(f = strappend(original_dir, *p));
+                assert_se(l = strappend(original_dir, *link));
 
                 assert_se(mkdir_parents(l, 0755) >= 0);
                 assert_se(symlink(f, l) == 0);
         }
 
+        unixsockp = strjoina(original_dir, "unixsock");
+        assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
+
         assert_se(copy_tree(original_dir, copy_dir, true) == 0);
 
         STRV_FOREACH(p, files) {
-                _cleanup_free_ char *buf = NULL;
+                _cleanup_free_ char *buf = NULL, *f;
                 size_t sz = 0;
-                char *f = strjoina(copy_dir, *p);
+
+                assert_se(f = strappend(copy_dir, *p));
 
                 assert_se(access(f, F_OK) == 0);
                 assert_se(read_full_file(f, &buf, &sz) == 0);
@@ -129,14 +139,19 @@ static void test_copy_tree(void) {
         }
 
         STRV_FOREACH_PAIR(link, p, links) {
-                _cleanup_free_ char *target = NULL;
-                char *f = strjoina(original_dir, *p);
-                char *l = strjoina(copy_dir, *link);
+                _cleanup_free_ char *target = NULL, *f, *l;
+
+                assert_se(f = strjoin(original_dir, *p, NULL));
+                assert_se(l = strjoin(copy_dir, *link, NULL));
 
                 assert_se(readlink_and_canonicalize(l, &target) == 0);
                 assert_se(path_equal(f, target));
         }
 
+        unixsockp = strjoina(copy_dir, "unixsock");
+        assert_se(stat(unixsockp, &st) >= 0);
+        assert_se(S_ISSOCK(st.st_mode));
+
         assert_se(copy_tree(original_dir, copy_dir, false) < 0);
         assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
 
index ca66f5b684693e7464b4131565962fd0cd48a1d1..361d1e7b0beacdd799569890b09e9fb75a6092ca 100644 (file)
 
 #include "bus-util.h"
 #include "manager.h"
+#include "rm-rf.h"
 #include "test-helper.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
+        _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
         Manager *m = NULL;
         Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
@@ -34,9 +37,11 @@ int main(int argc, char *argv[]) {
         Job *j;
         int r;
 
+        assert_se(runtime_dir = setup_fake_runtime_dir());
+
         /* prepare the test */
         assert_se(set_unit_path(TEST_DIR) >= 0);
-        r = manager_new(MANAGER_USER, true, &m);
+        r = manager_new(UNIT_FILE_USER, true, &m);
         if (MANAGER_SKIP_TEST(r)) {
                 printf("Skipping test: manager_new: %s\n", strerror(-r));
                 return EXIT_TEST_SKIP;
index 901cc44af6d284d9598ea927fdb5c379d5776189..77ef4e8b2acf1cc3e3bff4c041baa40506ffa511 100644 (file)
@@ -291,14 +291,14 @@ static void test_exec_spec_interpolation(Manager *m) {
         test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
 }
 
-static int run_tests(ManagerRunningAs running_as, test_function_t *tests) {
+static int run_tests(UnitFileScope scope, test_function_t *tests) {
         test_function_t *test = NULL;
         Manager *m = NULL;
         int r;
 
         assert_se(tests);
 
-        r = manager_new(running_as, true, &m);
+        r = manager_new(scope, true, &m);
         if (MANAGER_SKIP_TEST(r)) {
                 printf("Skipping test: manager_new: %s\n", strerror(-r));
                 return EXIT_TEST_SKIP;
@@ -366,9 +366,9 @@ int main(int argc, char *argv[]) {
         assert_se(unsetenv("VAR2") == 0);
         assert_se(unsetenv("VAR3") == 0);
 
-        r = run_tests(MANAGER_USER, user_tests);
+        r = run_tests(UNIT_FILE_USER, user_tests);
         if (r != 0)
                 return r;
 
-        return run_tests(MANAGER_SYSTEM, system_tests);
+        return run_tests(UNIT_FILE_SYSTEM, system_tests);
 }
index cd250ca7b874a6608cc876c39e0a8058e25cac32..4680b0336d1f499a994c8715152e354887d17920 100644 (file)
@@ -30,6 +30,8 @@ static void test_basic_mask_and_enable(const char *root) {
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
 
+        log_set_max_level(LOG_DEBUG);
+
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT);
@@ -78,7 +80,7 @@ static void test_basic_mask_and_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
 
         /* Enabling a masked unit should fail! */
-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN);
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL);
         unit_file_changes_free(changes, n_changes);
         changes = NULL; n_changes = 0;
 
@@ -105,7 +107,7 @@ static void test_basic_mask_and_enable(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
 
         /* Enabling it again should succeed but be a NOP */
-        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
         assert_se(n_changes == 0);
         unit_file_changes_free(changes, n_changes);
         changes = NULL; n_changes = 0;
@@ -604,7 +606,7 @@ static void test_preset_and_list(const char *root) {
         assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
 
         assert_se(h = hashmap_new(&string_hash_ops));
-        assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0);
+        assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0);
 
         p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
         q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
@@ -628,6 +630,57 @@ static void test_preset_and_list(const char *root) {
         assert_se(got_yes && got_no);
 }
 
+static void test_revert(const char *root) {
+        const char *p;
+        UnitFileState state;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+
+        assert(root);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/xx.service");
+        assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC);
+
+        /* Initially there's nothing to revert */
+        assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 0);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service");
+        assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        /* Revert the override file */
+        assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf");
+        assert_se(mkdir_parents(p, 0755) >= 0);
+        assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        /* Revert the dropin file */
+        assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 2);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        assert_se(streq(changes[0].path, p));
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d");
+        assert_se(changes[1].type == UNIT_FILE_UNLINK);
+        assert_se(streq(changes[1].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+}
+
 int main(int argc, char *argv[]) {
         char root[] = "/tmp/rootXXXXXX";
         const char *p;
@@ -656,6 +709,7 @@ int main(int argc, char *argv[]) {
         test_template_enable(root);
         test_indirect(root);
         test_preset_and_list(root);
+        test_revert(root);
 
         assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 
index 874d617621c2205e129c0681cdfb60f9dad5a9c5..0ac85f040acf1a38b4e207117aabf839cec71b9d 100644 (file)
@@ -46,8 +46,11 @@ int main(int argc, char* argv[]) {
         unsigned n_changes = 0;
         UnitFileState state = 0;
 
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+
         h = hashmap_new(&string_hash_ops);
-        r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+        r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
         assert_se(r == 0);
 
         HASHMAP_FOREACH(p, h, i) {
@@ -65,12 +68,12 @@ int main(int argc, char* argv[]) {
 
         unit_file_list_free(h);
 
-        log_error("enable");
+        log_info("/*** enable **/");
 
         r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
         assert_se(r >= 0);
 
-        log_error("enable2");
+        log_info("/*** enable2 **/");
 
         r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
         assert_se(r >= 0);
@@ -82,8 +85,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_ENABLED);
 
-        log_error("disable");
-
+        log_info("/*** disable ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -97,13 +99,13 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_DISABLED);
 
-        log_error("mask");
+        log_info("/*** mask ***/");
         changes = NULL;
         n_changes = 0;
 
         r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
         assert_se(r >= 0);
-        log_error("mask2");
+        log_info("/*** mask2 ***/");
         r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
         assert_se(r >= 0);
 
@@ -114,13 +116,13 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_MASKED);
 
-        log_error("unmask");
+        log_info("/*** unmask ***/");
         changes = NULL;
         n_changes = 0;
 
         r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
         assert_se(r >= 0);
-        log_error("unmask2");
+        log_info("/*** unmask2 ***/");
         r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
         assert_se(r >= 0);
 
@@ -131,7 +133,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_DISABLED);
 
-        log_error("mask");
+        log_info("/*** mask ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -145,13 +147,13 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_MASKED);
 
-        log_error("disable");
+        log_info("/*** disable ***/");
         changes = NULL;
         n_changes = 0;
 
         r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
         assert_se(r >= 0);
-        log_error("disable2");
+        log_info("/*** disable2 ***/");
         r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
         assert_se(r >= 0);
 
@@ -162,7 +164,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_MASKED);
 
-        log_error("umask");
+        log_info("/*** umask ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -176,7 +178,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_DISABLED);
 
-        log_error("enable files2");
+        log_info("/*** enable files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -190,7 +192,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_ENABLED);
 
-        log_error("disable files2");
+        log_info("/*** disable files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -203,7 +205,7 @@ int main(int argc, char* argv[]) {
         r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
         assert_se(r < 0);
 
-        log_error("link files2");
+        log_info("/*** link files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -217,7 +219,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_LINKED);
 
-        log_error("disable files2");
+        log_info("/*** disable files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -230,7 +232,7 @@ int main(int argc, char* argv[]) {
         r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
         assert_se(r < 0);
 
-        log_error("link files2");
+        log_info("/*** link files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -244,7 +246,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_LINKED);
 
-        log_error("reenable files2");
+        log_info("/*** reenable files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -258,7 +260,7 @@ int main(int argc, char* argv[]) {
         assert_se(r >= 0);
         assert_se(state == UNIT_FILE_ENABLED);
 
-        log_error("disable files2");
+        log_info("/*** disable files2 ***/");
         changes = NULL;
         n_changes = 0;
 
@@ -270,7 +272,7 @@ int main(int argc, char* argv[]) {
 
         r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
         assert_se(r < 0);
-        log_error("preset files");
+        log_info("/*** preset files ***/");
         changes = NULL;
         n_changes = 0;
 
index 0b2f9e9173fa7cbb902a918db93a66ec517db2c1..ff9f35cecd2adebb4866be237488b0d92be7ef73 100644 (file)
@@ -69,8 +69,10 @@ static void test_netns(void) {
         int r, n = 0;
         siginfo_t si;
 
-        if (geteuid() > 0)
-                return;
+        if (geteuid() > 0) {
+                log_info("Skipping test: not root");
+                exit(EXIT_TEST_SKIP);
+        }
 
         assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
 
@@ -124,6 +126,9 @@ int main(int argc, char *argv[]) {
         char boot_id[SD_ID128_STRING_MAX];
         _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
 
+        log_parse_environment();
+        log_open();
+
         assert_se(sd_id128_get_boot(&bid) >= 0);
         sd_id128_to_string(bid, boot_id);
 
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
new file mode 100644 (file)
index 0000000..55af592
--- /dev/null
@@ -0,0 +1,454 @@
+/***
+  This file is part of systemd.
+
+  Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <net/if.h>
+
+#include "log.h"
+#include "nss-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "alloc-util.h"
+#include "in-addr-util.h"
+#include "hexdecoct.h"
+#include "af-list.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "errno-list.h"
+#include "hostname-util.h"
+#include "local-addresses.h"
+
+static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
+        switch (status) {
+        case NSS_STATUS_TRYAGAIN:
+                return "NSS_STATUS_TRYAGAIN";
+        case NSS_STATUS_UNAVAIL:
+                return "NSS_STATUS_UNAVAIL";
+        case NSS_STATUS_NOTFOUND:
+                return "NSS_STATUS_NOTFOUND";
+        case NSS_STATUS_SUCCESS:
+                return "NSS_STATUS_SUCCESS";
+        case NSS_STATUS_RETURN:
+                return "NSS_STATUS_RETURN";
+        default:
+                snprintf(buf, buf_len, "%i", status);
+                return buf;
+        }
+};
+
+static const char* af_to_string(int family, char *buf, size_t buf_len) {
+        const char *name;
+
+        if (family == AF_UNSPEC)
+                return "*";
+
+        name = af_to_name(family);
+        if (name)
+                return name;
+
+        snprintf(buf, buf_len, "%i", family);
+        return buf;
+}
+
+static void* open_handle(const char* dir, const char* module, int flags) {
+        const char *path;
+        void *handle;
+
+        if (dir)
+                path = strjoina(dir, "/.libs/libnss_", module, ".so.2");
+        else
+                path = strjoina("libnss_", module, ".so.2");
+
+        handle = dlopen(path, flags);
+        assert_se(handle);
+        return handle;
+}
+
+static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
+        const struct gaih_addrtuple *it;
+        int n = 0;
+
+        for (it = tuples; it; it = it->next) {
+                _cleanup_free_ char *a = NULL;
+                union in_addr_union u;
+                int r;
+                char family_name[DECIMAL_STR_MAX(int)];
+                char ifname[IF_NAMESIZE];
+
+                memcpy(&u, it->addr, 16);
+                r = in_addr_to_string(it->family, &u, &a);
+                assert_se(r == 0 || r == -EAFNOSUPPORT);
+                if (r == -EAFNOSUPPORT)
+                        assert_se((a = hexmem(it->addr, 16)));
+
+                if (it->scopeid == 0)
+                        goto numerical_index;
+
+                if (if_indextoname(it->scopeid, ifname) == NULL) {
+                        log_warning("if_indextoname(%d) failed: %m", it->scopeid);
+                numerical_index:
+                        xsprintf(ifname, "%i", it->scopeid);
+                };
+
+                log_info("        \"%s\" %s %s %%%s",
+                         it->name,
+                         af_to_string(it->family, family_name, sizeof family_name),
+                         a,
+                         ifname);
+                n ++;
+        }
+        return n;
+}
+
+static void print_struct_hostent(struct hostent *host, const char *canon) {
+        char **s;
+
+        log_info("        \"%s\"", host->h_name);
+        STRV_FOREACH(s, host->h_aliases)
+                log_info("        alias \"%s\"", *s);
+        STRV_FOREACH(s, host->h_addr_list) {
+                union in_addr_union u;
+                _cleanup_free_ char *a = NULL;
+                char family_name[DECIMAL_STR_MAX(int)];
+                int r;
+
+                assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype));
+                memcpy(&u, *s, host->h_length);
+                r = in_addr_to_string(host->h_addrtype, &u, &a);
+                assert_se(r == 0);
+                log_info("        %s %s",
+                         af_to_string(host->h_addrtype, family_name, sizeof family_name),
+                         a);
+        }
+        if (canon)
+                log_info("        canonical: \"%s\"", canon);
+}
+
+static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
+        const char *fname;
+        _nss_gethostbyname4_r_t f;
+        char buffer[2000];
+        struct gaih_addrtuple *pat = NULL;
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
+                                    and will access this variable through *ttlp,
+                                    so we need to set it to something.
+                                    I'm not sure if this is a bug in nss-dns
+                                    or not. */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        int n;
+
+        fname = strjoina("_nss_", module, "_gethostbyname4_r");
+        f = dlsym(handle, fname);
+        log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+        assert_se(f);
+
+        status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
+        if (status == NSS_STATUS_SUCCESS) {
+                log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+                         fname, name,
+                         nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                         pat ? (char*) pat - buffer : 0,
+                         errno1, errno_to_name(errno1) ?: "---",
+                         errno2, hstrerror(errno2),
+                         ttl);
+                n = print_gaih_addrtuples(pat);
+        } else {
+                log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s",
+                         fname, name,
+                         nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                         pat,
+                         errno1, errno_to_name(errno1) ?: "---",
+                         errno2, hstrerror(errno2));
+                n = 0;
+        }
+
+        if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL)
+                return;
+
+        if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) {
+                assert_se(status == NSS_STATUS_SUCCESS);
+                assert_se(n == 2);
+        }
+}
+
+
+static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
+        const char *fname;
+        _nss_gethostbyname3_r_t f;
+        char buffer[2000];
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
+                                    and will access this variable through *ttlp,
+                                    so we need to set it to something.
+                                    I'm not sure if this is a bug in nss-dns
+                                    or not. */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        struct hostent host;
+        char *canon;
+        char family_name[DECIMAL_STR_MAX(int)];
+
+        fname = strjoina("_nss_", module, "_gethostbyname3_r");
+        f = dlsym(handle, fname);
+        log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+        assert_se(f);
+
+        status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon);
+        log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+                 fname, name, af_to_string(af, family_name, sizeof family_name),
+                 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                 errno1, errno_to_name(errno1) ?: "---",
+                 errno2, hstrerror(errno2),
+                 ttl);
+        if (status == NSS_STATUS_SUCCESS)
+                print_struct_hostent(&host, canon);
+}
+
+static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
+        const char *fname;
+        _nss_gethostbyname2_r_t f;
+        char buffer[2000];
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        struct hostent host;
+        char family_name[DECIMAL_STR_MAX(int)];
+
+        fname = strjoina("_nss_", module, "_gethostbyname2_r");
+        f = dlsym(handle, fname);
+        log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+        assert_se(f);
+
+        status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2);
+        log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+                 fname, name, af_to_string(af, family_name, sizeof family_name),
+                 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                 errno1, errno_to_name(errno1) ?: "---",
+                 errno2, hstrerror(errno2));
+        if (status == NSS_STATUS_SUCCESS)
+                print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
+        const char *fname;
+        _nss_gethostbyname_r_t f;
+        char buffer[2000];
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        struct hostent host;
+
+        fname = strjoina("_nss_", module, "_gethostbyname_r");
+        f = dlsym(handle, fname);
+        log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+        assert_se(f);
+
+        status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2);
+        log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+                 fname, name,
+                 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                 errno1, errno_to_name(errno1) ?: "---",
+                 errno2, hstrerror(errno2));
+        if (status == NSS_STATUS_SUCCESS)
+                print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyaddr2_r(void *handle,
+                                  const char *module,
+                                  const void* addr, socklen_t len,
+                                  int af) {
+
+        const char *fname;
+        _nss_gethostbyaddr2_r_t f;
+        char buffer[2000];
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        struct hostent host;
+        int32_t ttl = INT32_MAX;
+        _cleanup_free_ char *addr_pretty = NULL;
+
+        fname = strjoina("_nss_", module, "_gethostbyaddr2_r");
+        f = dlsym(handle, fname);
+
+        log_full_errno(f ? LOG_DEBUG : LOG_INFO,  errno,
+                       "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
+        if (!f)
+                return;
+
+        assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
+
+        status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl);
+        log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+                 fname, addr_pretty,
+                 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                 errno1, errno_to_name(errno1) ?: "---",
+                 errno2, hstrerror(errno2),
+                 ttl);
+        if (status == NSS_STATUS_SUCCESS)
+                print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyaddr_r(void *handle,
+                                 const char *module,
+                                 const void* addr, socklen_t len,
+                                 int af) {
+
+        const char *fname;
+        _nss_gethostbyaddr_r_t f;
+        char buffer[2000];
+        int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+        enum nss_status status;
+        char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+        struct hostent host;
+        _cleanup_free_ char *addr_pretty = NULL;
+
+        fname = strjoina("_nss_", module, "_gethostbyaddr_r");
+        f = dlsym(handle, fname);
+
+        log_full_errno(f ? LOG_DEBUG : LOG_INFO,  errno,
+                       "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
+        if (!f)
+                return;
+
+        assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
+
+        status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2);
+        log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+                 fname, addr_pretty,
+                 nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+                 errno1, errno_to_name(errno1) ?: "---",
+                 errno2, hstrerror(errno2));
+        if (status == NSS_STATUS_SUCCESS)
+                print_struct_hostent(&host, NULL);
+}
+
+static void test_byname(void *handle, const char *module, const char *name) {
+        test_gethostbyname4_r(handle, module, name);
+        puts("");
+
+        test_gethostbyname3_r(handle, module, name, AF_INET);
+        puts("");
+        test_gethostbyname3_r(handle, module, name, AF_INET6);
+        puts("");
+        test_gethostbyname3_r(handle, module, name, AF_UNSPEC);
+        puts("");
+        test_gethostbyname3_r(handle, module, name, AF_LOCAL);
+        puts("");
+
+        test_gethostbyname2_r(handle, module, name, AF_INET);
+        puts("");
+        test_gethostbyname2_r(handle, module, name, AF_INET6);
+        puts("");
+        test_gethostbyname2_r(handle, module, name, AF_UNSPEC);
+        puts("");
+        test_gethostbyname2_r(handle, module, name, AF_LOCAL);
+        puts("");
+
+        test_gethostbyname_r(handle, module, name);
+        puts("");
+}
+
+static void test_byaddr(void *handle,
+                        const char *module,
+                        const void* addr, socklen_t len,
+                        int af) {
+        test_gethostbyaddr2_r(handle, module, addr, len, af);
+        puts("");
+
+        test_gethostbyaddr_r(handle, module, addr, len, af);
+        puts("");
+}
+
+#ifdef HAVE_MYHOSTNAME
+#  define MODULE1 "myhostname\0"
+#else
+#  define MODULE1
+#endif
+#ifdef HAVE_RESOLVED
+#  define MODULE2 "resolve\0"
+#else
+#  define MODULE2
+#endif
+#ifdef HAVE_MACHINED
+#  define MODULE3 "mymachines\0"
+#else
+#  define MODULE3
+#endif
+#define MODULE4 "dns\0"
+
+int main(int argc, char **argv) {
+        _cleanup_free_ char *dir = NULL, *hostname = NULL;
+        const char *module;
+
+        const uint32_t local_address_ipv4 = htonl(0x7F000001);
+        const uint32_t local_address_ipv4_2 = htonl(0x7F000002);
+        _cleanup_free_ struct local_address *addresses = NULL;
+        int n_addresses;
+
+        log_set_max_level(LOG_INFO);
+        log_parse_environment();
+
+        dir = dirname_malloc(argv[0]);
+        assert_se(dir);
+
+        hostname = gethostname_malloc();
+        assert_se(hostname);
+
+        n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
+        if (n_addresses < 0) {
+                log_info_errno(n_addresses, "Failed to query local addresses: %m");
+                n_addresses = 0;
+        }
+
+        NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) {
+                void *handle;
+                const char *name;
+                int i;
+
+                log_info("======== %s ========", module);
+
+                handle = open_handle(streq(module, "dns") ? NULL : dir,
+                                     module,
+                                     RTLD_LAZY|RTLD_NODELETE);
+                NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0")
+                        test_byname(handle, module, name);
+
+                test_byname(handle, module, hostname);
+
+                test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET);
+                test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET);
+                test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6);
+
+                for (i = 0; i < n_addresses; i++)
+                        test_byaddr(handle, module,
+                                    &addresses[i].address,
+                                    FAMILY_ADDRESS_SIZE(addresses[i].family),
+                                    addresses[i].family);
+
+                dlclose(handle);
+
+                log_info(" ");
+        }
+
+        return EXIT_SUCCESS;
+}
index 268da002a949281e70ca2eea8a092af1f9357930..096326d176cd0912a0c71aa7387e61e90a9914ea 100644 (file)
 #include "string-util.h"
 #include "strv.h"
 
-static void test_paths(ManagerRunningAs running_as, bool personal) {
+static void test_paths(UnitFileScope scope) {
         char template[] = "/tmp/test-path-lookup.XXXXXXX";
 
         _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
         _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
-        char *exists, *not, *systemd_unit_path;
+        char *systemd_unit_path;
 
         assert_se(mkdtemp(template));
-        exists = strjoina(template, "/exists");
-        assert_se(mkdir(exists, 0755) == 0);
-        not = strjoina(template, "/not");
 
         assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
-        assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0);
-
-        assert_se(!strv_isempty(lp_without_env.unit_path));
-        assert_se(strv_contains(lp_without_env.unit_path, exists));
-        assert_se(strv_contains(lp_without_env.unit_path, not));
+        assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0);
+        assert_se(!strv_isempty(lp_without_env.search_path));
+        assert_se(lookup_paths_reduce(&lp_without_env) >= 0);
 
         systemd_unit_path = strjoina(template, "/systemd-unit-path");
         assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0);
-        assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0);
-        assert_se(strv_length(lp_with_env.unit_path) == 1);
-        assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path));
+        assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0);
+        assert_se(strv_length(lp_with_env.search_path) == 1);
+        assert_se(streq(lp_with_env.search_path[0], systemd_unit_path));
+        assert_se(lookup_paths_reduce(&lp_with_env) >= 0);
+        assert_se(strv_length(lp_with_env.search_path) == 0);
 
         assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
 
-static void print_generator_paths(ManagerRunningAs running_as) {
+static void print_generator_binary_paths(UnitFileScope scope) {
         _cleanup_strv_free_ char **paths;
         char **dir;
 
-        log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user");
+        log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
 
-        paths = generator_paths(running_as);
+        paths = generator_binary_paths(scope);
         STRV_FOREACH(dir, paths)
                 log_info("        %s", *dir);
 }
@@ -70,13 +67,12 @@ int main(int argc, char **argv) {
         log_parse_environment();
         log_open();
 
-        test_paths(MANAGER_SYSTEM, false);
-        test_paths(MANAGER_SYSTEM, true);
-        test_paths(MANAGER_USER, false);
-        test_paths(MANAGER_USER, true);
+        test_paths(UNIT_FILE_SYSTEM);
+        test_paths(UNIT_FILE_USER);
+        test_paths(UNIT_FILE_GLOBAL);
 
-        print_generator_paths(MANAGER_SYSTEM);
-        print_generator_paths(MANAGER_USER);
+        print_generator_binary_paths(UNIT_FILE_SYSTEM);
+        print_generator_binary_paths(UNIT_FILE_USER);
 
         return EXIT_SUCCESS;
 }
index d376dd56c57b4979b588c14a65406767298c4488..b53324b5e6de6bf16e0c65177c6966265bc65359 100644 (file)
@@ -90,6 +90,18 @@ static void test_path(void) {
                 assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
                 assert_se(path_equal(path_kill_slashes(p3), "/./"));
         }
+
+        assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
+        assert_se(PATH_IN_SET("/bin", "/bin"));
+        assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
+        assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
+        assert_se(!PATH_IN_SET("/", "/abc", "/def"));
+
+        assert_se(path_equal_ptr(NULL, NULL));
+        assert_se(path_equal_ptr("/a", "/a"));
+        assert_se(!path_equal_ptr("/a", "/b"));
+        assert_se(!path_equal_ptr("/a", NULL));
+        assert_se(!path_equal_ptr(NULL, "/a"));
 }
 
 static void test_find_binary(const char *self) {
@@ -477,6 +489,27 @@ static void test_filename_is_valid(void) {
         assert_se(filename_is_valid("o.o"));
 }
 
+static void test_hidden_or_backup_file(void) {
+        assert_se(hidden_or_backup_file(".hidden"));
+        assert_se(hidden_or_backup_file("..hidden"));
+        assert_se(!hidden_or_backup_file("hidden."));
+
+        assert_se(hidden_or_backup_file("backup~"));
+        assert_se(hidden_or_backup_file(".backup~"));
+
+        assert_se(hidden_or_backup_file("lost+found"));
+        assert_se(hidden_or_backup_file("aquota.user"));
+        assert_se(hidden_or_backup_file("aquota.group"));
+
+        assert_se(hidden_or_backup_file("test.rpmnew"));
+        assert_se(hidden_or_backup_file("test.dpkg-old"));
+        assert_se(hidden_or_backup_file("test.dpkg-remove"));
+        assert_se(hidden_or_backup_file("test.swp"));
+
+        assert_se(!hidden_or_backup_file("test.rpmnew."));
+        assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
+}
+
 int main(int argc, char **argv) {
         test_path();
         test_find_binary(argv[0]);
@@ -490,6 +523,7 @@ int main(int argc, char **argv) {
         test_path_is_mount_point();
         test_file_in_same_dir();
         test_filename_is_valid();
+        test_hidden_or_backup_file();
 
         return 0;
 }
index 1e704a03dc1d8b4f1a5a1d77afdd898ad6ed0bba..435cafd83afc5b13ad3bc8ba451fbdc91eff8af0 100644 (file)
@@ -30,6 +30,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "test-helper.h"
+#include "tests.h"
 #include "unit.h"
 #include "util.h"
 
@@ -44,7 +45,7 @@ static int setup_test(Manager **m) {
 
         assert_se(m);
 
-        r = manager_new(MANAGER_USER, true, &tmp);
+        r = manager_new(UNIT_FILE_USER, true, &tmp);
         if (MANAGER_SKIP_TEST(r)) {
                 printf("Skipping test: manager_new: %s\n", strerror(-r));
                 return -EXIT_TEST_SKIP;
@@ -243,7 +244,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
 }
 
 int main(int argc, char *argv[]) {
-        test_function_t tests[] = {
+        static const test_function_t tests[] = {
                 test_path_exists,
                 test_path_existsglob,
                 test_path_changed,
@@ -253,12 +254,15 @@ int main(int argc, char *argv[]) {
                 test_path_makedirectory_directorymode,
                 NULL,
         };
-        test_function_t *test = NULL;
+
+        _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
+        const test_function_t *test = NULL;
         Manager *m = NULL;
 
         log_parse_environment();
         log_open();
 
+        assert_se(runtime_dir = setup_fake_runtime_dir());
         assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
 
         for (test = tests; test && *test; test++) {
diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c
deleted file mode 100644 (file)
index 8ae416c..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/***
-  This file is part of systemd. See COPYING for details.
-
-  systemd is free software; you can redistribute it and/or modify it
-  under the terms of the GNU Lesser General Public License as published by
-  the Free Software Foundation; either version 2.1 of the License, or
-  (at your option) any later version.
-
-  systemd is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Tests for RB-Tree
- */
-
-#undef NDEBUG
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include "c-rbtree.h"
-
-/* verify that all API calls are exported */
-static void test_api(void) {
-        CRBTree t = {};
-        CRBNode n = C_RBNODE_INIT(n);
-
-        assert(!c_rbnode_is_linked(&n));
-
-        /* init, is_linked, add, remove, remove_init */
-
-        c_rbtree_add(&t, NULL, &t.root, &n);
-        assert(c_rbnode_is_linked(&n));
-
-        c_rbtree_remove_init(&t, &n);
-        assert(!c_rbnode_is_linked(&n));
-
-        c_rbtree_add(&t, NULL, &t.root, &n);
-        assert(c_rbnode_is_linked(&n));
-
-        c_rbtree_remove(&t, &n);
-        assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */
-
-        c_rbnode_init(&n);
-        assert(!c_rbnode_is_linked(&n));
-
-        /* first, last, leftmost, rightmost, next, prev */
-
-        assert(!c_rbtree_first(&t));
-        assert(!c_rbtree_last(&t));
-        assert(&n == c_rbnode_leftmost(&n));
-        assert(&n == c_rbnode_rightmost(&n));
-        assert(!c_rbnode_next(&n));
-        assert(!c_rbnode_prev(&n));
-}
-
-/* copied from c-rbtree.c, relies on internal representation */
-static inline _Bool c_rbnode_is_red(CRBNode *n) {
-        return !((unsigned long)n->__parent_and_color & 1UL);
-}
-
-/* copied from c-rbtree.c, relies on internal representation */
-static inline _Bool c_rbnode_is_black(CRBNode *n) {
-        return !!((unsigned long)n->__parent_and_color & 1UL);
-}
-
-static size_t validate(CRBTree *t) {
-        unsigned int i_black, n_black;
-        CRBNode *n, *p, *o;
-        size_t count = 0;
-
-        assert(t);
-        assert(!t->root || c_rbnode_is_black(t->root));
-
-        /* traverse to left-most child, count black nodes */
-        i_black = 0;
-        n = t->root;
-        while (n && n->left) {
-                if (c_rbnode_is_black(n))
-                        ++i_black;
-                n = n->left;
-        }
-        n_black = i_black;
-
-        /*
-         * Traverse tree and verify correctness:
-         *  1) A node is either red or black
-         *  2) The root is black
-         *  3) All leaves are black
-         *  4) Every red node must have two black child nodes
-         *  5) Every path to a leaf contains the same number of black nodes
-         *
-         * Note that NULL nodes are considered black, which is why we don't
-         * check for 3).
-         */
-        o = NULL;
-        while (n) {
-                ++count;
-
-                /* verify natural order */
-                assert(n > o);
-                o = n;
-
-                /* verify consistency */
-                assert(!n->right || c_rbnode_parent(n->right) == n);
-                assert(!n->left || c_rbnode_parent(n->left) == n);
-
-                /* verify 2) */
-                if (!c_rbnode_parent(n))
-                        assert(c_rbnode_is_black(n));
-
-                if (c_rbnode_is_red(n)) {
-                        /* verify 4) */
-                        assert(!n->left || c_rbnode_is_black(n->left));
-                        assert(!n->right || c_rbnode_is_black(n->right));
-                } else {
-                        /* verify 1) */
-                        assert(c_rbnode_is_black(n));
-                }
-
-                /* verify 5) */
-                if (!n->left && !n->right)
-                        assert(i_black == n_black);
-
-                /* get next node */
-                if (n->right) {
-                        n = n->right;
-                        if (c_rbnode_is_black(n))
-                                ++i_black;
-
-                        while (n->left) {
-                                n = n->left;
-                                if (c_rbnode_is_black(n))
-                                        ++i_black;
-                        }
-                } else {
-                        while ((p = c_rbnode_parent(n)) && n == p->right) {
-                                n = p;
-                                if (c_rbnode_is_black(p->right))
-                                        --i_black;
-                        }
-
-                        n = p;
-                        if (p && c_rbnode_is_black(p->left))
-                                --i_black;
-                }
-        }
-
-        return count;
-}
-
-static void insert(CRBTree *t, CRBNode *n) {
-        CRBNode **i, *p;
-
-        assert(t);
-        assert(n);
-        assert(!c_rbnode_is_linked(n));
-
-        i = &t->root;
-        p = NULL;
-        while (*i) {
-                p = *i;
-                if (n < *i) {
-                        i = &(*i)->left;
-                } else {
-                        assert(n > *i);
-                        i = &(*i)->right;
-                }
-        }
-
-        c_rbtree_add(t, p, i, n);
-}
-
-static void shuffle(void **nodes, size_t n_memb) {
-        unsigned int i, j;
-        void *t;
-
-        for (i = 0; i < n_memb; ++i) {
-                j = rand() % n_memb;
-                t = nodes[j];
-                nodes[j] = nodes[i];
-                nodes[i] = t;
-        }
-}
-
-/* run some pseudo-random tests on the tree */
-static void test_shuffle(void) {
-        CRBNode *nodes[256];
-        CRBTree t = {};
-        unsigned int i, j;
-        size_t n;
-
-        /* allocate and initialize all nodes */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                nodes[i] = malloc(sizeof(*nodes[i]));
-                assert(nodes[i]);
-                c_rbnode_init(nodes[i]);
-        }
-
-        /* shuffle nodes and validate *empty* tree */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-        n = validate(&t);
-        assert(n == 0);
-
-        /* add all nodes and validate after each insertion */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                insert(&t, nodes[i]);
-                n = validate(&t);
-                assert(n == i + 1);
-        }
-
-        /* shuffle nodes again */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
-        /* remove all nodes (in different order) and validate on each round */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                c_rbtree_remove(&t, nodes[i]);
-                n = validate(&t);
-                assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
-                c_rbnode_init(nodes[i]);
-        }
-
-        /* shuffle nodes and validate *empty* tree again */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-        n = validate(&t);
-        assert(n == 0);
-
-        /* add all nodes again */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                insert(&t, nodes[i]);
-                n = validate(&t);
-                assert(n == i + 1);
-        }
-
-        /* 4 times, remove half of the nodes and add them again */
-        for (j = 0; j < 4; ++j) {
-                /* shuffle nodes again */
-                shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
-                /* remove half of the nodes */
-                for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
-                        c_rbtree_remove(&t, nodes[i]);
-                        n = validate(&t);
-                        assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
-                        c_rbnode_init(nodes[i]);
-                }
-
-                /* shuffle the removed half */
-                shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2);
-
-                /* add the removed half again */
-                for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
-                        insert(&t, nodes[i]);
-                        n = validate(&t);
-                        assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1);
-                }
-        }
-
-        /* shuffle nodes again */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
-        /* remove all */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                c_rbtree_remove(&t, nodes[i]);
-                n = validate(&t);
-                assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
-                c_rbnode_init(nodes[i]);
-        }
-
-        /* free nodes again */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
-                free(nodes[i]);
-}
-
-typedef struct {
-        unsigned long key;
-        CRBNode rb;
-} Node;
-
-#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb)))
-
-static int compare(CRBTree *t, void *k, CRBNode *n) {
-        unsigned long key = (unsigned long)k;
-        Node *node = node_from_rb(n);
-
-        return (key < node->key) ? -1 : (key > node->key) ? 1 : 0;
-}
-
-/* run tests against the c_rbtree_find*() helpers */
-static void test_map(void) {
-        CRBNode **slot, *p;
-        CRBTree t = {};
-        Node *nodes[2048];
-        unsigned long i;
-
-        /* allocate and initialize all nodes */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                nodes[i] = malloc(sizeof(*nodes[i]));
-                assert(nodes[i]);
-                nodes[i]->key = i;
-                c_rbnode_init(&nodes[i]->rb);
-        }
-
-        /* shuffle nodes */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
-        /* add all nodes, and verify that each node is linked */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                assert(!c_rbnode_is_linked(&nodes[i]->rb));
-                assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-
-                slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p);
-                assert(slot);
-                c_rbtree_add(&t, p, slot, &nodes[i]->rb);
-
-                assert(c_rbnode_is_linked(&nodes[i]->rb));
-                assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-        }
-
-        /* shuffle nodes again */
-        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
-        /* remove all nodes (in different order) */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
-                assert(c_rbnode_is_linked(&nodes[i]->rb));
-                assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-
-                c_rbtree_remove_init(&t, &nodes[i]->rb);
-
-                assert(!c_rbnode_is_linked(&nodes[i]->rb));
-                assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-        }
-
-        /* free nodes again */
-        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
-                free(nodes[i]);
-}
-
-int main(int argc, char **argv) {
-        unsigned int i;
-
-        /* we want stable tests, so use fixed seed */
-        srand(0xdeadbeef);
-
-        test_api();
-
-        /*
-         * The tests are pseudo random; run them multiple times, each run will
-         * have different orders and thus different results.
-         */
-        for (i = 0; i < 4; ++i) {
-                test_shuffle();
-                test_map();
-        }
-
-        return 0;
-}
index d9ac9368cdb284a8c6fedacad2fbc78afedc7870..62afd2de5edd6009b0eade08c3bce333cf6a110a 100644 (file)
@@ -99,6 +99,18 @@ int main(int argc, char *argv[]) {
         test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL);
         test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL);
         test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL);
+        test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20");
+        test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40");
+        test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41");
+        test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0");
+        test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27");
+        test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40");
+        test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41");
+        test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20");
+        test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13");
+        test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1");
+        test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0");
+        test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20");
 
         return 0;
 }
index 7f515b53d878ca8bf7b2131313966ca75420cc96..3e9caafc710dd143fea8e50f0a9637c48c32f5b6 100644 (file)
 
 #include "macro.h"
 #include "manager.h"
+#include "rm-rf.h"
 #include "test-helper.h"
+#include "tests.h"
 
 int main(int argc, char *argv[]) {
+        _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
         Manager *m = NULL;
         Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
         Service *ser;
@@ -31,9 +34,11 @@ int main(int argc, char *argv[]) {
         FDSet *fdset = NULL;
         int r;
 
+        assert_se(runtime_dir = setup_fake_runtime_dir());
+
         /* prepare the test */
         assert_se(set_unit_path(TEST_DIR) >= 0);
-        r = manager_new(MANAGER_USER, true, &m);
+        r = manager_new(UNIT_FILE_USER, true, &m);
         if (MANAGER_SKIP_TEST(r)) {
                 printf("Skipping test: manager_new: %s\n", strerror(-r));
                 return EXIT_TEST_SKIP;
index fea1f848cdddfbbf199a7ecbe0680a066e4da681..fc01dcfaf13ce5a834be1db1e0c63e968de974ba 100644 (file)
@@ -358,7 +358,7 @@ static void test_strv_extend_strv_concat(void) {
 }
 
 static void test_strv_extend_strv(void) {
-        _cleanup_strv_free_ char **a = NULL, **b = NULL;
+        _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL;
 
         a = strv_new("abc", "def", "ghi", NULL);
         b = strv_new("jkl", "mno", "abc", "pqr", NULL);
@@ -373,8 +373,14 @@ static void test_strv_extend_strv(void) {
         assert_se(streq(a[3], "jkl"));
         assert_se(streq(a[4], "mno"));
         assert_se(streq(a[5], "pqr"));
-
         assert_se(strv_length(a) == 6);
+
+        assert_se(strv_extend_strv(&n, b, false) >= 0);
+        assert_se(streq(n[0], "jkl"));
+        assert_se(streq(n[1], "mno"));
+        assert_se(streq(n[2], "abc"));
+        assert_se(streq(n[3], "pqr"));
+        assert_se(strv_length(n) == 4);
 }
 
 static void test_strv_extend(void) {
index d7223dd2bfa056dedab7b78bd2e0e5cb540257b5..b34ebeefb24a12e1dcde2ad5d7813e9481e82f02 100644 (file)
 #include "util.h"
 
 int main(int argc, char** argv) {
+        _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL;
+        _cleanup_close_ int fd = -1, fd2 = -1;
         const char *p = argv[1] ?: "/tmp";
-        char *pattern = strjoina(p, "/systemd-test-XXXXXX");
-        _cleanup_close_ int fd, fd2;
-        _cleanup_free_ char *cmd, *cmd2, *ans, *ans2;
+        char *pattern;
 
         log_set_max_level(LOG_DEBUG);
         log_parse_environment();
 
-        fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
+        pattern = strjoina(p, "/systemd-test-XXXXXX");
+
+        fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
         assert_se(fd >= 0);
 
         assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
@@ -59,5 +61,21 @@ int main(int argc, char** argv) {
         log_debug("link2: %s", ans2);
         assert_se(endswith(ans2, " (deleted)"));
 
+        pattern = strjoina(p, "/tmpfiles-test");
+        assert_se(tempfn_random(pattern, NULL, &d) >= 0);
+
+        fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp);
+        assert_se(fd >= 0);
+        assert_se(write(fd, "foobar\n", 7) == 7);
+
+        assert_se(touch(d) >= 0);
+        assert_se(link_tmpfile(fd, tmp, d) == -EEXIST);
+        assert_se(unlink(d) >= 0);
+        assert_se(link_tmpfile(fd, tmp, d) >= 0);
+
+        assert_se(read_one_line_file(d, &line) >= 0);
+        assert_se(streq(line, "foobar"));
+        assert_se(unlink(d) >= 0);
+
         return 0;
 }
index d01789fe08cb962b1375df61b5720a9f5a7c2a8c..e965b4494a34c3fcd4aca40edc52535198d04535 100644 (file)
@@ -27,6 +27,7 @@
 #include <unistd.h>
 
 #include "fs-util.h"
+#include "log.h"
 #include "missing.h"
 #include "selinux-util.h"
 #include "signal-util.h"
@@ -39,39 +40,31 @@ static int fake_filesystems(void) {
                 const char *src;
                 const char *target;
                 const char *error;
+                bool ignore_mount_error;
         } fakefss[] = {
-                { "test/sys", "/sys",                   "failed to mount test /sys" },
-                { "test/dev", "/dev",                   "failed to mount test /dev" },
-                { "test/run", "/run",                   "failed to mount test /run" },
-                { "test/run", "/etc/udev/rules.d",      "failed to mount empty /etc/udev/rules.d" },
-                { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" },
+                { "test/tmpfs/sys", "/sys",                    "failed to mount test /sys",                        false },
+                { "test/tmpfs/dev", "/dev",                    "failed to mount test /dev",                        false },
+                { "test/run",       "/run",                    "failed to mount test /run",                        false },
+                { "test/run",       "/etc/udev/rules.d",       "failed to mount empty /etc/udev/rules.d",          true },
+                { "test/run",       UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
         };
         unsigned int i;
-        int err;
 
-        err = unshare(CLONE_NEWNS);
-        if (err < 0) {
-                err = -errno;
-                fprintf(stderr, "failed to call unshare(): %m\n");
-                goto out;
-        }
+        if (unshare(CLONE_NEWNS) < 0)
+                return log_error_errno(errno, "failed to call unshare(): %m");
 
-        if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
-                err = -errno;
-                fprintf(stderr, "failed to mount / as private: %m\n");
-                goto out;
-        }
+        if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0)
+                return log_error_errno(errno, "failed to mount / as private: %m");
 
         for (i = 0; i < ELEMENTSOF(fakefss); i++) {
-                err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
-                if (err < 0) {
-                        err = -errno;
-                        fprintf(stderr, "%s %m\n", fakefss[i].error);
-                        return err;
+                if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
+                        log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
+                        if (!fakefss[i].ignore_mount_error)
+                                return -errno;
                 }
         }
-out:
-        return err;
+
+        return 0;
 }
 
 int main(int argc, char *argv[]) {
@@ -84,6 +77,9 @@ int main(int argc, char *argv[]) {
         const char *action;
         int err;
 
+        log_parse_environment();
+        log_open();
+
         err = fake_filesystems();
         if (err < 0)
                 return EXIT_FAILURE;
index cc6c61ba634cd3d632ac374e8392e9c14e428a76..c340673c6ce7a44de3f48b1e783b05f055522312 100644 (file)
 #include "install.h"
 #include "load-fragment.h"
 #include "macro.h"
+#include "rm-rf.h"
 #include "specifier.h"
 #include "string-util.h"
 #include "strv.h"
 #include "test-helper.h"
+#include "tests.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -51,7 +53,7 @@ static int test_unit_file_get_set(void) {
         h = hashmap_new(&string_hash_ops);
         assert_se(h);
 
-        r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+        r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
 
         if (r == -EPERM || r == -EACCES) {
                 printf("Skipping test: unit_file_get_list: %s", strerror(-r));
@@ -113,7 +115,7 @@ static void test_config_parse_exec(void) {
         Manager *m = NULL;
         Unit *u = NULL;
 
-        r = manager_new(MANAGER_USER, true, &m);
+        r = manager_new(UNIT_FILE_USER, true, &m);
         if (MANAGER_SKIP_TEST(r)) {
                 printf("Skipping test: manager_new: %s\n", strerror(-r));
                 return;
@@ -840,11 +842,14 @@ static void test_config_parse_pass_environ(void) {
 }
 
 int main(int argc, char *argv[]) {
+        _cleanup_(rm_rf_and_freep) char *runtime_dir = NULL;
         int r;
 
         log_parse_environment();
         log_open();
 
+        assert_se(runtime_dir = setup_fake_runtime_dir());
+
         r = test_unit_file_get_set();
         test_config_parse_exec();
         test_config_parse_capability_set();
index 3de94ef4253e46cecdc378aa2b3f3883c16ed14c..2fd83f321cec6d0a23a031b4a44cd3caf802e622 100644 (file)
@@ -209,7 +209,7 @@ static int test_unit_printf(void) {
         assert_se(get_home_dir(&home) >= 0);
         assert_se(get_shell(&shell) >= 0);
 
-        r = manager_new(MANAGER_USER, true, &m);
+        r = manager_new(UNIT_FILE_USER, true, &m);
         if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
                 puts("manager_new: Permission denied. Skipping test.");
                 return EXIT_TEST_SKIP;
index efd264b34dbc26307f0cbed95bf7edeb4a5e9ce2..2053d35a67995df5db9221423f5618e9d083ab0b 100644 (file)
@@ -94,6 +94,7 @@ typedef enum ItemType {
 
         /* These ones take globs */
         WRITE_FILE = 'w',
+        EMPTY_DIRECTORY = 'e',
         SET_XATTR = 't',
         RECURSIVE_SET_XATTR = 'T',
         SET_ACL = 'a',
@@ -179,6 +180,7 @@ static bool needs_glob(ItemType t) {
                       IGNORE_DIRECTORY_PATH,
                       REMOVE_PATH,
                       RECURSIVE_REMOVE_PATH,
+                      EMPTY_DIRECTORY,
                       ADJUST_MODE,
                       RELABEL_PATH,
                       RECURSIVE_RELABEL_PATH,
@@ -195,6 +197,7 @@ static bool takes_ownership(ItemType t) {
                       CREATE_FILE,
                       TRUNCATE_FILE,
                       CREATE_DIRECTORY,
+                      EMPTY_DIRECTORY,
                       TRUNCATE_DIRECTORY,
                       CREATE_SUBVOLUME,
                       CREATE_SUBVOLUME_INHERIT_QUOTA,
@@ -1217,7 +1220,6 @@ static int create_item(Item *i) {
         case CREATE_SUBVOLUME:
         case CREATE_SUBVOLUME_INHERIT_QUOTA:
         case CREATE_SUBVOLUME_NEW_QUOTA:
-
                 RUN_WITH_UMASK(0000)
                         mkdir_parents_label(i->path, 0755);
 
@@ -1276,11 +1278,11 @@ static int create_item(Item *i) {
                 if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
                         r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
                         if (r == -ENOTTY)
-                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
+                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
                         else if (r == -EROFS)
-                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
+                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
                         else if (r == -ENOPROTOOPT)
-                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path);
+                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
                         else if (r < 0)
                                 q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
                         else if (r > 0)
@@ -1289,6 +1291,9 @@ static int create_item(Item *i) {
                                 log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
                 }
 
+                /* fall through */
+
+        case EMPTY_DIRECTORY:
                 r = path_set_perms(i, i->path);
                 if (q < 0)
                         return q;
@@ -1298,7 +1303,6 @@ static int create_item(Item *i) {
                 break;
 
         case CREATE_FIFO:
-
                 RUN_WITH_UMASK(0000) {
                         mac_selinux_create_file_prepare(i->path, S_IFIFO);
                         r = mkfifo(i->path, i->mode);
@@ -1535,47 +1539,20 @@ static int remove_item_instance(Item *i, const char *instance) {
 }
 
 static int remove_item(Item *i) {
-        int r = 0;
-
         assert(i);
 
         log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
 
         switch (i->type) {
 
-        case CREATE_FILE:
-        case TRUNCATE_FILE:
-        case CREATE_DIRECTORY:
-        case CREATE_SUBVOLUME:
-        case CREATE_SUBVOLUME_INHERIT_QUOTA:
-        case CREATE_SUBVOLUME_NEW_QUOTA:
-        case CREATE_FIFO:
-        case CREATE_SYMLINK:
-        case CREATE_CHAR_DEVICE:
-        case CREATE_BLOCK_DEVICE:
-        case IGNORE_PATH:
-        case IGNORE_DIRECTORY_PATH:
-        case ADJUST_MODE:
-        case RELABEL_PATH:
-        case RECURSIVE_RELABEL_PATH:
-        case WRITE_FILE:
-        case COPY_FILES:
-        case SET_XATTR:
-        case RECURSIVE_SET_XATTR:
-        case SET_ACL:
-        case RECURSIVE_SET_ACL:
-        case SET_ATTRIBUTE:
-        case RECURSIVE_SET_ATTRIBUTE:
-                break;
-
         case REMOVE_PATH:
         case TRUNCATE_DIRECTORY:
         case RECURSIVE_REMOVE_PATH:
-                r = glob_item(i, remove_item_instance, false);
-                break;
-        }
+                return glob_item(i, remove_item_instance, false);
 
-        return r;
+        default:
+                return 0;
+        }
 }
 
 static int clean_item_instance(Item *i, const char* instance) {
@@ -1630,8 +1607,6 @@ static int clean_item_instance(Item *i, const char* instance) {
 }
 
 static int clean_item(Item *i) {
-        int r = 0;
-
         assert(i);
 
         log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
@@ -1641,19 +1616,17 @@ static int clean_item(Item *i) {
         case CREATE_SUBVOLUME:
         case CREATE_SUBVOLUME_INHERIT_QUOTA:
         case CREATE_SUBVOLUME_NEW_QUOTA:
+        case EMPTY_DIRECTORY:
         case TRUNCATE_DIRECTORY:
         case IGNORE_PATH:
         case COPY_FILES:
                 clean_item_instance(i, i->path);
-                break;
+                return 0;
         case IGNORE_DIRECTORY_PATH:
-                r = glob_item(i, clean_item_instance, false);
-                break;
+                return glob_item(i, clean_item_instance, false);
         default:
-                break;
+                return 0;
         }
-
-        return r;
 }
 
 static int process_item_array(ItemArray *array);
@@ -1879,6 +1852,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         case CREATE_SUBVOLUME:
         case CREATE_SUBVOLUME_INHERIT_QUOTA:
         case CREATE_SUBVOLUME_NEW_QUOTA:
+        case EMPTY_DIRECTORY:
         case TRUNCATE_DIRECTORY:
         case CREATE_FIFO:
         case IGNORE_PATH:
@@ -2198,7 +2172,8 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 static int read_config_file(const char *fn, bool ignore_enoent) {
-        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_fclose_ FILE *_f = NULL;
+        FILE *f;
         char line[LINE_MAX];
         Iterator iterator;
         unsigned v = 0;
@@ -2207,16 +2182,23 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
 
         assert(fn);
 
-        r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
-        if (r < 0) {
-                if (ignore_enoent && r == -ENOENT) {
-                        log_debug_errno(r, "Failed to open \"%s\": %m", fn);
-                        return 0;
-                }
+        if (streq(fn, "-")) {
+                log_debug("Reading config from stdin.");
+                fn = "<stdin>";
+                f = stdin;
+        } else {
+                r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &_f);
+                if (r < 0) {
+                        if (ignore_enoent && r == -ENOENT) {
+                                log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
+                                return 0;
+                        }
 
-                return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
+                        return log_error_errno(r, "Failed to open '%s': %m", fn);
+                }
+                log_debug("Reading config file \"%s\".", fn);
+                f = _f;
         }
-        log_debug("Reading config file \"%s\".", fn);
 
         FOREACH_LINE(line, f, break) {
                 char *l;
index 7b67831e540a93a9d9b5bdf3331c204f7d8fc2ed..c7ded451a2f409eb0f579818bbd7ef71ba920ae1 100644 (file)
@@ -481,7 +481,7 @@ static int show_passwords(void) {
                 if (de->d_type != DT_REG)
                         continue;
 
-                if (hidden_file(de->d_name))
+                if (hidden_or_backup_file(de->d_name))
                         continue;
 
                 if (!startswith(de->d_name, "ask."))
index 8b1bcefe2dfe854e0b82ea880cd918469ae5d88a..a7be2a4eedc2c65c587e1bbd0b40d5ffe28d5d6d 100644 (file)
  * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
  *
  * Two character prefixes based on the type of interface:
- *   en -- Ethernet
- *   sl -- serial line IP (slip)
- *   wl -- wlan
- *   ww -- wwan
+ *   en  Ethernet
+ *   sl  serial line IP (slip)
+ *   wl  wlan
+ *   ww  wwan
  *
  * Type of names:
- *   b<number>                             -- BCMA bus core number
- *   c<bus_id>                             -- CCW bus group name, without leading zeros [s390]
- *   o<index>[d<dev_port>]                 -- on-board device index number
- *   s<slot>[f<function>][d<dev_port>]     -- hotplug slot index number
- *   x<MAC>                                -- MAC address
+ *   b<number>                              BCMA bus core number
+ *   c<bus_id>                              CCW bus group name, without leading zeros [s390]
+ *   o<index>[d<dev_port>]                  on-board device index number
+ *   s<slot>[f<function>][d<dev_port>]      hotplug slot index number
+ *   x<MAC>                                 MAC address
  *   [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
- *                                         -- PCI geographical location
+ *                                          PCI geographical location
  *   [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
- *                                         -- USB port number chain
+ *                                          USB port number chain
  *
  * All multi-function PCI devices will carry the [f<function>] number in the
  * device name, including the function 0 device.
@@ -140,9 +140,9 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
         const char *attr;
         int idx;
 
-        /* ACPI _DSM  -- device specific method for naming a PCI or PCI Express device */
+        /* ACPI _DSM   device specific method for naming a PCI or PCI Express device */
         attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
-        /* SMBIOS type 41 -- Onboard Devices Extended Information */
+        /* SMBIOS type 41  Onboard Devices Extended Information */
         if (!attr)
                 attr = udev_device_get_sysattr_value(names->pcidev, "index");
         if (!attr)
@@ -230,7 +230,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
         if (l == 0)
                 names->pci_path[0] = '\0';
 
-        /* ACPI _SUN  -- slot user number */
+        /* ACPI _SUN   slot user number */
         pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
         if (!pci) {
                 err = -ENOENT;
index b5f7f0d512df7e6de94120b8a36561bdcc8a01a8..c0ef073476b60ea8a42a62db44be7c7d4bd3e550 100644 (file)
@@ -40,7 +40,7 @@ static void sig_handler(int signum) {
 static void print_device(struct udev_device *device, const char *source, int prop) {
         struct timespec ts;
 
-        clock_gettime(CLOCK_MONOTONIC, &ts);
+        assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
         printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n",
                source,
                ts.tv_sec, ts.tv_nsec/1000,
index 243df7386fe1e78fdea6d6af9ff233ee4589c1c9..e9dd2f47c730c289af07ec6b36b657e9f42202f8 100644 (file)
@@ -400,10 +400,11 @@ static void worker_spawn(Manager *manager, struct event *event) {
                         goto out;
                 }
 
-                /* request TERM signal if parent exits */
-                prctl(PR_SET_PDEATHSIG, SIGTERM);
+                /* Request TERM signal if parent exits.
+                   Ignore error, not much we can do in that case. */
+                (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
 
-                /* reset OOM score, we only protect the main daemon */
+                /* Reset OOM score, we only protect the main daemon. */
                 write_string_file("/proc/self/oom_score_adj", "0", 0);
 
                 for (;;) {
deleted file mode 100644 (file)
index 5e89a29effecd19dd50b1f65fdbe19a1d081761d..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,10 +0,0 @@
-all:
-       @make -s --no-print-directory -C ../.. all
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
-       @make --no-print-directory -C ../.. all
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..e9f93b1104cd21161bfe11fb1b3b534ce2ae82b5
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
index dcb6ece4d433ad799586de4c508ff762b955be40..d97c4ec27d8eafc276ae08edb47a5f8ceaf64a0f 100755 (executable)
@@ -8,7 +8,8 @@ TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/1981"
 test_run() {
     dwarn "skipping QEMU"
     if check_nspawn; then
-        timeout --foreground 30s systemd-nspawn --kill-signal=SIGKILL --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND
+        NSPAWN_TIMEOUT=30s
+        run_nspawn
         check_result_nspawn || return 1
     else
         dwarn "can't run systemd-nspawn, skipping"
deleted file mode 100644 (file)
index 5e89a29effecd19dd50b1f65fdbe19a1d081761d..0000000000000000000000000000000000000000
+++ /dev/null
@@ -1,10 +0,0 @@
-all:
-       @make -s --no-print-directory -C ../.. all
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all
-setup:
-       @make --no-print-directory -C ../.. all
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup
-clean:
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean
-run:
-       @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..e9f93b1104cd21161bfe11fb1b3b534ce2ae82b5
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-09-ISSUE-2691/Makefile b/test/TEST-09-ISSUE-2691/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-09-ISSUE-2691/test.sh b/test/TEST-09-ISSUE-2691/test.sh
new file mode 100755 (executable)
index 0000000..e247694
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2691"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+QEMU_TIMEOUT=90
+
+check_result_qemu() {
+    ret=1
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+    [[ -e $TESTDIR/root/testok ]] && ret=0
+    [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+    cp -a $TESTDIR/root/var/log/journal $TESTDIR
+    umount $TESTDIR/root
+    [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+    ls -l $TESTDIR/journal/*/*.journal
+    test -s $TESTDIR/failed && ret=$(($ret+1))
+    return $ret
+}
+
+test_run() {
+    run_qemu || return 1
+    check_result_qemu || return 1
+    return 0
+}
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    # Create what will eventually be our root filesystem onto an overlay
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c '>/testok'
+RemainAfterExit=yes
+ExecStop=/bin/sh -c 'kill -SEGV $$$$'
+TimeoutStopSec=180s
+EOF
+
+        setup_testsuite
+    ) || return 1
+
+    # mask some services that we do not want to run in these tests
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+test_cleanup() {
+    umount $TESTDIR/root 2>/dev/null
+    [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+    return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-10-ISSUE-2467/Makefile b/test/TEST-10-ISSUE-2467/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-10-ISSUE-2467/test.sh b/test/TEST-10-ISSUE-2467/test.sh
new file mode 100755 (executable)
index 0000000..a652b0d
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/2467"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+    ret=1
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+    [[ -e $TESTDIR/root/testok ]] && ret=0
+    [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+    cp -a $TESTDIR/root/var/log/journal $TESTDIR
+    umount $TESTDIR/root
+    [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+    ls -l $TESTDIR/journal/*/*.journal
+    test -s $TESTDIR/failed && ret=$(($ret+1))
+    return $ret
+}
+
+test_run() {
+    run_qemu || return 1
+    check_result_qemu || return 1
+    return 0
+}
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    # Create what will eventually be our root filesystem onto an overlay
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+        dracut_install nc true rm
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<'EOF'
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -e -x -c 'rm -f /tmp/nonexistent; systemctl start test.socket; echo a | nc -U /run/test.ctl; >/testok'
+TimeoutStartSec=10s
+EOF
+
+       cat  >$initdir/etc/systemd/system/test.socket <<'EOF'
+[Socket]
+ListenStream=/run/test.ctl
+EOF
+
+       cat > $initdir/etc/systemd/system/test.service <<'EOF'
+[Unit]
+Requires=test.socket
+ConditionPathExistsGlob=/tmp/nonexistent
+
+[Service]
+ExecStart=/bin/true
+EOF
+
+        setup_testsuite
+    ) || return 1
+
+    # mask some services that we do not want to run in these tests
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+    ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+test_cleanup() {
+    umount $TESTDIR/root 2>/dev/null
+    [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+    return 0
+}
+
+do_test "$@"
diff --git a/test/TEST-11-ISSUE-3166/Makefile b/test/TEST-11-ISSUE-3166/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-11-ISSUE-3166/test.sh b/test/TEST-11-ISSUE-3166/test.sh
new file mode 100755 (executable)
index 0000000..7913537
--- /dev/null
@@ -0,0 +1,91 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/3166"
+
+. $TEST_BASE_DIR/test-functions
+SKIP_INITRD=yes
+
+check_result_qemu() {
+    ret=1
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+    [[ -e $TESTDIR/root/testok ]] && ret=0
+    [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR
+    cp -a $TESTDIR/root/var/log/journal $TESTDIR
+    umount $TESTDIR/root
+    [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed
+    ls -l $TESTDIR/journal/*/*.journal
+    test -s $TESTDIR/failed && ret=$(($ret+1))
+    return $ret
+}
+
+test_run() {
+    run_qemu || return 1
+    check_result_qemu || return 1
+    return 0
+}
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    # Create what will eventually be our root filesystem onto an overlay
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+        dracut_install false touch
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+After=multi-user.target
+
+[Service]
+ExecStart=/test-fail-on-restart.sh
+Type=oneshot
+EOF
+
+        cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF
+[Unit]
+Description=Fail on restart
+
+[Service]
+Type=simple
+ExecStart=/bin/false
+Restart=always
+EOF
+
+
+        cat >$initdir/test-fail-on-restart.sh <<'EOF'
+#!/bin/bash -x
+
+systemctl start fail-on-restart.service
+active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+while [[ "$active_state" == "ActiveState=activating" || "$active_state" == "ActiveState=active" ]]; do
+    sleep 1
+    active_state=$(systemctl show --property ActiveState fail-on-restart.service)
+done
+systemctl is-failed fail-on-restart.service || exit 1
+touch /testok
+EOF
+
+        chmod 0755 $initdir/test-fail-on-restart.sh
+        setup_testsuite
+    ) || return 1
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+test_cleanup() {
+    umount $TESTDIR/root 2>/dev/null
+    [[ $LOOPDEV ]] && losetup -d $LOOPDEV
+    return 0
+}
+
+do_test "$@"
index d76ab507d221172fddd67d0b4823000275e9bfb5..d4de5adf1a516355ef05479954f2b309e09fa1d4 100755 (executable)
@@ -5,7 +5,12 @@
 # does not write anything on disk or change any system configuration;
 # but it assumes (and checks at the beginning) that networkd is not currently
 # running.
-# This can be run on a normal installation, in QEMU, nspawn, or LXC.
+#
+# This can be run on a normal installation, in QEMU, nspawn (with
+# --private-network), LXD (with "--config raw.lxc=lxc.aa_profile=unconfined"),
+# or LXC system containers. You need at least the "ip" tool from the iproute
+# package; it is recommended to install dnsmasq too to get full test coverage.
+#
 # ATTENTION: This uses the *installed* networkd, not the one from the built
 # source tree.
 #
index 052c77d182a2eba730d3aeaf52b1ab90d937f006..49ee8027b2e1cba42a8312d56de4bb65d4a2d470 100644 (file)
Binary files a/test/sys.tar.xz and b/test/sys.tar.xz differ
old mode 100644 (file)
new mode 100755 (executable)
index aca5f1e..838dd57
@@ -1,3 +1,5 @@
+#!/usr/bin/python
+#
 # systemd-sysv-generator integration test
 #
 # (C) 2015 Canonical Ltd.
@@ -395,11 +397,12 @@ class SysvGeneratorTest(unittest.TestCase):
         # backup files (not enabled in rcN.d/)
         shutil.copy(script, script + '.bak')
         shutil.copy(script, script + '.old')
+        shutil.copy(script, script + '.tmp')
+        shutil.copy(script, script + '.new')
 
         err, results = self.run_generator()
         print(err)
-        self.assertEqual(sorted(results),
-                         ['foo.bak.service', 'foo.old.service', 'foo.service'])
+        self.assertEqual(sorted(results), ['foo.service', 'foo.tmp.service'])
 
         # ensure we don't try to create a symlink to itself
         self.assertNotIn('itself', err)
index 29f647ece46a90c2848184e9c6401cf59cfff310..b07c5003392ff282b66f960b46916952d24aa813 100644 (file)
@@ -8,6 +8,7 @@ LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE"
 KERNEL_VER=${KERNEL_VER-$(uname -r)}
 KERNEL_MODS="/lib/modules/$KERNEL_VER/"
 QEMU_TIMEOUT="${QEMU_TIMEOUT:-infinity}"
+NSPAWN_TIMEOUT="${NSPAWN_TIMEOUT:-infinity}"
 FSTYPE="${FSTYPE:-ext3}"
 
 if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then
@@ -96,8 +97,12 @@ $KERNEL_APPEND \
 }
 
 run_nspawn() {
+    local _nspawn_cmd="../../systemd-nspawn --register=no --kill-signal=SIGKILL --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND"
+    if [[ "$NSPAWN_TIMEOUT" != "infinity" ]]; then
+        _nspawn_cmd="timeout --foreground $NSPAWN_TIMEOUT $_nspawn_cmd"
+    fi
     set -x
-    ../../systemd-nspawn --register=no --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND
+    $_nspawn_cmd
 }
 
 setup_basic_environment() {
@@ -213,6 +218,9 @@ EOF
 install_fsck() {
     dracut_install /sbin/fsck*
     dracut_install -o /bin/fsck*
+
+    # fskc.reiserfs calls reiserfsck. so, install it
+    dracut_install -o reiserfsck
 }
 
 install_dmevent() {
@@ -257,7 +265,13 @@ create_empty_image() {
 ,
 EOF
 
-    mkfs -t "$FSTYPE" -L systemd "${LOOPDEV}p1"
+    local _label="-L systemd"
+    # mkfs.reiserfs doesn't know -L. so, use --label instead
+    [[ "$FSTYPE" == "reiserfs" ]] && _label="--label systemd"
+    if ! mkfs -t "${FSTYPE}" ${_label} "${LOOPDEV}p1" -q; then
+        dfatal "Failed to mkfs -t ${FSTYPE}"
+        exit 1
+    fi
 }
 
 check_result_nspawn() {
@@ -351,7 +365,7 @@ install_config_files() {
     echo systemd-testsuite > $initdir/etc/hostname
     # fstab
     cat >$initdir/etc/fstab <<EOF
-LABEL=systemd           /       ext3    rw 0 1
+LABEL=systemd           /       ${FSTYPE}    rw 0 1
 EOF
 }
 
index b047493f6b874f8a215ea47babbcb1a66dc5335d..da0a4e1f6b4c8dc5b78aa62ea20f0abc90e4ecfd 100755 (executable)
@@ -27,12 +27,19 @@ my $strace              = 0;
 my $udev_bin_valgrind   = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin";
 my $udev_bin_gdb        = "gdb --args $udev_bin";
 my $udev_bin_strace     = "strace -efile $udev_bin";
-my $udev_dev            = "test/dev";
 my $udev_run            = "test/run";
+my $udev_tmpfs          = "test/tmpfs";
+my $udev_sys            = "${udev_tmpfs}/sys";
+my $udev_dev            = "${udev_tmpfs}/dev";
 my $udev_rules_dir      = "$udev_run/udev/rules.d";
 my $udev_rules          = "$udev_rules_dir/udev-test.rules";
 my $EXIT_TEST_SKIP      = 77;
 
+my $rules_10k_tags      = "";
+for (my $i = 1; $i <= 10000; ++$i) {
+    $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
+}
+
 my @tests = (
         {
                 desc            => "no rules",
@@ -702,7 +709,7 @@ EOF
                 desc            => "big major number test",
                 devpath         => "/devices/virtual/misc/misc-fake1",
                 exp_name        => "node",
-                exp_majorminor  => "511:1",
+                exp_majorminor  => "4095:1",
                 rules                => <<EOF
 KERNEL=="misc-fake1", SYMLINK+="node"
 EOF
@@ -711,7 +718,7 @@ EOF
                 desc            => "big major and big minor number test",
                 devpath         => "/devices/virtual/misc/misc-fake89999",
                 exp_name        => "node",
-                exp_majorminor  => "511:89999",
+                exp_majorminor  => "4095:89999",
                 rules           => <<EOF
 KERNEL=="misc-fake89999", SYMLINK+="node"
 EOF
@@ -1315,6 +1322,25 @@ EOF
                 rules           => <<EOF
 KERNEL=="sda", IMPORT{builtin}="path_id"
 KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
+EOF
+        },
+        {
+                desc            => "add and match tag",
+                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                exp_name        => "found",
+                not_exp_name    => "bad" ,
+                rules           => <<EOF
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
+TAGS=="green", SYMLINK+="found"
+TAGS=="blue", SYMLINK+="bad"
+EOF
+        },
+        {
+                desc            => "don't crash with lots of tags",
+                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                exp_name        => "found",
+                rules           => $rules_10k_tags . <<EOF
+TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
 EOF
         },
 );
@@ -1329,13 +1355,13 @@ sub udev {
         close CONF;
 
         if ($valgrind > 0) {
-                system("$udev_bin_valgrind $action $devpath");
+                return system("$udev_bin_valgrind $action $devpath");
         } elsif ($gdb > 0) {
-                system("$udev_bin_gdb $action $devpath");
+                return system("$udev_bin_gdb $action $devpath");
         } elsif ($strace > 0) {
-                system("$udev_bin_strace $action $devpath");
+                return system("$udev_bin_strace $action $devpath");
         } else {
-                system("$udev_bin", "$action", "$devpath");
+                return system("$udev_bin", "$action", "$devpath");
         }
 }
 
@@ -1405,23 +1431,34 @@ sub major_minor_test {
 }
 
 sub udev_setup {
-        system("rm", "-rf", "$udev_dev");
+        system("umount", $udev_tmpfs);
+        rmdir($udev_tmpfs);
+        mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
+        system("mount", "-o", "rw,mode=755,nosuid,noexec,nodev", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs";
+
         mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
         # setting group and mode of udev_dev ensures the tests work
         # even if the parent directory has setgid bit enabled.
         chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
         chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
 
+        system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+
         system("rm", "-rf", "$udev_run");
 }
 
 sub run_test {
         my ($rules, $number) = @_;
+        my $rc;
 
         print "TEST $number: $rules->{desc}\n";
         print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n";
 
-        udev("add", $rules->{devpath}, \$rules->{rules});
+        $rc = udev("add", $rules->{devpath}, \$rules->{rules});
+        if ($rc != 0) {
+                print "$udev_bin add failed with code $rc\n";
+                $error++;
+        }
         if (defined($rules->{not_exp_name})) {
                 if ((-e "$udev_dev/$rules->{not_exp_name}") ||
                     (-l "$udev_dev/$rules->{not_exp_name}")) {
@@ -1462,7 +1499,11 @@ sub run_test {
                 return;
         }
 
-        udev("remove", $rules->{devpath}, \$rules->{rules});
+        $rc = udev("remove", $rules->{devpath}, \$rules->{rules});
+        if ($rc != 0) {
+                print "$udev_bin remove failed with code $rc\n";
+                $error++;
+        }
         if ((-e "$udev_dev/$rules->{exp_name}") ||
             (-l "$udev_dev/$rules->{exp_name}")) {
                 print "remove:      error";
@@ -1543,8 +1584,9 @@ if ($list[0]) {
 print "$error errors occurred\n\n";
 
 # cleanup
-system("rm", "-rf", "$udev_dev");
 system("rm", "-rf", "$udev_run");
+system("umount", "$udev_tmpfs");
+rmdir($udev_tmpfs);
 
 if ($error > 0) {
     exit(1);
index 276bc6b1bac8aa5b757b355fb65db83865b9671e..150dab1e5baf506c191e80c8fddc0d961f8ea4d9 100644 (file)
@@ -26,32 +26,45 @@ d /run/log 0755 root root -
 
 z /run/log/journal 2755 root systemd-journal - -
 Z /run/log/journal/%m ~2750 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
 m4_ifdef(`ENABLE_WHEEL_GROUP',``
 a+ /run/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
 A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
 '',``
 a+ /run/log/journal/%m - - - - d:group:adm:r-x
 A+ /run/log/journal/%m - - - - group:adm:r-x
-''))m4_dnl
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /run/log/journal/%m - - - - d:group:wheel:r-x
+A+ /run/log/journal/%m - - - - group:wheel:r-x
+'')')')m4_dnl
 
 z /var/log/journal 2755 root systemd-journal - -
 z /var/log/journal/%m 2755 root systemd-journal - -
 z /var/log/journal/%m/system.journal 0640 root systemd-journal - -
-m4_ifdef(`HAVE_ACL',
+m4_ifdef(`HAVE_ACL',`m4_dnl
+m4_ifdef(`ENABLE_ADM_GROUP',`m4_dnl
 m4_ifdef(`ENABLE_WHEEL_GROUP',``
 a+ /var/log/journal    - - - - d:group:adm:r-x,d:group:wheel:r-x
 a+ /var/log/journal    - - - - group:adm:r-x,group:wheel:r-x
 a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x
 a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x
 a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--
-'',``
+'', ``
 a+ /var/log/journal    - - - - d:group:adm:r-x
 a+ /var/log/journal    - - - - group:adm:r-x
 a+ /var/log/journal/%m - - - - d:group:adm:r-x
 a+ /var/log/journal/%m - - - - group:adm:r-x
 a+ /var/log/journal/%m/system.journal - - - - group:adm:r--
-''))m4_dnl
+'')',`m4_dnl
+m4_ifdef(`ENABLE_WHEEL_GROUP',``
+a+ /var/log/journal    - - - - d:group:wheel:r-x
+a+ /var/log/journal    - - - - group:wheel:r-x
+a+ /var/log/journal/%m - - - - d:group:wheel:r-x
+a+ /var/log/journal/%m - - - - group:wheel:r-x
+a+ /var/log/journal/%m/system.journal - - - - group:wheel:r--
+'')')')m4_dnl
 
 d /var/lib/systemd 0755 root root -
 d /var/lib/systemd/coredump 0755 root root 3d
index fb390eacfedfee931ea1ad863b81268fe4e1e81b..0de16f24e89ee2f14a953a65a02c0a080866aebe 100644 (file)
@@ -11,6 +11,7 @@ Documentation=man:sulogin(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
 Conflicts=rescue.service
+Conflicts=syslog.socket
 Before=shutdown.target
 
 [Service]
index d4db1747ed1eece7fb7ebb35ec970ec0bafd06f4..480dddbe37620acc3be51c9597837926fbbebba0 100644 (file)
@@ -17,3 +17,4 @@ Type=forking
 ExecStart=@RC_LOCAL_SCRIPT_PATH_START@ start
 TimeoutSec=0
 RemainAfterExit=yes
+GuessMainPID=no
index 3710c595ca19e9c23fe1d9d985d371dd7f9417d4..685baab21d4055eb6b4fe914ce0ecde1565e07ee 100644 (file)
@@ -15,7 +15,7 @@ After=machine.slice
 [Service]
 ExecStart=@rootlibexecdir@/systemd-machined
 BusName=org.freedesktop.machine1
-CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID
+CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD
 WatchdogSec=3min
 
 # Note that machined cannot be placed in a mount namespace, since it
index 1927c4d485318a580bc191d44d5596c5cd8338ae..ea28941507d77ecfe163de00ef142c3505bd3ced 100644 (file)
@@ -13,7 +13,7 @@ Before=machines.target
 After=network.target
 
 [Service]
-ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth --settings=override --machine=%i
+ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --network-veth -U --settings=override --machine=%i
 KillMode=mixed
 Type=notify
 RestartForceExitStatus=133
index c09c05d4d5bd4fed0639c2e5b8f481d546bb1c27..b4ea5a134bee969d2db9083b37e4806075fa23e7 100644 (file)
@@ -8,7 +8,7 @@
 [Unit]
 Description=Permit User Sessions
 Documentation=man:systemd-user-sessions.service(8)
-After=remote-fs.target nss-user-lookup.target
+After=remote-fs.target nss-user-lookup.target network.target
 
 [Service]
 Type=oneshot
index 00a0d28722449038f17e6aa66cb6c70def0cf9f8..1448bd268a0bb0d5b8c130eb53900118dc836e76 100644 (file)
@@ -13,6 +13,7 @@ ConditionPathIsSymbolicLink=!/tmp
 DefaultDependencies=no
 Conflicts=umount.target
 Before=local-fs.target umount.target
+After=swap.target
 
 [Mount]
 What=tmpfs