]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #1880 from fsateler/sysctl-doc
authorLennart Poettering <lennart@poettering.net>
Fri, 13 Nov 2015 15:40:37 +0000 (16:40 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 13 Nov 2015 15:40:37 +0000 (16:40 +0100)
man: document systemd-sysctl arguments

962 files changed:
.gitignore
.mailmap
CODING_STYLE
Makefile-man.am
Makefile.am
NEWS
README
TODO
catalog/systemd.da.catalog [moved from systemd-master/catalog/systemd.da.catalog with 95% similarity]
catalog/systemd.ko.catalog [new file with mode: 0644]
catalog/systemd.zh_CN.catalog [new file with mode: 0644]
coccinelle/errno.cocci
configure.ac
hwdb/20-bluetooth-vendor-product.hwdb
hwdb/60-evdev.hwdb
hwdb/60-keyboard.hwdb
hwdb/70-mouse.hwdb
man/bootchart.conf.xml
man/bootctl.xml
man/busctl.xml
man/coredump.conf.xml
man/crypttab.xml
man/custom-html.xsl
man/daemon.xml
man/file-hierarchy.xml
man/hwdb.xml
man/journalctl.xml
man/journald.conf.xml
man/kernel-command-line.xml
man/libudev.xml
man/locale.conf.xml
man/loginctl.xml
man/logind.conf.xml
man/machine-info.xml
man/machinectl.xml
man/networkctl.xml
man/nss-myhostname.xml
man/nss-mymachines.xml
man/nss-resolve.xml
man/os-release.xml
man/pam_systemd.xml
man/resolved.conf.xml
man/runlevel.xml
man/sd-bus-errors.xml
man/sd_bus_creds_get_pid.xml
man/sd_bus_creds_new_from_pid.xml
man/sd_bus_default.xml
man/sd_bus_error.xml
man/sd_bus_error_add_map.xml
man/sd_bus_message_append.xml
man/sd_bus_message_append_array.xml
man/sd_bus_message_get_monotonic_usec.xml
man/sd_bus_negotiate_fds.xml
man/sd_bus_new.xml
man/sd_bus_path_encode.xml
man/sd_event_add_child.xml
man/sd_event_add_defer.xml
man/sd_event_add_signal.xml
man/sd_event_new.xml
man/sd_event_run.xml
man/sd_event_set_name.xml
man/sd_event_wait.xml
man/sd_get_seats.xml
man/sd_journal_add_match.xml
man/sd_journal_get_data.xml
man/sd_journal_get_fd.xml
man/sd_journal_open.xml
man/sd_journal_print.xml
man/sd_listen_fds.xml
man/sd_login_monitor_new.xml
man/sd_machine_get_class.xml
man/sd_notify.xml
man/sd_pid_get_session.xml
man/sd_seat_get_active.xml
man/sd_session_is_active.xml
man/sd_uid_get_state.xml
man/sd_watchdog_enabled.xml
man/standard-conf.xml
man/sysctl.d.xml
man/systemctl.xml
man/systemd-activate.xml
man/systemd-analyze.xml
man/systemd-ask-password.xml
man/systemd-backlight@.service.xml
man/systemd-binfmt.service.xml
man/systemd-bootchart.xml
man/systemd-cat.xml
man/systemd-cgtop.xml
man/systemd-coredump.xml
man/systemd-cryptsetup-generator.xml
man/systemd-delta.xml
man/systemd-detect-virt.xml
man/systemd-escape.xml
man/systemd-firstboot.xml
man/systemd-fsck@.service.xml
man/systemd-fstab-generator.xml
man/systemd-gpt-auto-generator.xml
man/systemd-hwdb.xml
man/systemd-journal-upload.xml
man/systemd-journald.service.xml
man/systemd-machine-id-commit.service.xml
man/systemd-machine-id-setup.xml
man/systemd-modules-load.service.xml
man/systemd-networkd-wait-online.service.xml
man/systemd-notify.xml
man/systemd-nspawn.xml
man/systemd-path.xml
man/systemd-random-seed.service.xml
man/systemd-remount-fs.service.xml
man/systemd-resolved.service.xml
man/systemd-run.xml
man/systemd-sysctl.service.xml
man/systemd-system.conf.xml
man/systemd-sysusers.xml
man/systemd-sysv-generator.xml
man/systemd-timesyncd.service.xml
man/systemd-tmpfiles.xml
man/systemd-udevd.service.xml
man/systemd-update-done.service.xml
man/systemd-user-sessions.service.xml
man/systemd-vconsole-setup.service.xml
man/systemd.automount.xml
man/systemd.device.xml
man/systemd.exec.xml
man/systemd.generator.xml
man/systemd.kill.xml
man/systemd.link.xml
man/systemd.mount.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.nspawn.xml
man/systemd.path.xml
man/systemd.resource-control.xml
man/systemd.scope.xml
man/systemd.service.xml
man/systemd.slice.xml
man/systemd.snapshot.xml [deleted file]
man/systemd.socket.xml
man/systemd.special.xml
man/systemd.swap.xml
man/systemd.target.xml
man/systemd.time.xml
man/systemd.timer.xml
man/systemd.unit.xml
man/systemd.xml
man/sysusers.d.xml
man/timedatectl.xml
man/timesyncd.conf.xml
man/tmpfiles.d.xml
man/udev.xml
man/udev_device_get_syspath.xml
man/udev_device_new_from_syspath.xml
man/udev_enumerate_scan_devices.xml
man/udev_list_entry.xml
man/udevadm.xml
po/LINGUAS
po/POTFILES.skip
po/da.po
po/ko.po
po/zh_CN.po [new file with mode: 0644]
shell-completion/bash/hostnamectl
shell-completion/bash/journalctl
shell-completion/bash/systemctl.in
shell-completion/bash/systemd-run
shell-completion/zsh/_journalctl
shell-completion/zsh/_sd_unit_files
shell-completion/zsh/_systemctl.in
shell-completion/zsh/_systemd-run
src/activate/activate.c
src/analyze/analyze-verify.c
src/analyze/analyze.c
src/ask-password/ask-password.c
src/backlight/backlight.c
src/basic/alloc-util.c [new file with mode: 0644]
src/basic/alloc-util.h [new file with mode: 0644]
src/basic/async.c
src/basic/audit-util.c [moved from src/basic/audit.c with 95% similarity]
src/basic/audit-util.h [moved from src/basic/audit.h with 100% similarity]
src/basic/barrier.c
src/basic/bitmap.c
src/basic/btrfs-util.c
src/basic/btrfs-util.h
src/basic/bus-label.c
src/basic/calendarspec.c
src/basic/calendarspec.h
src/basic/cap-list.c
src/basic/capability-util.c [moved from src/basic/capability.c with 97% similarity]
src/basic/capability-util.h [moved from src/basic/capability.h with 100% similarity]
src/basic/cgroup-util.c
src/basic/chattr-util.c [new file with mode: 0644]
src/basic/chattr-util.h [new file with mode: 0644]
src/basic/clock-util.c
src/basic/clock-util.h
src/basic/conf-files.c
src/basic/copy.c
src/basic/cpu-set-util.c
src/basic/def.h
src/basic/device-nodes.h
src/basic/dirent-util.c [new file with mode: 0644]
src/basic/dirent-util.h [new file with mode: 0644]
src/basic/env-util.c
src/basic/env-util.h
src/basic/escape.c [new file with mode: 0644]
src/basic/escape.h [new file with mode: 0644]
src/basic/ether-addr-util.c [new file with mode: 0644]
src/basic/ether-addr-util.h
src/basic/extract-word.c [new file with mode: 0644]
src/basic/extract-word.h [new file with mode: 0644]
src/basic/fd-util.c [new file with mode: 0644]
src/basic/fd-util.h [new file with mode: 0644]
src/basic/fdset.c
src/basic/fdset.h
src/basic/fileio.c
src/basic/fileio.h
src/basic/formats-util.h [moved from src/shared/formats-util.h with 100% similarity]
src/basic/fs-util.c [new file with mode: 0644]
src/basic/fs-util.h [new file with mode: 0644]
src/basic/glob-util.c [new file with mode: 0644]
src/basic/glob-util.h [new file with mode: 0644]
src/basic/hashmap.c
src/basic/hexdecoct.c [new file with mode: 0644]
src/basic/hexdecoct.h [new file with mode: 0644]
src/basic/hostname-util.c
src/basic/in-addr-util.c
src/basic/io-util.c [new file with mode: 0644]
src/basic/io-util.h [new file with mode: 0644]
src/basic/json.c
src/basic/locale-util.c
src/basic/locale-util.h
src/basic/lockfile-util.c
src/basic/log.c
src/basic/log.h
src/basic/login-util.c
src/basic/login-util.h
src/basic/macro.h
src/basic/memfd-util.c
src/basic/memfd-util.h
src/basic/missing.h
src/basic/mkdir.c
src/basic/mount-util.c [new file with mode: 0644]
src/basic/mount-util.h [new file with mode: 0644]
src/basic/parse-util.c [new file with mode: 0644]
src/basic/parse-util.h [new file with mode: 0644]
src/basic/path-util.c
src/basic/path-util.h
src/basic/prioq.c
src/basic/proc-cmdline.c [new file with mode: 0644]
src/basic/proc-cmdline.h [new file with mode: 0644]
src/basic/process-util.c
src/basic/process-util.h
src/basic/random-util.c
src/basic/replace-var.c
src/basic/rlimit-util.c [new file with mode: 0644]
src/basic/rlimit-util.h [moved from src/core/snapshot.h with 71% similarity]
src/basic/rm-rf.c
src/basic/selinux-util.c
src/basic/signal-util.c
src/basic/signal-util.h
src/basic/smack-util.c
src/basic/socket-label.c
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/stat-util.c [new file with mode: 0644]
src/basic/stat-util.h [new file with mode: 0644]
src/basic/stdio-util.h [new file with mode: 0644]
src/basic/strbuf.c
src/basic/string-table.c [new file with mode: 0644]
src/basic/string-table.h [new file with mode: 0644]
src/basic/string-util.c [new file with mode: 0644]
src/basic/string-util.h [new file with mode: 0644]
src/basic/strv.c
src/basic/strv.h
src/basic/syslog-util.c [new file with mode: 0644]
src/basic/syslog-util.h [new file with mode: 0644]
src/basic/terminal-util.c
src/basic/terminal-util.h
src/basic/time-util.c
src/basic/time-util.h
src/basic/umask-util.h [new file with mode: 0644]
src/basic/unit-name.c
src/basic/unit-name.h
src/basic/user-util.c [new file with mode: 0644]
src/basic/user-util.h [new file with mode: 0644]
src/basic/utf8.c
src/basic/util.c
src/basic/util.h
src/basic/verbs.c
src/basic/virt.c
src/basic/virt.h
src/basic/web-util.c [new file with mode: 0644]
src/basic/web-util.h [moved from src/core/dbus-snapshot.h with 80% similarity]
src/basic/xattr-util.c [new file with mode: 0644]
src/basic/xattr-util.h [new file with mode: 0644]
src/basic/xml.c
src/binfmt/binfmt.c
src/boot/bootctl.c
src/bootchart/bootchart.c
src/bootchart/store.c
src/bootchart/svg.c
src/bus-proxyd/bus-proxyd.c
src/bus-proxyd/bus-xml-policy.c
src/bus-proxyd/driver.c
src/bus-proxyd/proxy.c
src/bus-proxyd/proxy.h
src/bus-proxyd/stdio-bridge.c
src/bus-proxyd/synthesize.c
src/bus-proxyd/synthesize.h
src/bus-proxyd/test-bus-xml-policy.c
src/cgls/cgls.c
src/cgroups-agent/cgroups-agent.c
src/cgtop/cgtop.c
src/core/audit-fd.c
src/core/automount.c
src/core/bus-endpoint.c
src/core/bus-policy.c
src/core/busname.c
src/core/busname.h
src/core/cgroup.c
src/core/dbus-automount.c
src/core/dbus-busname.c
src/core/dbus-cgroup.c
src/core/dbus-cgroup.h
src/core/dbus-execute.c
src/core/dbus-execute.h
src/core/dbus-job.c
src/core/dbus-job.h
src/core/dbus-kill.h
src/core/dbus-manager.c
src/core/dbus-mount.c
src/core/dbus-mount.h
src/core/dbus-path.c
src/core/dbus-scope.c
src/core/dbus-service.c
src/core/dbus-snapshot.c [deleted file]
src/core/dbus-socket.c
src/core/dbus-swap.c
src/core/dbus-target.h
src/core/dbus-timer.c
src/core/dbus-unit.c
src/core/dbus.c
src/core/device.c
src/core/execute.c
src/core/execute.h
src/core/failure-action.c
src/core/hostname-setup.c
src/core/ima-setup.c
src/core/job.c
src/core/job.h
src/core/kill.c
src/core/killall.c
src/core/kmod-setup.c
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/load-fragment.h
src/core/locale-setup.c
src/core/loopback-setup.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/namespace.c
src/core/path.c
src/core/scope.c
src/core/selinux-access.c
src/core/selinux-access.h
src/core/selinux-setup.c
src/core/service.c
src/core/show-status.c
src/core/show-status.h
src/core/shutdown.c
src/core/slice.c
src/core/smack-setup.c
src/core/snapshot.c [deleted file]
src/core/socket.c
src/core/swap.c
src/core/swap.h
src/core/target.c
src/core/timer.c
src/core/transaction.c
src/core/transaction.h
src/core/umount.c
src/core/unit-printf.c
src/core/unit.c
src/core/unit.h
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup.c
src/dbus1-generator/dbus1-generator.c
src/debug-generator/debug-generator.c
src/delta/delta.c
src/detect-virt/detect-virt.c
src/escape/escape.c
src/firstboot/firstboot.c
src/fsck/fsck.c
src/fstab-generator/fstab-generator.c
src/getty-generator/getty-generator.c
src/gpt-auto-generator/gpt-auto-generator.c
src/hibernate-resume/hibernate-resume-generator.c
src/hibernate-resume/hibernate-resume.c
src/hostname/hostnamectl.c
src/hostname/hostnamed.c
src/hwdb/hwdb.c
src/import/aufs-util.c
src/import/curl-util.c
src/import/curl-util.h
src/import/export-raw.c
src/import/export-tar.c
src/import/export.c
src/import/import-common.c
src/import/import-compress.c
src/import/import-raw.c
src/import/import-tar.c
src/import/import.c
src/import/importd.c
src/import/pull-common.c
src/import/pull-dkr.c
src/import/pull-job.c
src/import/pull-raw.c
src/import/pull-tar.c
src/import/pull.c
src/import/qcow2-util.c
src/import/test-qcow2.c
src/initctl/initctl.c
src/journal-remote/journal-gatewayd.c
src/journal-remote/journal-remote-parse.c
src/journal-remote/journal-remote-write.c
src/journal-remote/journal-remote.c
src/journal-remote/journal-upload-journal.c
src/journal-remote/journal-upload.c
src/journal-remote/log-generator.py
src/journal-remote/microhttpd-util.c
src/journal/cat.c
src/journal/catalog.c
src/journal/compress.c
src/journal/coredump-vacuum.c
src/journal/coredump.c
src/journal/coredumpctl.c
src/journal/fsprg.h
src/journal/journal-authenticate.c
src/journal/journal-def.h
src/journal/journal-file.c
src/journal/journal-file.h
src/journal/journal-internal.h
src/journal/journal-qrcode.h
src/journal/journal-send.c
src/journal/journal-vacuum.c
src/journal/journal-verify.c
src/journal/journalctl.c
src/journal/journald-audit.c
src/journal/journald-console.c
src/journal/journald-kmsg.c
src/journal/journald-native.c
src/journal/journald-rate-limit.c
src/journal/journald-server.c
src/journal/journald-server.h
src/journal/journald-stream.c
src/journal/journald-stream.h
src/journal/journald-syslog.c
src/journal/journald-wall.c
src/journal/journald.c
src/journal/mmap-cache.c
src/journal/sd-journal.c
src/journal/stacktrace.c
src/journal/test-catalog.c
src/journal/test-compress-benchmark.c
src/journal/test-compress.c
src/journal/test-journal-enum.c
src/journal/test-journal-flush.c
src/journal/test-journal-init.c
src/journal/test-journal-interleaving.c
src/journal/test-journal-match.c
src/journal/test-journal-send.c
src/journal/test-journal-stream.c
src/journal/test-journal-syslog.c
src/journal/test-journal-verify.c
src/journal/test-mmap-cache.c
src/libsystemd-network/arp-util.c
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/dhcp-identifier.h
src/libsystemd-network/dhcp-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/dhcp6-internal.h
src/libsystemd-network/dhcp6-network.c
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/icmp6-util.c [new file with mode: 0644]
src/libsystemd-network/icmp6-util.h [new file with mode: 0644]
src/libsystemd-network/lldp-internal.c
src/libsystemd-network/lldp-internal.h
src/libsystemd-network/lldp-network.c
src/libsystemd-network/lldp-port.c
src/libsystemd-network/lldp-tlv.c
src/libsystemd-network/network-internal.c
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-dhcp6-lease.c
src/libsystemd-network/sd-icmp6-nd.c [deleted file]
src/libsystemd-network/sd-ipv4acd.c
src/libsystemd-network/sd-ipv4ll.c
src/libsystemd-network/sd-lldp.c
src/libsystemd-network/sd-ndisc.c [new file with mode: 0644]
src/libsystemd-network/sd-pppoe.c [deleted file]
src/libsystemd-network/test-dhcp-client.c
src/libsystemd-network/test-dhcp-option.c
src/libsystemd-network/test-dhcp-server.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd-network/test-icmp6-rs.c [deleted file]
src/libsystemd-network/test-ipv4ll-manual.c
src/libsystemd-network/test-ipv4ll.c
src/libsystemd-network/test-lldp.c
src/libsystemd-network/test-ndisc-rs.c [new file with mode: 0644]
src/libsystemd-network/test-pppoe.c [deleted file]
src/libsystemd/sd-bus/bus-container.c
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-convenience.c
src/libsystemd/sd-bus/bus-creds.c
src/libsystemd/sd-bus/bus-dump.c
src/libsystemd/sd-bus/bus-error.c
src/libsystemd/sd-bus/bus-internal.c
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-introspect.c
src/libsystemd/sd-bus/bus-kernel.c
src/libsystemd/sd-bus/bus-match.c
src/libsystemd/sd-bus/bus-match.h
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-message.h
src/libsystemd/sd-bus/bus-objects.c
src/libsystemd/sd-bus/bus-slot.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/bus-track.c
src/libsystemd/sd-bus/bus-type.h
src/libsystemd/sd-bus/busctl-introspect.c
src/libsystemd/sd-bus/busctl.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-benchmark.c
src/libsystemd/sd-bus/test-bus-chat.c
src/libsystemd/sd-bus/test-bus-cleanup.c
src/libsystemd/sd-bus/test-bus-gvariant.c
src/libsystemd/sd-bus/test-bus-kernel-bloom.c
src/libsystemd/sd-bus/test-bus-kernel.c
src/libsystemd/sd-bus/test-bus-marshal.c
src/libsystemd/sd-bus/test-bus-objects.c
src/libsystemd/sd-bus/test-bus-proxy.c
src/libsystemd/sd-bus/test-bus-server.c
src/libsystemd/sd-bus/test-bus-signature.c
src/libsystemd/sd-bus/test-bus-zero-copy.c
src/libsystemd/sd-daemon/sd-daemon.c
src/libsystemd/sd-device/Makefile [new symlink]
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/device-private.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-event/event-util.h
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-event/test-event.c
src/libsystemd/sd-hwdb/hwdb-util.h
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-id128/sd-id128.c
src/libsystemd/sd-login/sd-login.c
src/libsystemd/sd-login/test-login.c
src/libsystemd/sd-netlink/local-addresses.c
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/rtnl-message.c
src/libsystemd/sd-netlink/sd-netlink.c
src/libsystemd/sd-netlink/test-local-addresses.c
src/libsystemd/sd-netlink/test-netlink.c
src/libsystemd/sd-network/network-util.c
src/libsystemd/sd-network/sd-network.c
src/libsystemd/sd-path/sd-path.c
src/libsystemd/sd-resolve/resolve-util.h
src/libsystemd/sd-resolve/sd-resolve.c
src/libsystemd/sd-resolve/test-resolve.c
src/libsystemd/sd-utf8/sd-utf8.c
src/libudev/libudev-device-internal.h
src/libudev/libudev-device-private.c
src/libudev/libudev-device.c
src/libudev/libudev-enumerate.c
src/libudev/libudev-hwdb.c
src/libudev/libudev-list.c
src/libudev/libudev-monitor.c
src/libudev/libudev-private.h
src/libudev/libudev-queue.c
src/libudev/libudev-util.c
src/libudev/libudev.c
src/locale/localectl.c
src/locale/localed.c
src/login/inhibit.c
src/login/loginctl.c
src/login/logind-acl.c
src/login/logind-acl.h
src/login/logind-action.c
src/login/logind-action.h
src/login/logind-button.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-device.c
src/login/logind-inhibit.c
src/login/logind-seat-dbus.c
src/login/logind-seat.c
src/login/logind-session-dbus.c
src/login/logind-session-device.c
src/login/logind-session.c
src/login/logind-user-dbus.c
src/login/logind-user.c
src/login/logind-utmp.c
src/login/logind.c
src/login/logind.h
src/login/pam_systemd.c
src/login/sysfs-show.c
src/login/test-inhibit.c
src/machine-id-setup/machine-id-setup-main.c
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machine.c
src/machine/machinectl.c
src/machine/machined-dbus.c
src/machine/machined.c
src/machine/machined.h
src/modules-load/modules-load.c
src/network/networkctl.c
src/network/networkd-address-pool.c
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-fdb.c
src/network/networkd-ipv4ll.c
src/network/networkd-link-bus.c
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager-bus.c
src/network/networkd-manager.c
src/network/networkd-ndisc.c [new file with mode: 0644]
src/network/networkd-netdev-bond.c
src/network/networkd-netdev-bridge.c
src/network/networkd-netdev-gperf.gperf
src/network/networkd-netdev-ipvlan.c
src/network/networkd-netdev-macvlan.c
src/network/networkd-netdev-tunnel.c
src/network/networkd-netdev-tuntap.c
src/network/networkd-netdev-veth.c
src/network/networkd-netdev-vlan.c
src/network/networkd-netdev-vxlan.c
src/network/networkd-netdev-vxlan.h
src/network/networkd-netdev.c
src/network/networkd-network-bus.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-route.c
src/network/networkd-route.h
src/network/networkd-util.c
src/network/networkd-wait-online-link.c
src/network/networkd-wait-online-manager.c
src/network/networkd.c
src/network/networkd.h
src/network/test-network.c
src/notify/notify.c
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-expose-ports.c
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-mount.h
src/nspawn/nspawn-network.c
src/nspawn/nspawn-network.h
src/nspawn/nspawn-register.c
src/nspawn/nspawn-register.h
src/nspawn/nspawn-settings.c
src/nspawn/nspawn-settings.h
src/nspawn/nspawn-setuid.c
src/nspawn/nspawn.c
src/nss-myhostname/nss-myhostname.c
src/nss-mymachines/nss-mymachines.c
src/nss-resolve/nss-resolve.c
src/path/path.c
src/quotacheck/quotacheck.c
src/random-seed/random-seed.c
src/rc-local-generator/rc-local-generator.c
src/remount-fs/remount-fs.c
src/reply-password/reply-password.c
src/resolve-host/resolve-host.c
src/resolve/resolved-bus.c
src/resolve/resolved-conf.c
src/resolve/resolved-dns-answer.c
src/resolve/resolved-dns-cache.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-question.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-zone.c
src/resolve/resolved-link.c
src/resolve/resolved-llmnr.c
src/resolve/resolved-manager.c
src/resolve/resolved.c
src/rfkill/rfkill.c
src/run/run.c
src/shared/acl-util.c
src/shared/acpi-fpdt.c
src/shared/apparmor-util.c
src/shared/architecture.c
src/shared/ask-password-api.c
src/shared/base-filesystem.c
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/cgroup-show.c
src/shared/clean-ipc.c
src/shared/condition.c
src/shared/conf-parser.c
src/shared/dev-setup.c
src/shared/dns-domain.c
src/shared/dropin.c
src/shared/efivars.c
src/shared/firewall-util.c
src/shared/fstab-util.c
src/shared/fstab-util.h
src/shared/generator.c
src/shared/import-util.c
src/shared/import-util.h
src/shared/install-printf.c
src/shared/install.c
src/shared/install.h
src/shared/logs-show.c
src/shared/machine-image.c
src/shared/machine-pool.c
src/shared/pager.c
src/shared/path-lookup.c
src/shared/ptyfwd.c
src/shared/seccomp-util.c
src/shared/sleep-config.c
src/shared/spawn-polkit-agent.c
src/shared/specifier.c
src/shared/switch-root.c
src/shared/sysctl-util.c
src/shared/uid-range.c
src/shared/utmp-wtmp.c
src/shared/watchdog.c
src/sleep/sleep.c
src/socket-proxy/socket-proxyd.c
src/sysctl/sysctl.c
src/system-update-generator/system-update-generator.c
src/systemctl/systemctl.c
src/systemd/sd-device.h
src/systemd/sd-dhcp-client.h
src/systemd/sd-dhcp-lease.h
src/systemd/sd-dhcp-server.h
src/systemd/sd-dhcp6-client.h
src/systemd/sd-dhcp6-lease.h
src/systemd/sd-hwdb.h
src/systemd/sd-icmp6-nd.h [deleted file]
src/systemd/sd-ipv4acd.h
src/systemd/sd-ipv4ll.h
src/systemd/sd-lldp.h
src/systemd/sd-ndisc.h [new file with mode: 0644]
src/systemd/sd-netlink.h
src/systemd/sd-path.h
src/systemd/sd-pppoe.h [deleted file]
src/systemd/sd-resolve.h
src/sysusers/sysusers.c
src/sysv-generator/sysv-generator.c
src/test/test-af-list.c
src/test/test-arphrd-list.c
src/test/test-async.c
src/test/test-btrfs.c
src/test/test-calendarspec.c
src/test/test-cap-list.c
src/test/test-capability.c
src/test/test-cgroup-util.c
src/test/test-cgroup.c
src/test/test-condition.c
src/test/test-conf-files.c
src/test/test-conf-parser.c
src/test/test-copy.c
src/test/test-date.c
src/test/test-device-nodes.c
src/test/test-dns-domain.c
src/test/test-ellipsize.c
src/test/test-engine.c
src/test/test-env-replace.c
src/test/test-execute.c
src/test/test-extract-word.c [new file with mode: 0644]
src/test/test-fdset.c
src/test/test-fileio.c
src/test/test-fstab-util.c
src/test/test-hashmap-plain.c
src/test/test-hostname-util.c
src/test/test-id128.c
src/test/test-install-root.c [new file with mode: 0644]
src/test/test-install.c
src/test/test-ipcrm.c
src/test/test-json.c
src/test/test-libudev.c
src/test/test-namespace.c
src/test/test-netlink-manual.c
src/test/test-parse-util.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-prioq.c
src/test/test-process-util.c
src/test/test-replace-var.c
src/test/test-sigbus.c
src/test/test-socket-util.c
src/test/test-strbuf.c
src/test/test-string-util.c [new file with mode: 0644]
src/test/test-strip-tab-ansi.c
src/test/test-strv.c
src/test/test-strxcpyx.c
src/test/test-tables.c
src/test/test-terminal-util.c
src/test/test-time.c
src/test/test-tmpfiles.c
src/test/test-udev.c
src/test/test-uid-range.c
src/test/test-unit-file.c
src/test/test-unit-name.c
src/test/test-user-util.c [new file with mode: 0644]
src/test/test-utf8.c
src/test/test-util.c
src/test/test-xml.c
src/timedate/timedatectl.c
src/timedate/timedated.c
src/timesync/timesyncd-conf.c
src/timesync/timesyncd-manager.c
src/timesync/timesyncd-server.c
src/timesync/timesyncd.c
src/tmpfiles/tmpfiles.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/.gitignore
src/udev/ata_id/ata_id.c
src/udev/cdrom_id/cdrom_id.c
src/udev/collect/collect.c
src/udev/net/ethtool-util.c
src/udev/net/link-config.c
src/udev/net/link-config.h
src/udev/scsi_id/scsi_id.c
src/udev/scsi_id/scsi_serial.c
src/udev/udev-builtin-blkid.c
src/udev/udev-builtin-btrfs.c
src/udev/udev-builtin-hwdb.c
src/udev/udev-builtin-input_id.c
src/udev/udev-builtin-keyboard.c
src/udev/udev-builtin-kmod.c
src/udev/udev-builtin-net_id.c
src/udev/udev-builtin-net_setup_link.c
src/udev/udev-builtin-path_id.c
src/udev/udev-builtin-uaccess.c
src/udev/udev-builtin-usb_id.c
src/udev/udev-builtin.c
src/udev/udev-ctrl.c
src/udev/udev-event.c
src/udev/udev-node.c
src/udev/udev-rules.c
src/udev/udev.h
src/udev/udevadm-hwdb.c
src/udev/udevadm-info.c
src/udev/udevadm-monitor.c
src/udev/udevadm-settle.c
src/udev/udevadm-test-builtin.c
src/udev/udevadm-test.c
src/udev/udevadm-trigger.c
src/udev/udevadm-util.c
src/udev/udevadm.c
src/udev/udevd.c
src/udev/v4l_id/v4l_id.c
src/update-done/update-done.c
src/update-utmp/update-utmp.c
src/user-sessions/user-sessions.c
src/vconsole/vconsole-setup.c
test/TEST-01-BASIC/test.sh
test/TEST-02-CRYPTSETUP/test.sh
test/TEST-03-JOBS/test-jobs.sh
test/end.service [new file with mode: 0644]
test/end.service.in [deleted file]
test/exec-environment-empty.service [deleted file]
test/exec-environment.service [deleted file]
test/exec-group.service [deleted file]
test/exec-umask-0177.service [deleted file]
test/exec-umask-default.service [deleted file]
test/exec-user.service [deleted file]
test/paths.target [deleted symlink]
test/test-execute/exec-capabilityboundingset-invert.service [new file with mode: 0644]
test/test-execute/exec-capabilityboundingset-merge.service [new file with mode: 0644]
test/test-execute/exec-capabilityboundingset-reset.service [new file with mode: 0644]
test/test-execute/exec-capabilityboundingset-simple.service [new file with mode: 0644]
test/test-execute/exec-environment-empty.service [new file with mode: 0644]
test/test-execute/exec-environment-multiple.service [moved from test/exec-environment-multiple.service with 53% similarity]
test/test-execute/exec-environment.service [new file with mode: 0644]
test/test-execute/exec-environmentfile.service [new file with mode: 0644]
test/test-execute/exec-group.service [new file with mode: 0644]
test/test-execute/exec-ignoresigpipe-no.service [moved from test/exec-ignoresigpipe-no.service with 68% similarity]
test/test-execute/exec-ignoresigpipe-yes.service [moved from test/exec-ignoresigpipe-yes.service with 69% similarity]
test/test-execute/exec-ioschedulingclass-best-effort.service [new file with mode: 0644]
test/test-execute/exec-ioschedulingclass-idle.service [new file with mode: 0644]
test/test-execute/exec-ioschedulingclass-none.service [new file with mode: 0644]
test/test-execute/exec-ioschedulingclass-realtime.service [new file with mode: 0644]
test/test-execute/exec-oomscoreadjust-negative.service [new file with mode: 0644]
test/test-execute/exec-oomscoreadjust-positive.service [new file with mode: 0644]
test/test-execute/exec-passenvironment-absent.service [new file with mode: 0644]
test/test-execute/exec-passenvironment-empty.service [new file with mode: 0644]
test/test-execute/exec-passenvironment-repeated.service [new file with mode: 0644]
test/test-execute/exec-passenvironment.service [new file with mode: 0644]
test/test-execute/exec-personality-s390.service [moved from test/exec-personality-s390.service with 53% similarity]
test/test-execute/exec-personality-x86-64.service [moved from test/exec-personality-x86-64.service with 53% similarity]
test/test-execute/exec-personality-x86.service [moved from test/exec-personality-x86.service with 52% similarity]
test/test-execute/exec-privatedevices-no.service [moved from test/exec-privatedevices-no.service with 63% similarity]
test/test-execute/exec-privatedevices-yes.service [moved from test/exec-privatedevices-yes.service with 63% similarity]
test/test-execute/exec-privatenetwork-yes.service [new file with mode: 0644]
test/test-execute/exec-privatetmp-no.service [moved from test/exec-privatetmp-no.service with 55% similarity]
test/test-execute/exec-privatetmp-yes.service [moved from test/exec-privatetmp-yes.service with 55% similarity]
test/test-execute/exec-runtimedirectory-mode.service [moved from test/exec-runtimedirectory-mode.service with 57% similarity]
test/test-execute/exec-runtimedirectory-owner.service [moved from test/exec-runtimedirectory-owner.service with 63% similarity]
test/test-execute/exec-runtimedirectory.service [moved from test/exec-runtimedirectory.service with 61% similarity]
test/test-execute/exec-systemcallerrornumber.service [moved from test/exec-systemcallerrornumber.service with 70% similarity]
test/test-execute/exec-systemcallfilter-failing.service [moved from test/exec-systemcallfilter-failing.service with 93% similarity]
test/test-execute/exec-systemcallfilter-failing2.service [moved from test/exec-systemcallfilter-failing2.service with 93% similarity]
test/test-execute/exec-systemcallfilter-not-failing.service [moved from test/exec-systemcallfilter-not-failing.service with 94% similarity]
test/test-execute/exec-systemcallfilter-not-failing2.service [moved from test/exec-systemcallfilter-not-failing2.service with 88% similarity]
test/test-execute/exec-umask-0177.service [new file with mode: 0644]
test/test-execute/exec-umask-default.service [new file with mode: 0644]
test/test-execute/exec-user.service [new file with mode: 0644]
test/test-execute/exec-workingdirectory.service [moved from test/exec-workingdirectory.service with 57% similarity]
test/test-functions
test/test-path/basic.target [new symlink]
test/test-path/path-changed.path [moved from test/path-changed.path with 100% similarity]
test/test-path/path-changed.service [moved from test/path-changed.service with 100% similarity]
test/test-path/path-directorynotempty.path [moved from test/path-directorynotempty.path with 100% similarity]
test/test-path/path-directorynotempty.service [moved from test/path-directorynotempty.service with 100% similarity]
test/test-path/path-exists.path [moved from test/path-exists.path with 100% similarity]
test/test-path/path-exists.service [moved from test/path-exists.service with 100% similarity]
test/test-path/path-existsglob.path [moved from test/path-existsglob.path with 100% similarity]
test/test-path/path-existsglob.service [moved from test/path-existsglob.service with 100% similarity]
test/test-path/path-makedirectory.path [moved from test/path-makedirectory.path with 100% similarity]
test/test-path/path-makedirectory.service [moved from test/path-makedirectory.service with 100% similarity]
test/test-path/path-modified.path [moved from test/path-modified.path with 100% similarity]
test/test-path/path-modified.service [moved from test/path-modified.service with 100% similarity]
test/test-path/path-mycustomunit.service [moved from test/path-mycustomunit.service with 100% similarity]
test/test-path/path-service.service [moved from test/path-service.service with 100% similarity]
test/test-path/path-unit.path [moved from test/path-unit.path with 100% similarity]
test/test-path/paths.target [new symlink]
test/test-path/sysinit.target [new symlink]
test/unstoppable.service
tmpfiles.d/home.conf
tmpfiles.d/systemd-nspawn.conf
tmpfiles.d/tmp.conf
tmpfiles.d/var.conf
units/.gitignore
units/system.slice
units/systemd-networkd.socket
units/systemd-nspawn@.service.in
units/tmp.mount.m4 [moved from units/tmp.mount with 100% similarity]
units/user/exit.target

index 709c8b53d08e84c31f1f57f358024d379301ea9a..922ff3244fc363e03a951bd9c34433db3d33fca5 100644 (file)
 /*.tar.bz2
 /*.tar.gz
 /*.tar.xz
-/Makefile
-/TAGS
 /GPATH
 /GRTAGS
 /GSYMS
 /GTAGS
+/Makefile
+/TAGS
 /ata_id
 /bootctl
 /build-aux
 /journalctl
 /libsystemd-*.c
 /libtool
+/linuxx64.efi.stub
 /localectl
 /loginctl
 /machinectl
 /mtd_probe
 /networkctl
-/linuxx64.efi.stub
-/systemd-bootx64.efi
-/test-efi-disk.img
 /scsi_id
 /systemadm
 /systemctl
@@ -61,6 +59,7 @@
 /systemd-backlight
 /systemd-binfmt
 /systemd-bootchart
+/systemd-bootx64.efi
 /systemd-bus-proxyd
 /systemd-cat
 /systemd-cgls
 /systemd-vconsole-setup
 /tags
 /test-acd
-/test-architecture
-/test-audit-type
 /test-af-list
+/test-architecture
 /test-arphrd-list
 /test-async
+/test-audit-type
 /test-barrier
 /test-bitmap
 /test-boot-timestamp
 /test-dhcp-server
 /test-dhcp6-client
 /test-dns-domain
+/test-efi-disk.img
 /test-ellipsize
 /test-engine
 /test-env-replace
 /test-event
 /test-execute
+/test-extract-word
 /test-fdset
 /test-fileio
-/test-fstab-util
 /test-firewall-util
+/test-fstab-util
 /test-hashmap
 /test-hostname
 /test-hostname-util
-/test-icmp6-rs
 /test-id128
 /test-inhibit
 /test-install
 /test-machine-tables
 /test-mmap-cache
 /test-namespace
+/test-ndisc-rs
+/test-netlink
+/test-netlink-manual
 /test-network
 /test-network-tables
 /test-ns
+/test-parse-util
 /test-path
 /test-path-lookup
 /test-path-util
-/test-pppoe
 /test-prioq
 /test-process-util
 /test-pty
 /test-replace-var
 /test-resolve
 /test-ring
-/test-netlink
-/test-netlink-manual
 /test-sched-prio
 /test-set
 /test-sigbus
 /test-socket-util
 /test-ssd
 /test-strbuf
+/test-string-util
 /test-strip-tab-ansi
 /test-strv
 /test-strxcpyx
 /test-unaligned
 /test-unit-file
 /test-unit-name
+/test-user-util
 /test-utf8
 /test-util
 /test-verbs
index 7617f324032cab938011df1850fe7b553aa503c0..69060957dad2f4f527cbfd38407d6d47d54ac633 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -63,3 +63,4 @@ Arnd Bergmann <arnd@arndb.de>
 Tom Rini <trini@kernel.crashing.org>
 Paul Mundt <lethal@linux-sh.org>
 Atul Sabharwal <atul.sabharwal@intel.com>
+Daniel Machon <Danielmachon@live.dk>
index d373f4dea3e2a7d19c48d27dc6c5710ce26da5a6..00643032032b4a6259ee24494ebcce2142e6a61a 100644 (file)
 - Think about the types you use. If a value cannot sensibly be
   negative, do not use "int", but use "unsigned".
 
-- Do not use types like "short". They *never* make sense. Use ints,
-  longs, long longs, all in unsigned+signed fashion, and the fixed
-  size types uint32_t and so on, as well as size_t, but nothing
-  else. Do not use kernel types like u32 and so on, leave that to the
-  kernel.
+- Use "char" only for actual characters. Use "uint8_t" or "int8_t"
+  when you actually mean a byte-sized signed or unsigned
+  integers. When referring to a generic byte, we generally prefer the
+  unsigned variant "uint8_t". Do not use types based on "short". They
+  *never* make sense. Use ints, longs, long longs, all in
+  unsigned+signed fashion, and the fixed size types
+  uint8_t/uint16_t/uint32_t/uint64_t/int8_t/int16_t/int32_t and so on,
+  as well as size_t, but nothing else. Do not use kernel types like
+  u32 and so on, leave that to the kernel.
 
 - Public API calls (i.e. functions exported by our shared libraries)
   must be marked "_public_" and need to be prefixed with "sd_". No
 - If you want to concatenate two or more strings, consider using
   strjoin() rather than asprintf(), as the latter is a lot
   slower. This matters particularly in inner loops.
+
+- Please avoid using global variables as much as you can. And if you
+  do use them make sure they are static at least, instead of
+  exported. Especially in library-like code it is important to avoid
+  global variables. Why are global variables bad? They usually hinder
+  generic reusability of code (since they break in threaded programs,
+  and usually would require locking there), and as the code using them
+  has side-effects make programs intransparent. That said, there are
+  many cases where they explicitly make a lot of sense, and are OK to
+  use. For example, the log level and target in log.c is stored in a
+  global variable, and that's OK and probably expected by most. Also
+  in many cases we cache data in global variables. If you add more
+  caches like this, please be careful however, and think about
+  threading. Only use static variables if you are sure that
+  thread-safety doesn't matter in your case. Alternatively consider
+  using TLS, which is pretty easy to use with gcc's "thread_local"
+  concept. It's also OK to store data that is inherently global in
+  global variables, for example data parsed from command lines, see
+  below.
+
+- If you parse a command line, and want to store the parsed parameters
+  in global variables, please consider prefixing their names with
+  "arg_". We have been following this naming rule in most of our
+  tools, and we should continue to do so, as it makes it easy to
+  identify command line parameter variables, and makes it clear why it
+  is OK that they are global variables.
index 1ff85d7d2cbb512d8384a36ea6952f4ae5dc8556..c792c8932499feee2c6c5ecb1bb885abc8f73e53 100644 (file)
@@ -136,7 +136,6 @@ MANPAGES += \
        man/systemd.scope.5 \
        man/systemd.service.5 \
        man/systemd.slice.5 \
-       man/systemd.snapshot.5 \
        man/systemd.socket.5 \
        man/systemd.special.7 \
        man/systemd.swap.5 \
@@ -374,6 +373,7 @@ MANPAGES_ALIAS += \
        man/systemd-hybrid-sleep.service.8 \
        man/systemd-initctl.8 \
        man/systemd-initctl.socket.8 \
+       man/systemd-journald-audit.socket.8 \
        man/systemd-journald-dev-log.socket.8 \
        man/systemd-journald.8 \
        man/systemd-journald.socket.8 \
@@ -663,6 +663,7 @@ man/systemd-hibernate.service.8: man/systemd-suspend.service.8
 man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8
 man/systemd-initctl.8: man/systemd-initctl.service.8
 man/systemd-initctl.socket.8: man/systemd-initctl.service.8
+man/systemd-journald-audit.socket.8: man/systemd-journald.service.8
 man/systemd-journald-dev-log.socket.8: man/systemd-journald.service.8
 man/systemd-journald.8: man/systemd-journald.service.8
 man/systemd-journald.socket.8: man/systemd-journald.service.8
@@ -1378,6 +1379,9 @@ man/systemd-initctl.html: man/systemd-initctl.service.html
 man/systemd-initctl.socket.html: man/systemd-initctl.service.html
        $(html-alias)
 
+man/systemd-journald-audit.socket.html: man/systemd-journald.service.html
+       $(html-alias)
+
 man/systemd-journald-dev-log.socket.html: man/systemd-journald.service.html
        $(html-alias)
 
@@ -2408,7 +2412,6 @@ EXTRA_DIST += \
        man/systemd.scope.xml \
        man/systemd.service.xml \
        man/systemd.slice.xml \
-       man/systemd.snapshot.xml \
        man/systemd.socket.xml \
        man/systemd.special.xml \
        man/systemd.swap.xml \
index 8646e55450fb89005974226ed159707b2ec20732..9b93d0025c4d7fa38f58a369205bed7c3306ef1c 100644 (file)
@@ -616,7 +616,8 @@ EXTRA_DIST += \
        units/initrd-udevadm-cleanup-db.service.in \
        units/initrd-switch-root.service.in \
        units/systemd-nspawn@.service.in \
-       units/systemd-update-done.service.in
+       units/systemd-update-done.service.in \
+    units/tmp.mount.m4
 
 if HAVE_SYSV_COMPAT
 nodist_systemunit_DATA += \
@@ -724,8 +725,8 @@ SOURCE_XML_FILES = ${patsubst %,$(top_srcdir)/%,$(filter-out man/systemd.directi
 # This target should only be run manually. It recreates Makefile-man.am
 # file in the source directory based on all man/*.xml files. Run it after
 # adding, removing, or changing the conditional in a man page.
-update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB)
-       $(AM_V_GEN)$(PYTHON) $^ > $(top_srcdir)/Makefile-man.tmp
+update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB) man/custom-entities.ent
+       $(AM_V_GEN)$(PYTHON) $< $(XML_GLOB) > $(top_srcdir)/Makefile-man.tmp
        $(AM_V_at)mv $(top_srcdir)/Makefile-man.tmp $(top_srcdir)/Makefile-man.am
        @echo "Makefile-man.am has been regenerated"
 
@@ -761,10 +762,11 @@ noinst_LTLIBRARIES += \
 
 libbasic_la_SOURCES = \
        src/basic/missing.h \
-       src/basic/capability.c \
-       src/basic/capability.h \
+       src/basic/capability-util.c \
+       src/basic/capability-util.h \
        src/basic/conf-files.c \
        src/basic/conf-files.h \
+       src/basic/stdio-util.h \
        src/basic/hostname-util.h \
        src/basic/hostname-util.c \
        src/basic/unit-name.c \
@@ -780,6 +782,42 @@ libbasic_la_SOURCES = \
        src/basic/refcnt.h \
        src/basic/util.c \
        src/basic/util.h \
+       src/basic/io-util.c \
+       src/basic/io-util.h \
+       src/basic/string-util.c \
+       src/basic/string-util.h \
+       src/basic/fd-util.c \
+       src/basic/fd-util.h \
+       src/basic/parse-util.c \
+       src/basic/parse-util.h \
+       src/basic/user-util.c \
+       src/basic/user-util.h \
+       src/basic/rlimit-util.c \
+       src/basic/rlimit-util.h \
+       src/basic/dirent-util.c \
+       src/basic/dirent-util.h \
+       src/basic/xattr-util.c \
+       src/basic/xattr-util.h \
+       src/basic/chattr-util.c \
+       src/basic/chattr-util.h \
+       src/basic/proc-cmdline.c \
+       src/basic/proc-cmdline.h \
+       src/basic/fs-util.c \
+       src/basic/fs-util.h \
+       src/basic/syslog-util.c \
+       src/basic/syslog-util.h \
+       src/basic/stat-util.c \
+       src/basic/stat-util.h \
+       src/basic/mount-util.c \
+       src/basic/mount-util.h \
+       src/basic/hexdecoct.c \
+       src/basic/hexdecoct.h \
+       src/basic/glob-util.h \
+       src/basic/glob-util.c \
+       src/basic/extract-word.c \
+       src/basic/extract-word.h \
+       src/basic/escape.c \
+       src/basic/escape.h \
        src/basic/cpu-set-util.c \
        src/basic/cpu-set-util.h \
        src/basic/lockfile-util.c \
@@ -790,8 +828,11 @@ libbasic_la_SOURCES = \
        src/basic/time-util.h \
        src/basic/locale-util.c \
        src/basic/locale-util.h \
+       src/basic/umask-util.h \
        src/basic/signal-util.c \
        src/basic/signal-util.h \
+       src/basic/string-table.c \
+       src/basic/string-table.h \
        src/basic/mempool.c \
        src/basic/mempool.h \
        src/basic/hashmap.c \
@@ -806,6 +847,8 @@ libbasic_la_SOURCES = \
        src/basic/fdset.h \
        src/basic/prioq.c \
        src/basic/prioq.h \
+       src/basic/web-util.c \
+       src/basic/web-util.h \
        src/basic/strv.c \
        src/basic/strv.h \
        src/basic/env-util.c \
@@ -837,6 +880,7 @@ libbasic_la_SOURCES = \
        src/basic/in-addr-util.c \
        src/basic/in-addr-util.h \
        src/basic/ether-addr-util.h \
+       src/basic/ether-addr-util.c \
        src/basic/replace-var.c \
        src/basic/replace-var.h \
        src/basic/clock-util.c \
@@ -863,8 +907,8 @@ libbasic_la_SOURCES = \
        src/basic/login-util.c \
        src/basic/cap-list.c \
        src/basic/cap-list.h \
-       src/basic/audit.c \
-       src/basic/audit.h \
+       src/basic/audit-util.c \
+       src/basic/audit-util.h \
        src/basic/xml.c \
        src/basic/xml.h \
        src/basic/json.c \
@@ -898,7 +942,10 @@ libbasic_la_SOURCES = \
        src/basic/rm-rf.c \
        src/basic/rm-rf.h \
        src/basic/copy.c \
-       src/basic/copy.h
+       src/basic/copy.h \
+       src/basic/alloc-util.h \
+       src/basic/alloc-util.c \
+       src/basic/formats-util.h
 
 nodist_libbasic_la_SOURCES = \
        src/basic/errno-from-name.h \
@@ -919,7 +966,6 @@ libbasic_la_CFLAGS = \
 libbasic_la_LIBADD = \
        $(SELINUX_LIBS) \
        $(CAP_LIBS) \
-       -ldl \
        -lrt \
        -lm
 
@@ -939,7 +985,6 @@ libshared_la_SOURCES = \
        src/shared/architecture.h \
        src/shared/efivars.c \
        src/shared/efivars.h \
-       src/shared/formats-util.h \
        src/shared/fstab-util.c \
        src/shared/fstab-util.h \
        src/shared/sleep-config.c \
@@ -1093,8 +1138,6 @@ libcore_la_SOURCES = \
        src/core/bus-policy.h \
        src/core/target.c \
        src/core/target.h \
-       src/core/snapshot.c \
-       src/core/snapshot.h \
        src/core/device.c \
        src/core/device.h \
        src/core/mount.c \
@@ -1133,8 +1176,6 @@ libcore_la_SOURCES = \
        src/core/dbus-busname.h \
        src/core/dbus-target.c \
        src/core/dbus-target.h \
-       src/core/dbus-snapshot.c \
-       src/core/dbus-snapshot.h \
        src/core/dbus-device.c \
        src/core/dbus-device.h \
        src/core/dbus-mount.c \
@@ -1229,7 +1270,7 @@ BUILT_SOURCES += \
        $(gperf_gperf_m4_sources:-gperf.gperf.m4=-gperf-nulstr.c) \
        $(gperf_gperf_sources:-gperf.gperf=-gperf.c) \
        $(gperf_txt_sources:-list.txt=-from-name.h) \
-       $(gperf_txt_sources:-list.txt=-to-name.h)
+       $(filter-out %keyboard-keys-to-name.h,$(gperf_txt_sources:-list.txt=-to-name.h))
 
 CLEANFILES += \
        $(gperf_txt_sources:-list.txt=-from-name.gperf)
@@ -1402,6 +1443,10 @@ tests += \
        test-utf8 \
        test-ellipsize \
        test-util \
+       test-string-util \
+       test-extract-word \
+       test-parse-util \
+       test-user-util \
        test-hostname-util \
        test-process-util \
        test-terminal-util \
@@ -1448,7 +1493,8 @@ tests += \
        test-verbs \
        test-af-list \
        test-arphrd-list \
-       test-dns-domain
+       test-dns-domain \
+       test-install-root
 
 EXTRA_DIST += \
        test/a.service \
@@ -1457,7 +1503,7 @@ EXTRA_DIST += \
        test/c.service \
        test/daughter.service \
        test/d.service \
-       test/end.service.in \
+       test/end.service \
        test/e.service \
        test/f.service \
        test/grandchild.service \
@@ -1467,7 +1513,6 @@ EXTRA_DIST += \
        test/h.service \
        test/parent-deep.slice \
        test/parent.slice \
-       test/paths.target \
        test/sched_idle_bad.service \
        test/sched_idle_ok.service \
        test/sched_rr_bad.service \
@@ -1481,43 +1526,62 @@ EXTRA_DIST += \
        test/testsuite.target \
        test/timers.target \
        test/unstoppable.service \
-       test/path-changed.service \
-       test/path-directorynotempty.service \
-       test/path-existsglob.service \
-       test/path-exists.service \
-       test/path-makedirectory.service \
-       test/path-modified.service \
-       test/path-mycustomunit.service \
-       test/path-service.service \
-       test/path-changed.path \
-       test/path-directorynotempty.path \
-       test/path-existsglob.path \
-       test/path-exists.path \
-       test/path-makedirectory.path \
-       test/path-modified.path \
-       test/path-unit.path \
-       test/exec-environment-empty.service \
-       test/exec-environment-multiple.service \
-       test/exec-environment.service \
-       test/exec-group.service \
-       test/exec-ignoresigpipe-no.service \
-       test/exec-ignoresigpipe-yes.service \
-       test/exec-personality-x86-64.service \
-       test/exec-personality-x86.service \
-       test/exec-personality-s390.service \
-       test/exec-privatedevices-no.service \
-       test/exec-privatedevices-yes.service \
-       test/exec-privatetmp-no.service \
-       test/exec-privatetmp-yes.service \
-       test/exec-systemcallerrornumber.service \
-       test/exec-systemcallfilter-failing2.service \
-       test/exec-systemcallfilter-failing.service \
-       test/exec-systemcallfilter-not-failing2.service \
-       test/exec-systemcallfilter-not-failing.service \
-       test/exec-user.service \
-       test/exec-workingdirectory.service \
-       test/exec-umask-0177.service \
-       test/exec-umask-default.service \
+       test/test-path/paths.target \
+       test/test-path/basic.target \
+       test/test-path/sysinit.target \
+       test/test-path/path-changed.service \
+       test/test-path/path-directorynotempty.service \
+       test/test-path/path-existsglob.service \
+       test/test-path/path-exists.service \
+       test/test-path/path-makedirectory.service \
+       test/test-path/path-modified.service \
+       test/test-path/path-mycustomunit.service \
+       test/test-path/path-service.service \
+       test/test-path/path-changed.path \
+       test/test-path/path-directorynotempty.path \
+       test/test-path/path-existsglob.path \
+       test/test-path/path-exists.path \
+       test/test-path/path-makedirectory.path \
+       test/test-path/path-modified.path \
+       test/test-path/path-unit.path \
+       test/test-execute/exec-environment-empty.service \
+       test/test-execute/exec-environment-multiple.service \
+       test/test-execute/exec-environment.service \
+       test/test-execute/exec-passenvironment-absent.service \
+       test/test-execute/exec-passenvironment-empty.service \
+       test/test-execute/exec-passenvironment-repeated.service \
+       test/test-execute/exec-passenvironment.service \
+       test/test-execute/exec-group.service \
+       test/test-execute/exec-ignoresigpipe-no.service \
+       test/test-execute/exec-ignoresigpipe-yes.service \
+       test/test-execute/exec-personality-x86-64.service \
+       test/test-execute/exec-personality-x86.service \
+       test/test-execute/exec-personality-s390.service \
+       test/test-execute/exec-privatedevices-no.service \
+       test/test-execute/exec-privatedevices-yes.service \
+       test/test-execute/exec-privatetmp-no.service \
+       test/test-execute/exec-privatetmp-yes.service \
+       test/test-execute/exec-systemcallerrornumber.service \
+       test/test-execute/exec-systemcallfilter-failing2.service \
+       test/test-execute/exec-systemcallfilter-failing.service \
+       test/test-execute/exec-systemcallfilter-not-failing2.service \
+       test/test-execute/exec-systemcallfilter-not-failing.service \
+       test/test-execute/exec-user.service \
+       test/test-execute/exec-workingdirectory.service \
+       test/test-execute/exec-umask-0177.service \
+       test/test-execute/exec-umask-default.service \
+       test/test-execute/exec-privatenetwork-yes.service \
+       test/test-execute/exec-environmentfile.service \
+       test/test-execute/exec-oomscoreadjust-positive.service \
+       test/test-execute/exec-oomscoreadjust-negative.service \
+       test/test-execute/exec-ioschedulingclass-best-effort.service \
+       test/test-execute/exec-ioschedulingclass-idle.service \
+       test/test-execute/exec-ioschedulingclass-none.service \
+       test/test-execute/exec-ioschedulingclass-realtime.service \
+       test/test-execute/exec-capabilityboundingset-invert.service \
+       test/test-execute/exec-capabilityboundingset-merge.service \
+       test/test-execute/exec-capabilityboundingset-reset.service \
+       test/test-execute/exec-capabilityboundingset-simple.service \
        test/bus-policy/hello.conf \
        test/bus-policy/methods.conf \
        test/bus-policy/ownerships.conf \
@@ -1686,6 +1750,30 @@ test_util_SOURCES = \
 test_util_LDADD = \
        libshared.la
 
+test_string_util_SOURCES = \
+       src/test/test-string-util.c
+
+test_string_util_LDADD = \
+       libshared.la
+
+test_extract_word_SOURCES = \
+       src/test/test-extract-word.c
+
+test_extract_word_LDADD = \
+       libshared.la
+
+test_parse_util_SOURCES = \
+       src/test/test-parse-util.c
+
+test_parse_util_LDADD = \
+       libshared.la
+
+test_user_util_SOURCES = \
+       src/test/test-user-util.c
+
+test_user_util_LDADD = \
+       libshared.la
+
 test_hostname_util_SOURCES = \
        src/test/test-hostname-util.c
 
@@ -1749,6 +1837,12 @@ test_verbs_SOURCES = \
 test_verbs_LDADD = \
        libshared.la
 
+test_install_root_SOURCES = \
+       src/test/test-install-root.c
+
+test_install_root_LDADD = \
+       libshared.la
+
 test_namespace_LDADD = \
        libcore.la
 
@@ -3215,10 +3309,9 @@ libsystemd_network_la_SOURCES = \
        src/systemd/sd-dhcp-lease.h \
        src/systemd/sd-ipv4ll.h \
        src/systemd/sd-ipv4acd.h \
-       src/systemd/sd-icmp6-nd.h \
+       src/systemd/sd-ndisc.h \
        src/systemd/sd-dhcp6-client.h \
        src/systemd/sd-dhcp6-lease.h \
-       src/systemd/sd-pppoe.h \
        src/systemd/sd-lldp.h \
        src/libsystemd-network/sd-dhcp-client.c \
        src/libsystemd-network/sd-dhcp-server.c \
@@ -3234,10 +3327,11 @@ libsystemd_network_la_SOURCES = \
        src/libsystemd-network/sd-ipv4acd.c \
        src/libsystemd-network/arp-util.h \
        src/libsystemd-network/arp-util.c \
-       src/libsystemd-network/sd-pppoe.c \
        src/libsystemd-network/network-internal.c \
        src/libsystemd-network/network-internal.h \
-       src/libsystemd-network/sd-icmp6-nd.c \
+       src/libsystemd-network/sd-ndisc.c \
+       src/libsystemd-network/icmp6-util.h \
+       src/libsystemd-network/icmp6-util.c \
        src/libsystemd-network/sd-dhcp6-client.c \
        src/libsystemd-network/dhcp6-internal.h \
        src/libsystemd-network/dhcp6-protocol.h \
@@ -3313,23 +3407,15 @@ test_acd_LDADD = \
        libsystemd-network.la \
        libshared.la
 
-test_pppoe_SOURCES = \
-       src/systemd/sd-pppoe.h \
-       src/libsystemd-network/test-pppoe.c
-
-test_pppoe_LDADD = \
-       libsystemd-network.la \
-       libshared.la
-
-test_icmp6_rs_SOURCES = \
+test_ndisc_rs_SOURCES = \
        src/systemd/sd-dhcp6-client.h \
-       src/systemd/sd-icmp6-nd.h \
-       src/libsystemd-network/dhcp6-internal.h \
-       src/libsystemd-network/test-icmp6-rs.c \
+       src/systemd/sd-ndisc.h \
+       src/libsystemd-network/icmp6-util.h \
+       src/libsystemd-network/test-ndisc-rs.c \
        src/libsystemd-network/dhcp-identifier.h \
        src/libsystemd-network/dhcp-identifier.c
 
-test_icmp6_rs_LDADD = \
+test_ndisc_rs_LDADD = \
        libsystemd-network.la \
        libudev.la \
        libshared.la
@@ -3361,13 +3447,10 @@ tests += \
        test-dhcp-client \
        test-dhcp-server \
        test-ipv4ll \
-       test-icmp6-rs \
+       test-ndisc-rs \
        test-dhcp6-client \
        test-lldp
 
-manual_tests += \
-       test-pppoe
-
 # ------------------------------------------------------------------------------
 include_HEADERS += \
        src/libudev/libudev.h
@@ -3483,7 +3566,7 @@ noinst_LTLIBRARIES += \
 
 src/udev/keyboard-keys-list.txt:
        $(AM_V_at)$(MKDIR_P) $(dir $@)
-       $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@
+       $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9K]/ { if ($$2 != "KEY_MAX") { print $$2 } }' > $@
 
 src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys-list.txt
        $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print tolower(substr($$1 ,5)) ", " $$1 }' < $< > $@
@@ -3491,9 +3574,6 @@ src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys-list.txt
 src/udev/keyboard-keys-from-name.h: src/udev/keyboard-keys-from-name.gperf
        $(AM_V_GPERF)$(GPERF) -L ANSI-C -t -N keyboard_lookup_key -H hash_key_name -p -C < $< > $@
 
-src/udev/keyboard-keys-to-name.h: src/udev/keyboard-keys-list.txt
-       $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@
-
 gperf_txt_sources += \
        src/udev/keyboard-keys-list.txt
 
@@ -3520,7 +3600,6 @@ libudev_core_la_SOURCES = \
 
 nodist_libudev_core_la_SOURCES = \
        src/udev/keyboard-keys-from-name.h \
-       src/udev/keyboard-keys-to-name.h \
        src/udev/net/link-config-gperf.c
 
 gperf_gperf_sources += \
@@ -3831,6 +3910,7 @@ endif
 if HAVE_GNUTLS
 systemd_journal_remote_LDADD += \
        $(GNUTLS_LIBS)
+endif
 
 # systemd-journal-remote make sense mostly with full crypto stack
 dist_systemunit_DATA += \
@@ -3845,7 +3925,6 @@ journal-remote-install-hook: journal-install-hook
        -chmod 755 $(DESTDIR)/var/log/journal/remote
 
 INSTALL_EXEC_HOOKS += journal-remote-install-hook
-endif
 
 nodist_pkgsysconf_DATA += \
        src/journal-remote/journal-remote.conf
@@ -4184,6 +4263,7 @@ dist_catalog_DATA = \
        catalog/systemd.pl.catalog \
        catalog/systemd.pt_BR.catalog \
        catalog/systemd.ru.catalog \
+       catalog/systemd.zh_CN.catalog \
        catalog/systemd.zh_TW.catalog \
        catalog/systemd.catalog
 
@@ -5148,7 +5228,8 @@ libnss_resolve_la_LDFLAGS = \
        -Wl,--version-script=$(top_srcdir)/src/nss-resolve/nss-resolve.sym
 
 libnss_resolve_la_LIBADD = \
-       libshared.la
+       libshared.la \
+        -ldl
 
 lib_LTLIBRARIES += \
        libnss_resolve.la
@@ -5234,6 +5315,7 @@ libnetworkd_core_la_SOURCES = \
        src/network/networkd-ipv4ll.c \
        src/network/networkd-dhcp4.c \
        src/network/networkd-dhcp6.c \
+       src/network/networkd-ndisc.c \
        src/network/networkd-network.h \
        src/network/networkd-network.c \
        src/network/networkd-network-bus.c \
diff --git a/NEWS b/NEWS
index 1b7dc2183d1c672eade65f5dd97e335846d07671..1e4f6f7aaa4891392ab06054cd69c6e0aaf8c144 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,161 @@
 systemd System and Service Manager
 
+CHANGES WITH 228:
+
+        * A number of properties previously only settable in unit
+          files are now also available as properties to set when
+          creating transient units programmatically via the bus, as it
+          is exposed with systemd-run's --property=
+          setting. Specifically, these are: SyslogIdentifier=,
+          SyslogLevelPrefix=, TimerSlackNSec=, OOMScoreAdjust=,
+          EnvironmentFile=, ReadWriteDirectories=,
+          ReadOnlyDirectories=, InaccessibleDirectories=,
+          ProtectSystem=, ProtectHome=, RuntimeDirectory=.
+
+        * When creating transient services via the bus API it is now
+          possible to pass in a set of file descriptors to use as
+          STDIN/STDOUT/STDERR for the invoked process.
+
+        * Wherever systemd expects a calendar timestamp specification
+          (like in journalctl's --since= and --until= switches) UTC
+          timestamps are now supported. Timestamps suffixed with "UTC"
+          are now considered to be in Universal Time Coordinated
+          instead of the local timezone. Also, timestamps may now
+          optionally be specified with a sub-second accuracy. Both of
+          these additions also apply to recurring calendar event
+          specification, such as OnCalendar= in timer units.
+
+        * journalctl gained a new "--sync" switch that asks the
+          journal daemon to write all so far unwritten log messages to
+          disk and sync the files, before returning.
+
+        * systemd-tmpfiles learned two new line types "q" and "Q" that
+          operate like "v", but also set up a basic btrfs quota
+          hierarchy when used on a btrfs file system with quota
+          enabled.
+
+        * systemd-detect-virt gained a new --chroot switch to detect
+          whether execution takes place in a chroot() environment.
+
+        * CPUAffinity= now takes CPU index ranges in addition to
+          individual indexes.
+
+        * The various memory-related resource limit settings (such as
+          LimitAS=) now understand the usual K, M, G, ... suffixes to
+          the base of 1024 (IEC). Similar, the time-related resource
+          limit settings understand the usual min, h, day, ...
+          suffixes now.
+
+        * systemd-nspawn gained the new --network-veth-extra= switch
+          to define additional and arbitrarily-named virtual Ethernet
+          links between the host and the container.
+
+        * A new service execution setting PassEnvironment= has been
+          added that allows importing select environment variables
+          from PID1's environment block into the environment block of
+          the service.
+
+        * systemd will now bump the net.unix.max_dgram_qlen to 512 by
+          default now (the kernel default is 16). This is beneficial
+          for avoiding blocking on AF_UNIX/SOCK_DGRAM sockets since it
+          allows substantially larger numbers of queued
+          datagrams. This should increase the capability of systemd to
+          parallelize boot-up, as logging and sd_notify() are unlikely
+          to stall execution anymore. If you need to change the value
+          from the new defaults, use the usual sysctl.d/ snippets.
+
+        * The compression framing format used by the journal or
+          coredump processing has changed to be in line with what the
+          official LZ4 tools generate. LZ4 compression support in
+          systemd was considered unsupported previously, as the format
+          was not compatible with the normal tools. With this release
+          this has changed now, and it is hence safe for downstream
+          distributions to turn it on. While not compressing as well
+          as the XZ,LZ4 is substantially faster, which makes
+          it a good default choice for the compression logic in the
+          journal and in coredump handling.
+
+        * Any reference to /etc/mtab has been dropped from
+          systemd. The file has been obsolete since a while, but
+          systemd refused to work on systems where it was incorrectly
+          set up (it should be a symlink or non-existant). Please make
+          sure to update to util-linux 2.27.1 or newer in conjunction
+          with this systemd release, which also drops any reference to
+          /etc/mtab. If you maintain a distribution make sure that no
+          software you package still references it, as this is a
+          likely source of bugs. There's also a glibc bug pending,
+          asking for removal of any reference to this obsolete file:
+
+          https://sourceware.org/bugzilla/show_bug.cgi?id=19108
+
+        * 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.
+
+        * The dependency types RequiresOverridable= and
+          RequisiteOverridable= have been removed from systemd. They
+          have been used only very sparingly to our knowledge and
+          other options that provide a similar effect (such as
+          systemctl --mode=ignore-dependencies) are much more useful
+          and commonly used. Moreover, they were only half-way
+          implemented as the option to control behaviour regarding
+          these dependencies was never added to systemctl. By removing
+          these dependency types the execution engine becomes a bit
+          simpler. Unit files that use these dependencies should be
+          changed to use the non-Overridable dependency types
+          instead. In fact, when parsing unit files with these
+          options, that's what systemd will automatically convert them
+          too, but it will also warn, asking users to fix the unit
+          files accordingly. Removal of these dependency types should
+          only affect a negligible number of unit files in the wild.
+
+        * Behaviour of networkd's IPForward= option changed
+          (again). It will no longer maintain a per-interface setting,
+          but propagate one way from interfaces where this is enabled
+          to the global kernel setting. The global setting will be
+          enabled when requested by a network that is set up, but
+          never be disabled again. This change was made to make sure
+          IPv4 and IPv6 behaviour regarding packet forwarding is
+          similar (as the Linux IPv6 stack does not support
+          per-interface control of this setting) and to minimize
+          surprises.
+
+        * In unit files the behaviour of %u, %U, %h, %s has
+          changed. These specifiers will now unconditionally resolve
+          to the various user database fields of the user that the
+          systemd instance is running as, instead of the user
+          configured in the specific unit via User=. Note that this
+          effectively doesn't change much, as resolving of these
+          specifiers was already turned off in the --system instance
+          of systemd, as we cannot do NSS lookups from PID 1. In the
+          --user instance of systemd these specifiers where correctly
+          resolved, but hardly made any sense, since the user instance
+          lacks privileges to do user switches anyway, and User= is
+          hence useless. Morever, even in the --user instance of
+          systemd behaviour was awkward as it would only take settings
+          from User= assignment placed before the specifier into
+          account. In order to unify and simplify the logic around
+          this the specifiers will now always resolve to the
+          credentials of the user invoking the manager (which in case
+          of PID 1 is the root user).
+
+        Contributions from: Andrew Jones, Beniamino Galvani, Boyuan
+        Yang, Daniel Machon, Daniel Mack, David Herrmann, David
+        Reynolds, David Strauss, Dongsu Park, Evgeny Vereshchagin,
+        Filipe Brandenburger, Franck Bui, Hristo Venev, Iago López
+        Galeiras, Jan Engelhardt, Jan Janssen, Jan Synacek, Jesus
+        Ornelas Aguayo, Karel Zak, kayrus, Kay Sievers, Lennart
+        Poettering, Mantas Mikulėnas, Marcel Holtmann, Marcin Bachry,
+        Marcos Alano, Marcos Mello, Mark Theunissen, Martin Pitt,
+        Michael Marineau, Michael Olbrich, Michal Schmidt, Michal
+        Sekletar, Mirco Tischler, Nick Owens, Nicolas Cornu, Patrik
+        Flykt, Peter Hutterer, reverendhomer, Ronny Chevalier,
+        Sangjung Woo, Seong-ho Cho, Shawn Landden, Susant Sahani,
+        Thomas Haller, Thomas Hindoe Paaboel Andersen, Tom Gundersen,
+        Torstein Husebø, Vito Caputo, Zbigniew Jędrzejewski-Szmek
+
+        -- Berlin, 2015-11-XX
+
 CHANGES WITH 227:
 
         * systemd now depends on util-linux v2.27. More specifically,
@@ -117,7 +273,7 @@ CHANGES WITH 227:
 
         * File descriptors passed during socket activation may now be
           named. A new API sd_listen_fds_with_names() is added to
-          access the names.  The default names may be overriden,
+          access the names.  The default names may be overridden,
           either in the .socket file using the FileDescriptorName=
           parameter, or by passing FDNAME= when storing the file
           descriptors using sd_notify().
@@ -1156,7 +1312,7 @@ CHANGES WITH 218:
           another unit listed in its Also= setting might be.
 
         * Similar to the various existing ConditionXYZ= settings for
-          units there are now matching AssertXYZ= settings. While
+          units, there are now matching AssertXYZ= settings. While
           failing conditions cause a unit to be skipped, but its job
           to succeed, failing assertions declared like this will cause
           a unit start operation and its job to fail.
@@ -1164,7 +1320,7 @@ CHANGES WITH 218:
         * hostnamed now knows a new chassis type "embedded".
 
         * systemctl gained a new "edit" command. When used on a unit
-          file this allows extending unit files with .d/ drop-in
+          file, this allows extending unit files with .d/ drop-in
           configuration snippets or editing the full file (after
           copying it from /usr/lib to /etc). This will invoke the
           user's editor (as configured with $EDITOR), and reload the
@@ -1188,7 +1344,7 @@ CHANGES WITH 218:
           inhibitors.
 
         * Scope and service units gained a new "Delegate" boolean
-          property, which when set allows processes running inside the
+          property, which, when set, allows processes running inside the
           unit to further partition resources. This is primarily
           useful for systemd user instances as well as container
           managers.
@@ -1198,7 +1354,7 @@ CHANGES WITH 218:
           audit fields are split up and fully indexed. This means that
           journalctl in many ways is now a (nicer!) alternative to
           ausearch, the traditional audit client. Note that this
-          implements only a minimal audit client, if you want the
+          implements only a minimal audit client. If you want the
           special audit modes like reboot-on-log-overflow, please use
           the traditional auditd instead, which can be used in
           parallel to journald.
@@ -1209,7 +1365,7 @@ CHANGES WITH 218:
 
         * journalctl gained two new commands --vacuum-size= and
           --vacuum-time= to delete old journal files until the
-          remaining ones take up no more the specified size on disk,
+          remaining ones take up no more than the specified size on disk,
           or are not older than the specified time.
 
         * A new, native PPPoE library has been added to sd-network,
@@ -1262,9 +1418,9 @@ CHANGES WITH 218:
           will spew out warnings if the compilation fails. This
           requires libxkbcommon to be installed.
 
-        * When a coredump is collected a larger number of metadata
+        * When a coredump is collected, a larger number of metadata
           fields is now collected and included in the journal records
-          created for it. More specifically control group membership,
+          created for it. More specifically, control group membership,
           environment variables, memory maps, working directory,
           chroot directory, /proc/$PID/status, and a list of open file
           descriptors is now stored in the log entry.
@@ -1303,7 +1459,7 @@ CHANGES WITH 218:
           a fixed machine ID for subsequent boots.
 
         * networkd's .netdev files now provide a large set of
-          configuration parameters for VXLAN devices. Similar, the
+          configuration parameters for VXLAN devices. Similarly, the
           bridge port cost parameter is now configurable in .network
           files. There's also new support for configuring IP source
           routing. networkd .link files gained support for a new
@@ -1636,7 +1792,7 @@ CHANGES WITH 216:
 
         * .socket units gained a new DeferAcceptSec= setting that
           controls the kernels' TCP_DEFER_ACCEPT sockopt for
-          TCP. Similar, support for controlling TCP keep-alive
+          TCP. Similarly, support for controlling TCP keep-alive
           settings has been added (KeepAliveTimeSec=,
           KeepAliveIntervalSec=, KeepAliveProbes=). Also, support for
           turning off Nagle's algorithm on TCP has been added
@@ -1852,7 +2008,7 @@ CHANGES WITH 215:
         * tmpfiles learnt a new "L+" directive which creates a symlink
           but (unlike "L") deletes a pre-existing file first, should
           it already exist and not already be the correct
-          symlink. Similar, "b+", "c+" and "p+" directives have been
+          symlink. Similarly, "b+", "c+" and "p+" directives have been
           added as well, which create block and character devices, as
           well as fifos in the filesystem, possibly removing any
           pre-existing files of different types.
@@ -1934,8 +2090,8 @@ CHANGES WITH 215:
           open_by_handle_at() is now prohibited for containers,
           closing a hole similar to a recently discussed vulnerability
           in docker regarding access to files on file hierarchies the
-          container should normally not have access to. Note that for
-          nspawn we generally make no security claims anyway (and
+          container should normally not have access to. Note that, for
+          nspawn, we generally make no security claims anyway (and
           this is explicitly documented in the man page), so this is
           just a fix for one of the most obvious problems.
 
@@ -2035,14 +2191,14 @@ CHANGES WITH 214:
           CAP_NET_BROADCAST, CAP_NET_RAW capabilities though, but
           loses the ability to write to files owned by root this way.
 
-        * Similar, systemd-resolved now runs under its own
+        * Similarly, systemd-resolved now runs under its own
           "systemd-resolve" user with no capabilities remaining.
 
-        * Similar, systemd-bus-proxyd now runs under its own
+        * Similarly, systemd-bus-proxyd now runs under its own
           "systemd-bus-proxy" user with only CAP_IPC_OWNER remaining.
 
         * systemd-networkd gained support for setting up "veth"
-          virtual ethernet devices for container connectivity, as well
+          virtual Ethernet devices for container connectivity, as well
           as GRE and VTI tunnels.
 
         * systemd-networkd will no longer automatically attempt to
@@ -2744,7 +2900,7 @@ CHANGES WITH 209:
         * The configuration of network interface naming rules for
           "permanent interface names" has changed: a new NamePolicy=
           setting in the [Link] section of .link files determines the
-          priority of possible naming schemes (onboard, slot, mac,
+          priority of possible naming schemes (onboard, slot, MAC,
           path). The default value of this setting is determined by
           /usr/lib/net/links/99-default.link. Old
           80-net-name-slot.rules udev configuration file has been
@@ -4274,8 +4430,8 @@ CHANGES WITH 197:
           devices as seat masters, i.e. as devices that are required
           to be existing before a seat is considered preset. Instead,
           it will now look for all devices that are tagged as
-          "seat-master" in udev. By default framebuffer devices will
-          be marked as such, but depending on local systems other
+          "seat-master" in udev. By default, framebuffer devices will
+          be marked as such, but depending on local systems, other
           devices might be marked as well. This may be used to
           integrate graphics cards using closed source drivers (such
           as NVidia ones) more nicely into logind. Note however, that
@@ -5315,7 +5471,7 @@ CHANGES WITH 44:
 
         * Reorder configuration file lookup order. /etc now always
           overrides /run in order to allow the administrator to always
-          and unconditionally override vendor supplied or
+          and unconditionally override vendor-supplied or
           automatically generated data.
 
         * The various user visible bits of the journal now have man
diff --git a/README b/README
index f6fb966b26d4d54841857f9c3688dbea61dc8a94..bc7068a66da294cd150d5e02cdcc971a6a9284ea 100644 (file)
--- a/README
+++ b/README
@@ -122,7 +122,7 @@ REQUIREMENTS:
 
         glibc >= 2.16
         libcap
-        libmount >= 2.27 (from util-linux)
+        libmount >= 2.27.1 (from util-linux)
         libseccomp >= 1.0.0 (optional)
         libblkid >= 2.24 (from util-linux) (optional)
         libkmod >= 15 (optional)
@@ -144,7 +144,7 @@ REQUIREMENTS:
         During runtime, you need the following additional
         dependencies:
 
-        util-linux >= v2.27 required
+        util-linux >= v2.27.1 required
         dbus >= 1.4.0 (strictly speaking optional, but recommended)
         dracut (optional)
         PolicyKit (optional)
diff --git a/TODO b/TODO
index d399ae9477b1eb3e6843b0e159fdb0ffa12cfa90..f32e53f7e9fb712688c8dcf4440fd81787418ac9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -21,12 +21,32 @@ External:
 
 * wiki: update journal format documentation for lz4 additions
 
-* When lz4 gets an API for lz4 command output, make use of it to
-  compress coredumps in a way compatible with /usr/bin/lz4.
+Janitorial Clean-ups:
+
+* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead
+
+* replace manual readdir() loops with FOREACH_DIRENT or FOREACH_DIRENT_ALL
+
+* Get rid of the last strerror() invocations in favour of %m and strerror_r()
+
+* Rearrange tests so that the various test-xyz.c match a specific src/basic/xyz.c again
 
 Features:
 
-* when creating transient services, support passing in a tty fd to use for stdin/stdout
+* 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
+  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.
+
+* do something about "/control" subcgroups in the unified cgroup hierarchy
+
+* when we detect that there are waiting jobs but no running jobs, do something
+
+* push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy)
 
 * add a concept of RemainAfterExit= to scope units
 
@@ -53,18 +73,11 @@ Features:
   prefixed with /sys generally special.
   http://lists.freedesktop.org/archives/systemd-devel/2015-June/032962.html
 
-* Add PassEnvironment= setting to service units, to import select env vars from PID 1 into the service env block
-
 * nspawn: fix logic always print a final newline on output.
   https://github.com/systemd/systemd/pull/272#issuecomment-113153176
 
-* make nspawn's --network-veth switch more powerful:
-  http://lists.freedesktop.org/archives/systemd-devel/2015-June/033121.html
-
 * man: document that unless you use StandardError=null the shell >/dev/stderr won't work in shell scripts in services
 
-* man: clarify that "machinectl show" shows different information than "machinectl status" (no cgroup tree, no IP addresses, ...)
-
 * "systemctl daemon-reload" should result in /etc/systemd/system.conf being reloaded by systemd
 
 * install: include generator dirs in unit file search paths
@@ -134,9 +147,6 @@ Features:
 
 * .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC
 
-* create a btrfs qgroup for /var/lib/machines, and add all container
-  subvolumes we create to it.
-
 * When logging about multiple units (stopping BoundTo units, conflicts, etc.),
   log both units as UNIT=, so that journalctl -u triggers on both.
 
@@ -176,14 +186,12 @@ Features:
 * networkd/udev: implement SR_IOV configuration in .link files:
   http://lists.freedesktop.org/archives/systemd-devel/2015-January/027451.html
 
-* When RLIMIT_NPROC is set from a unit file it currently always is set
-  for root, not for the user set in User=, which makes it
-  useless. After fixing this, set RLIMIT_NPROC for
-  systemd-journal-xyz, and all other of our services that run under
-  their own user ids, and use User= (but only in a world where userns
-  is ubiquitous since otherwise we cannot invoke those daemons on the
-  host AND in a container anymore). Also, if LimitNPROC= is used
-  without User= we should warn and refuse operation.
+* Set RLIMIT_NPROC for systemd-journal-xyz, and all other of our
+  services that run under their own user ids, and use User= (but only
+  in a world where userns is ubiquitous since otherwise we cannot
+  invoke those daemons on the host AND in a container anymore). Also,
+  if LimitNPROC= is used without User= we should warn and refuse
+  operation.
 
 * logind: maybe allow configuration of the StopTimeout for session scopes
 
@@ -222,8 +230,6 @@ Features:
 * Find a solution for SMACK capabilities stuff:
   http://lists.freedesktop.org/archives/systemd-devel/2014-December/026188.html
 
-* port libmount hookup to use API's own inotify interface, as soon as that is table in libmount
-
 * "systemctl preset-all" should probably order the unit files it
   operates on lexicographically before starting to work, in order to
   ensure deterministic behaviour if two unit files conflict (like DMs
@@ -265,8 +271,6 @@ Features:
 
 * maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment=
 
-* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead
-
 * introduce systemd-timesync-wait.service or so to sync on an NTP fix?
 
 * systemd --user should issue sd_notify() upon reaching basic.target, not on becoming idle
@@ -554,9 +558,6 @@ Features:
 
 * maybe do not install getty@tty1.service symlink in /etc but in /usr?
 
-* fstab: add new mount option x-systemd-after=/foobar/waldo to allow manual dependencies to other mount points
-  https://bugzilla.redhat.com/show_bug.cgi?id=812826
-
 * print a nicer explanation if people use variable/specifier expansion in ExecStart= for the first word
 
 * mount: turn dependency information from /proc/self/mountinfo into dependency information between systemd units.
@@ -599,7 +600,6 @@ Features:
   - add API to close/reopen/get fd for journal client fd in libsystemd-journal.
   - fallback to /dev/log based logging in libsystemd-journal, if we cannot log natively?
   - declare the local journal protocol stable in the wiki interface chart
-  - journal: reuse XZ context
   - sd-journal: speed up sd_journal_get_data() with transparent hash table in bg
   - journald: when dropping msgs due to ratelimit make sure to write
     "dropped %u messages" not only when we are about to print the next
@@ -653,7 +653,6 @@ Features:
   - document systemd-journal-flush.service properly
   - documentation: recommend to connect the timer units of a service to the service via Also= in [Install]
   - man: document the very specific env the shutdown drop-in tools live in
-  - man: extend runlevel(8) to mention that runlevels suck, and are dead. Maybe add runlevel(7) with a note about that too
   - man: add more examples to man pages
   - man: maybe sort directives in man pages, and take sections from --help and apply them to man too
 
@@ -668,8 +667,6 @@ Features:
   - add new command to systemctl: "systemctl system-reexec" which reexecs as many daemons as virtually possible
   - systemctl enable: fail if target to alias into does not exist? maybe show how many units are enabled afterwards?
   - systemctl: "Journal has been rotated since unit was started." message is misleading
-  - support "systemctl stop foobar@.service" to stop all units matching a certain template
-  - Something is wrong with symlink handling of "autovt@.service" in "systemctl list-unit-files"
   - better error message if you run systemctl without systemd running
   - systemctl status output should should include list of triggering units and their status
 
@@ -684,7 +681,6 @@ Features:
     o DST changes
   - Support 2012-02~4 as syntax for specifying the fourth to last day of the month.
   - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1
-  - when parsing calendar timestamps support the UTC timezone (even if we will not support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200
   - Modulate timer frequency based on battery state
 
 * add libsystemd-password or so to query passwords during boot using the password agent logic
@@ -744,8 +740,6 @@ Features:
 
 * introduce Type=pid-file
 
-* change Requires=basic.target to RequisiteOverride=basic.target
-
 * when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr
 
 * ExecOnFailure=/usr/bin/foo
@@ -764,8 +758,6 @@ Features:
 
 * add option to sockets to avoid activation. Instead just drop packets/connections, see http://cyberelk.net/tim/2012/02/15/portreserve-systemd-solution/
 
-* default unix qlen is too small (10). bump sysctl? add sockopt?
-
 * save coredump in Windows/Mozilla minidump format
 
 * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting)
@@ -874,7 +866,7 @@ Features:
    - add Scope= parsing option for [Network]
    - properly handle routerless dhcp leases
    - add more attribute support for SIT tunnel
-   - work with non-ethernet devices
+   - work with non-Ethernet devices
    - add support for more bond options
 
 * networkd-wait-online:
@@ -913,12 +905,8 @@ External:
 
 * drop accountsservice's StandardOutput=syslog and Type=dbus fields
 
-* dbus upstream still refers to dbus.target and should not
-
 * dbus: in fedora, make /var/lib/dbus/machine-id a symlink to /etc/machine-id
 
-* add "# export SYSTEMD_PAGER=" to bash login
-
 * /usr/bin/service should actually show the new command line
 
 * fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus=
@@ -951,7 +939,3 @@ Regularly:
 * use secure_getenv() instead of getenv() where appropriate
 
 * link up selected blog stories from man pages and unit files Documentation= fields
-
-Scheduled for removal or fixing:
-
-* xxxOverridable dependencies (probably: fix)
similarity index 95%
rename from systemd-master/catalog/systemd.da.catalog
rename to catalog/systemd.da.catalog
index dc3f8b552ef035b463d08b7c7829c02f640a1e82..bd4d742d8a14716e10f95a39b4496abb755b63a9 100644 (file)
-#  This file is part of systemd.\r
-#\r
-#  Copyright 2012 Lennart Poettering\r
-#\r
-#  systemd is free software; you can redistribute it and/or modify it\r
-#  under the terms of the GNU Lesser General Public License as published by\r
-#  the Free Software Foundation; either version 2.1 of the License, or\r
-#  (at your option) any later version.\r
-#\r
-#  systemd is distributed in the hope that it will be useful, but\r
-#  WITHOUT ANY WARRANTY; without even the implied warranty of\r
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-#  Lesser General Public License for more details.\r
-#\r
-#  You should have received a copy of the GNU Lesser General Public License\r
-#  along with systemd; If not, see <http://www.gnu.org/licenses/>.\r
\r
-# Message catalog for systemd's own messages\r
-# Danish translation\r
\r
-# The catalog format is documented on\r
-# http://www.freedesktop.org/wiki/Software/systemd/catalog\r
\r
-# For an explanation why we do all this, see https://xkcd.com/1024/\r
\r
--- f77379a8490b408bbe5f6940505a777b\r
-Subject: Journalen er blevet startet\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-System-journal processen har startet op, åbnet journal filerne for\r
-tilskrivning og er nu klar til at modtage anmodninger.\r
\r
--- d93fb3c9c24d451a97cea615ce59c00b\r
-Subject: Journalen er blevet stoppet\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-System-journal processen er stoppet og har lukket alle aktive journal\r
-filer.\r
\r
--- a596d6fe7bfa4994828e72309e95d61e\r
-Subject: Beskeder fra en service er blevet undertrykt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: man:journald.conf(5)\r
\r
-En service har logget for mange beskeder inden for en given tidsperiode.\r
-Beskeder fra omtalte service er blevet smidt væk.\r
\r
-Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre\r
-services er ikke påvirket.\r
\r
-Grænsen for hvornår beskeder bliver smidt væk kan konfigureres \r
-med RateLimitInterval= og RateLimitBurst= i\r
-/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.\r
\r
--- e9bf28e6e834481bb6f48f548ad13606\r
-Subject: Journal beskeder er gået tabt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Kernel beskeder er gået tabt da journal systemet ikke har været i stand\r
-til at håndtere dem hurtigt nok.\r
\r
--- fc2e22bc6ee647b6b90729ab34a250b1\r
-Subject: Fejl-fil genereret for process @COREDUMP_PID@ (@COREDUMP_COMM@)\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: man:core(5)\r
\r
-Process @COREDUMP_PID@ (@COREDUMP_COMM@) har lukket ned og genereret en\r
-fejl-fil.\r
\r
-Dette indikerer som regel en programmeringsfejl i det nedlukkede program\r
-og burde blive reporteret som en bug til folkene bag\r
\r
--- 8d45620c1a4348dbb17410da57c60c66\r
-Subject: En ny session @SESSION_ID@ er blevet lavet for bruger @USER_ID@\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat\r
\r
-En ny session med ID @SESSION_ID@ er blevet lavet for brugeren @USER_ID@.\r
\r
-Den ledende process for sessionen er @LEADER@.\r
\r
--- 3354939424b4456d9802ca8333ed424a\r
-Subject: Session @SESSION_ID@ er blevet lukket ned\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat\r
\r
-En session med ID @SESSION_ID@ er blevet lukket ned.\r
\r
--- fcbefc5da23d428093f97c82a9290f7b\r
-Subject: En ny arbejdsstation $SEAT_ID@ er nu tilgængelig\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat\r
\r
-En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig.\r
\r
--- e7852bfe46784ed0accde04bc864c2d5\r
-Subject: Arbejdsstation @SEAT_ID@ er nu blevet fjernet\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat\r
\r
-En arbejdsstation @SEAT_ID@ er blevet fjernet og er ikke længere tilgængelig.\r
\r
--- c7a787079b354eaaa9e77b371893cd27\r
-Subject: Tidsændring\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Systemtiden er blevet ændret til @REALTIME@ mikrosekunder efter d. 1. Januar 1970.\r
\r
--- 45f82f4aef7a4bbf942ce861d1f20990\r
-Subject: Tidszoneændring til @TIMEZONE@\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Tidszonen for systemet er blevet ændret til @TIMEZONE@.\r
\r
--- b07a249cd024414a82dd00cd181378ff\r
-Subject: Opstart af systemet er nu fuldført\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Alle system services i kø til at køre ved opstart, er blevet startet\r
-med success. Bemærk at dette ikke betyder at maskinen er i dvale, da\r
-services stadig kan være i gang med at færdiggøre deres opstart.\r
\r
-Opstart af kernel tog @KERNEL_USEC@ mikrosekunder.\r
\r
-Opstart af initrd tog @INITRD_USEC@ mikrosekunder.\r
\r
-Opstart af userspace tog @USERSPACE_USEC@ mikrosekunder.\r
\r
--- 6bbd95ee977941e497c48be27c254128\r
-Subject: System slumretilstand @SLEEP@ trådt i kraft\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-System er nu gået i @SLEEP@ slumretilstand.\r
\r
--- 8811e6df2a8e40f58a94cea26f8ebf14\r
-Subject: System slumretilstand @SLEEP@ forladt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Systemet har nu forladt @SLEEP@ slumretilstand.\r
\r
--- 98268866d1d54a499c4e98921d93bc40\r
-Subject: Systemnedlukning påbegyndt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Systemnedlukning er blevet påbegyndt. Nedlukningen er nu begyndt og\r
-alle system services er blevet afbrudt og alle filsystemer afmonteret.\r
\r
--- 7d4958e842da4a758f6c1cdc7b36dcc5\r
-Subject: Enhed @UNIT@ har påbegyndt opstart\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ er begyndt at starte op.\r
\r
--- 39f53479d3a045ac8e11786248231fbf\r
-Subject: Enhed @UNIT har færdiggjort opstart\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ er færdig med at starte op.\r
\r
-Resultat for opstart er @RESULT@.\r
\r
--- de5b426a63be47a7b6ac3eaac82e2f6f\r
-Subject: Enhed @UNIT@ har påbegyndt nedlukning\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ har påbegyndt nedlukning.\r
\r
--- 9d1aaa27d60140bd96365438aad20286\r
-Subject: Enhed @UNIT@ har færdiggjort nedlukning\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ har færdiggjort nedlukning.\r
\r
--- be02cf6855d2428ba40df7e9d022f03d\r
-Subject: Enhed @UNIT@ har fejlet\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ har fejlet.\r
\r
-Resultatet er @RESULT@\r
\r
--- d34d037fff1847e6ae669a370e694725\r
-Subject: Enhed @UNIT@ har påbegyndt genindlæsning af sin konfiguration\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ er begyndt at genindlæse sin konfiguration\r
\r
--- 7b05ebc668384222baa8881179cfda54\r
-Subject: Enhed @UNIT@ har færdiggjort genindlæsning af sin konfiguration\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Enhed @UNIT@ er færdig med at genindlæse sin konfiguration\r
\r
-Resultatet er: @RESULT@.\r
\r
--- 641257651c1b4ec9a8624d7a40a9e1e7\r
-Subject: Process @EXECUTABLE@ kunne ikke eksekveres\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Processen @EXECUTABLE@ kunne ikke eksekveres og fejlede.\r
\r
-Processens returnerede fejlkode er @ERRNO@.\r
\r
--- 0027229ca0644181a76c4e92458afa2e\r
-Subject: Èn eller flere beskeder kunne ikke videresendes til syslog\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Èn eller flere beskeder kunne ikke videresendes til syslog servicen\r
-der kører side-om-side med journald. Dette indikerer typisk at syslog\r
-implementationen ikke har kunnet følge med mængden af ventende beskeder.\r
\r
--- 1dee0369c7fc4736b7099b38ecb46ee7\r
-Subject: Monteringspunkt er ikke tomt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Folderen @WHERE@ er specificeret som monteringspunkt (andet felt i\r
-/etc/fstab eller Where= feltet i systemd enhedsfil) men er ikke tom.\r
-Dette forstyrrer ikke monteringen, men de pre-eksisterende filer i folderen\r
-bliver utilgængelige. For at se de over-monterede filer; montér det \r
-underlæggende filsystem til en anden lokation.\r
\r
--- 24d8d4452573402496068381a6312df2\r
-Subject: En virtuel maskine eller container er blevet startet\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet\r
-startet og er klar til brug.\r
\r
--- 58432bd3bace477cb514b56381b8a758\r
-Subject: En virtuel maskine eller container er blevet afbrudt\r
-Defined-By: systemd\r
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel\r
\r
-Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet\r
-nedlukket.\r
+#  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
+# Danish translation
+
+# The catalog format is documented on
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# For an explanation why we do all this, see https://xkcd.com/1024/
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: Journalen er blevet startet
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+System-journal processen har startet op, åbnet journal filerne for
+tilskrivning og er nu klar til at modtage anmodninger.
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: Journalen er blevet stoppet
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+System-journal processen er stoppet og har lukket alle aktive journal
+filer.
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: Beskeder fra en service er blevet undertrykt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+En service har logget for mange beskeder inden for en given tidsperiode.
+Beskeder fra omtalte service er blevet smidt væk.
+
+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
+/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: Journal beskeder er gået tabt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Kernel beskeder er gået tabt da journal systemet ikke har været i stand
+til at håndtere dem hurtigt nok.
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: Fejl-fil genereret for process @COREDUMP_PID@ (@COREDUMP_COMM@)
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+Process @COREDUMP_PID@ (@COREDUMP_COMM@) har lukket ned og genereret en
+fejl-fil.
+
+Dette indikerer som regel en programmeringsfejl i det nedlukkede program
+og burde blive reporteret som en bug til folkene bag
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: En ny session @SESSION_ID@ er blevet lavet for bruger @USER_ID@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+En ny session med ID @SESSION_ID@ er blevet lavet for brugeren @USER_ID@.
+
+Den ledende process for sessionen er @LEADER@.
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: Session @SESSION_ID@ er blevet lukket ned
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+En session med ID @SESSION_ID@ er blevet lukket ned.
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: En ny arbejdsstation $SEAT_ID@ er nu tilgængelig
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig.
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: Arbejdsstation @SEAT_ID@ er nu blevet fjernet
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+En arbejdsstation @SEAT_ID@ er blevet fjernet og er ikke længere tilgængelig.
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: Tidsændring
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Systemtiden er blevet ændret til @REALTIME@ mikrosekunder efter d. 1. Januar 1970.
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: Tidszoneændring til @TIMEZONE@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Tidszonen for systemet er blevet ændret til @TIMEZONE@.
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: Opstart af systemet er nu fuldført
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Alle system services i kø til at køre ved opstart, er blevet startet
+med success. Bemærk at dette ikke betyder at maskinen er i dvale, da
+services stadig kan være i gang med at færdiggøre deres opstart.
+
+Opstart af kernel tog @KERNEL_USEC@ mikrosekunder.
+
+Opstart af initrd tog @INITRD_USEC@ mikrosekunder.
+
+Opstart af userspace tog @USERSPACE_USEC@ mikrosekunder.
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: System slumretilstand @SLEEP@ trådt i kraft
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+System er nu gået i @SLEEP@ slumretilstand.
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: System slumretilstand @SLEEP@ forladt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Systemet har nu forladt @SLEEP@ slumretilstand.
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: Systemnedlukning påbegyndt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Systemnedlukning er blevet påbegyndt. Nedlukningen er nu begyndt og
+alle system services er blevet afbrudt og alle filsystemer afmonteret.
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: Enhed @UNIT@ har påbegyndt opstart
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ er begyndt at starte op.
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: Enhed @UNIT har færdiggjort opstart
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ er færdig med at starte op.
+
+Resultat for opstart er @RESULT@.
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: Enhed @UNIT@ har påbegyndt nedlukning
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ har påbegyndt nedlukning.
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: Enhed @UNIT@ har færdiggjort nedlukning
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ har færdiggjort nedlukning.
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: Enhed @UNIT@ har fejlet
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ har fejlet.
+
+Resultatet er @RESULT@
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: Enhed @UNIT@ har påbegyndt genindlæsning af sin konfiguration
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ er begyndt at genindlæse sin konfiguration
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: Enhed @UNIT@ har færdiggjort genindlæsning af sin konfiguration
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Enhed @UNIT@ er færdig med at genindlæse sin konfiguration
+
+Resultatet er: @RESULT@.
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: Process @EXECUTABLE@ kunne ikke eksekveres
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Processen @EXECUTABLE@ kunne ikke eksekveres og fejlede.
+
+Processens returnerede fejlkode er @ERRNO@.
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: Èn eller flere beskeder kunne ikke videresendes til syslog
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Èn eller flere beskeder kunne ikke videresendes til syslog servicen
+der kører side-om-side med journald. Dette indikerer typisk at syslog
+implementationen ikke har kunnet følge med mængden af ventende beskeder.
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: Monteringspunkt er ikke tomt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Folderen @WHERE@ er specificeret som monteringspunkt (andet felt i
+/etc/fstab eller Where= feltet i systemd enhedsfil) men er ikke tom.
+Dette forstyrrer ikke monteringen, men de pre-eksisterende filer i folderen
+bliver utilgængelige. For at se de over-monterede filer; montér det
+underlæggende filsystem til en anden lokation.
+
+-- 24d8d4452573402496068381a6312df2
+Subject: En virtuel maskine eller container er blevet startet
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet
+startet og er klar til brug.
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: En virtuel maskine eller container er blevet afbrudt
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet
+nedlukket.
diff --git a/catalog/systemd.ko.catalog b/catalog/systemd.ko.catalog
new file mode 100644 (file)
index 0000000..3c3535a
--- /dev/null
@@ -0,0 +1,264 @@
+#  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
+# Korean translation
+
+# The catalog format is documented on
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# For an explanation why we do all this, see https://xkcd.com/1024/
+#
+# Translator :
+#     Seong-ho Cho <darkcircle.0426@gmail.com>, 2015.
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: 저널 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+시스템 저널 프로세스를 시작했고 기록목적으로 저널 파일을 열었으며,
+프로세스 요청을 기다리고 있습니다.
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: 저널 멈춤
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+시스템 저널 프로세스를 껐고 현재 활성화 중인 저널 파일을 모두
+닫았습니다.
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: 서비스의 메시지를 거절함
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+일정 시간동안 서비스에서 너무 많은 메시지를 기록했습니다.
+서비스에서 오는 메시지를 거절했습니다.
+
+의문점이 있는 서비스로부터 오는 메시지만 거절했음을 참고하십시오
+다른 서비스의 메시지에는 영향을 주지 않습니다.
+
+메시지 거절 제어 제한 값은 /etc/systemd/journald.conf 의
+RateLimitInterval= 변수와 RateLimitBurst= 변수로 설정합니다.
+자세한 내용은 ournald.conf(5)를 살펴보십시오.
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: 저널 메시지 놓침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+저널 시스템에서 커널 메시지를 충분히 빠르게 처리할 수 없어 커널
+ 메시지를 잃었습니다.
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: 프로세스 @COREDUMP_PID@번 코어 덤프(@COREDUMP_COMM@) 생성함
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+프로세스 @COREDUMP_PID@번 (@COREDUMP_COMM@)이 비정상적으로 끝나
+코어 덤프를 생성했습니다.
+
+보통 비정상 종료 관리 프로그램에서 프로그래밍 오류를 나타내며,
+제작자에게 버그로 보고해야합니다.
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: @USER_ID@ 사용자의 새 @SESSION_ID@ 세션 만듦
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+@USER_ID@ 사용자의 새 @SESSION_ID@ 세션을 만들었습니다.
+
+이 세션의 관리 프로세스는 @LEADER@ 입니다.
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: @SESSION_ID@ 세션 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+@SESSION_ID@ 세션을 끝냈습니다.
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: 새 @SEAT_ID@ 시트 사용할 수 있음
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+새 @SEAT_ID@ 시트를 설정했고 사용할 수 있습니다.
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: @SEAT_ID@ 시트 제거함
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+@SEAT_ID@ 시트를 제거했으며 더이상 사용할 수 없습니다.
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: 시간 바꿈
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+시스템 시계를 1970년 1월 1일 이후로 @REALTIME@ 마이크로초 지난 값으로
+설정했습니다.
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: @TIMEZONE@ 시간대로 시간대 바꿈
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+시스템 시간대를 @TIMEZONE@ 시간대로 바꾸었습니다.
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: 시스템 시동 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+부팅 과정에 시작하려고 준비한 모든 시스템 서비스를 성공적으로
+ 시작했습니다. 머신이 서비스처럼 대기중이라는 의미는 아니며
+지동을 완전히 마칠 때까지 사용중일 수도 있는 점 참고하십시오.
+
+커널 시동에 @KERNEL_USEC@ 마이크로초가 걸립니다.
+
+초기 램 디스크 시동에 @INITRD_USEC@ 마이크로초가 걸립니다.
+
+사용자 영역 시동에 @USERSPACE_USEC@ 마이크로초가 걸립니다.
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: @SLEEP@ 대기 상태 진입
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@SLEEP@ 대기 상태로 진입했습니다.
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: @SLEEP@ 대기 상태 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@SLEEP@ 대기 상태를 마쳤습니다.
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: 컴퓨터 끄기 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+컴퓨터 끄기 동작을 시작했습니다. 모든 시스템 동작을 멈추고
+모든 파일 시스템의 마운트를 해제합니다.
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: @UNIT@ 유닛 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛을 시작했습니다.
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: @UNIT@ 유닛 시동 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛 시동을 마쳤습니다.
+
+시동 결과는 @RESULT@ 입니다.
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: @UNIT@ 유닛 끝내기 동작 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛 끝내기 동작을 시작했습니다.
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: @UNIT@ 유닛 끝내기 동작 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛 끝내기 동작을 마쳤습니다.
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: @UNIT@ 유닛 동작 실패
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛 동작에 실패했습니다.
+
+결과는 @RESULT@ 입니다.
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: @UNIT@ 유닛 설정 다시 읽기 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛의 설정 다시 읽기를 시작했습니다
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: @UNIT@ 유닛 설정 다시 읽기 완료
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 유닛의 설정 다시 읽기 동작을 끝냈습니다.
+
+결과는 @RESULT@ 입니다.
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: @EXECUTABLE@ 프로세스 시작할 수 없음
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@EXECUTABLE@ 프로세스를 시작할 수 없어 실행에 실패했습니다.
+
+이 프로세스에서 반환한 오류 번호는 @ERRNO@번 입니다.
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: 하나 이상의 메시지를 syslog에 전달할 수 없음
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+journald 서비스와 동시에 실행중인 syslog 서비스에 하나 이상의 메시지를
+전달할 수 없습니다. 보통 순차적으로 오는 메시지의 속도를 syslog 구현체가
+따라가지 못함을 의미합니다.
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: 마운트 지점 비어있지 않음
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@WHERE@ 디렉터리를 마운트 지점으로 지정했으며 (/etc/fstab 파일의
+ 두번째 필드 또는 systemd 유닛 파일의 Where= 필드) 비어있지 않습니다.
+마운트 과정에 방해가 되진 않지만 이전에 이 디렉터리에 존재하는 파일에
+ 접근할 수 없게 됩니다. 중복으로 마운트한 파일을 보려면, 근본 파일
+시스템의 다음 위치에 직접 마운트하십시오.
+
+-- 24d8d4452573402496068381a6312df2
+Subject: 가상 머신 또는 컨테이너 시작
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@LEADER@ 프로세스 ID로 동작하는 @NAME@ 가상 머신을 시작했으며,
+이제부터 사용할 수 있습니다.
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: 가상 머신 또는 컨테이너 마침
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@LEADER@ 프로세스 ID로 동작하는 @NAME@ 가상 머신을 껐습니다.
diff --git a/catalog/systemd.zh_CN.catalog b/catalog/systemd.zh_CN.catalog
new file mode 100644 (file)
index 0000000..3863910
--- /dev/null
@@ -0,0 +1,253 @@
+#  This file is part of systemd.
+#
+#  Copyright 2012 Lennart Poettering
+#  Copyright 2015 Boyuan Yang
+#
+#  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
+# Simplified Chinese translation
+
+# 本 catalog 文档格式被记载在
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# 如需了解我们为什么做这些工作,请见 https://xkcd.com/1024/
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: 日志已开始
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统日志进程已启动,已打开供写入的日志文件并准备好处理请求。
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: 日志已停止
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统日志进程已终止,并已关闭所有当前活动的日志文件。
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: 由某个服务而来的消息已被抑制
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+某个服务在一个时间周期内记录了太多消息。
+从该服务而来的消息已被丢弃。
+
+请注意只有由有问题的服务传来的消息被丢弃,
+其它服务的消息不受影响。
+
+可以在 /etc/systemd/journald.conf 中设定 RateLimitInterval=
+以及 RateLimitBurst = 的值以控制丢弃信息的限制。
+请参见 journald.conf(5) 以了解详情。
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: 日志消息已遗失
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+因日志系统对内核消息的处理速度不够快,
+部分信息已经遗失。
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: 进程 @COREDUMP_PID@ (@COREDUMP_COMM@) 核心已转储
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+进程 @COREDUMP_PID@ (@COREDUMP_COMM@) 已崩溃并进行核心转储。
+
+这通常意味着崩溃程序中存在编程错误,并应当将此错误向其开发者报告。
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: 一个新会话 @SESSION_ID@ 已为用户 @USER_ID@ 建立
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+一个 ID 为 @SESSION_ID@ 的新会话已为用户 @USER_ID@ 建立。
+
+该会话的首进程为 @LEADER@。
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: 会话 @SESSION_ID@ 已终止
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+一个 ID 为 @SESSION_ID@ 的会话已终止。
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: 一个新的座位 @SEAT_ID@ 可用
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+一个新的座位 @SEAT_ID@ 已被配置并已可用。
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: 座位 @SEAT_ID@ 已被移除
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+座位 @SEAT_ID@ 已被移除并不再可用。
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: 时间已变更
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统时钟已变更为1970年1月1日后 @REALTIME@ 微秒。
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: 时区变更为 @TIMEZONE@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统时区已变更为 @TIMEZONE@。
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: 系统启动已完成
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+所有系统启动时需要的系统服务均已成功启动。
+请注意这并不代表现在机器已经空闲,因为某些服务可能仍处于完成启动的过程中。
+
+内核启动使用了 @KERNEL_USEC@ 毫秒。
+
+初始内存盘启动使用了 @INITRD_USEC@ 毫秒。
+
+用户空间启动使用了 @USERSPACE_USEC@ 毫秒。
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: 系统已进入 @SLEEP@ 睡眠状态
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-deve
+
+系统现已进入 @SLEEP@ 睡眠状态。
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: 系统已离开 @SLEEP@ 睡眠状态
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统现已离开 @SLEEP@ 睡眠状态。
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: 系统关机已开始
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+系统关机操作已初始化。
+关机已开始,所有系统服务均已结束,所有文件系统已卸载。
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: @UNIT@ 单元已开始启动
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已开始启动。
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: @UNIT@ 单元已结束启动
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已结束启动。
+
+启动结果为“@RESULT@”。
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: @UNIT@ 单元已开始停止操作
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已开始停止操作。
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: @UNIT@ 单元已结束停止操作
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已结束停止操作。
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: @UNIT@ 单元已失败
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已失败。
+
+结果为“@RESULT@”。
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: @UNIT@ 单元已开始重新载入其配置
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已开始重新载入其配置。
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: @UNIT@ 单元已结束配置重载入
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@UNIT@ 单元已结束配置重载入操作。
+
+结果为“@RESULT@”。
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: 进程 @EXECUTABLE@ 无法执行
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+进程 @EXECUTABLE@ 无法被执行并已失败。
+
+该进程返回的错误代码为 @ERRNO@。
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: 一个或更多消息无法被转发至 syslog
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+有一条或更多的消息无法被转发至与 journald 同时运行的 syslog 服务。
+这通常意味着 syslog 实现无法跟上队列中消息进入的速度。
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: 挂载点不为空
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+目录 @WHERE@ 被指定为挂载点(即 /etc/fstab 文件的第二栏,或 systemd 单元
+文件的 Where= 字段),且该目录非空。
+这并不会影响挂载行为,但该目录中先前已存在的文件将无法被访问。
+如需查看这些文件,请手动将其下的文件系统挂载到另一个位置。
+
+-- 24d8d4452573402496068381a6312df2
+Subject: 一个虚拟机或容器已启动
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+虚拟机 @NAME@,以及其首进程 PID @LEADER@,已被启动并可被使用。
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: 一个虚拟机或容器已被终止
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+虚拟机 @NAME@,以及其首进程 PID @LEADER@,已被关闭并停止。
index 45f2b6e9d504ce1543435d43eae437ccdad5630c..ed74c0a98af0eb27b1f624073bb39eb58ccfc6a8 100644 (file)
@@ -1,48 +1,32 @@
 @@
-identifier r;
+identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$";
+local idexpression r;
 expression e;
 @@
 - r = -e;
-- log_error_errno(e,
-+ r = log_error_errno(e,
-  ...);
++ r =
+  log_LEVEL_errno(e, ...);
 @@
-identifier r;
+identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$";
+local idexpression r;
 expression e;
 @@
-- log_error_errno(e,
-+ r = log_error_errno(e,
-  ...);
++ r =
+  log_LEVEL_errno(e, ...);
 - r = -e;
 @@
-identifier r;
+identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$";
+local idexpression r;
 expression e;
 @@
-- r = log_error_errno(e,
-+ return log_error_errno(e,
-  ...);
+- r =
++ return
+  log_LEVEL_errno(e, ...);
 - return r;
 @@
-identifier r;
+identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$";
 expression e;
 @@
-- r = -e;
-- log_warning_errno(e,
-+ r = log_warning_errno(e,
-  ...);
-@@
-identifier r;
-expression e;
-@@
-- log_warning_errno(e,
-+ r = log_warning_errno(e,
-  ...);
-- r = -e;
-@@
-identifier r;
-expression e;
-@@
-- r = log_warning_errno(e,
-+ return log_warning_errno(e,
-  ...);
-- return r;
++ return
+  log_LEVEL_errno(e, ...);
+- return -e;
index 5e3cdd6d2bfd57ff844b710d54ad8c69d2f8a48b..c96b9fb1d9fe47b3a6926a282036b35d6b408de2 100644 (file)
@@ -93,7 +93,6 @@ AC_PROG_GREP
 AC_PROG_AWK
 
 AC_PATH_PROG([M4], [m4])
-AC_PATH_PROG([XSLTPROC], [xsltproc])
 
 AC_PATH_PROG([QUOTAON], [quotaon], [/usr/sbin/quotaon], [$PATH:/usr/sbin:/sbin])
 AC_PATH_PROG([QUOTACHECK], [quotacheck], [/usr/sbin/quotacheck], [$PATH:/usr/sbin:/sbin])
@@ -282,7 +281,6 @@ AM_CONDITIONAL([HAVE_PYTHON], [test "x$have_python" = "xyes"])
 
 # ------------------------------------------------------------------------------
 
-AC_SEARCH_LIBS([dlsym], [dl], [], [AC_MSG_ERROR([*** Dynamic linking loader library not found])])
 AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])])
 AC_CHECK_HEADERS([linux/btrfs.h], [], [])
 AC_CHECK_HEADERS([linux/memfd.h], [], [])
@@ -294,6 +292,7 @@ save_LIBS="$LIBS"
 LIBS=
 AC_SEARCH_LIBS([cap_init], [cap], [], [AC_MSG_ERROR([*** POSIX caps library not found])])
 CAP_LIBS="$LIBS"
+LIBS="$save_LIBS"
 AC_SUBST(CAP_LIBS)
 
 AC_CHECK_FUNCS([memfd_create])
@@ -531,25 +530,27 @@ AC_SUBST(CERTIFICATEROOT)
 # ------------------------------------------------------------------------------
 have_xz=no
 AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
-if test "x$enable_xz" != "xno"; then
+AS_IF([test "x$enable_xz" != "xno"], [
         PKG_CHECK_MODULES(XZ, [ liblzma ],
-                [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available]) have_xz=yes], have_xz=no)
-        if test "x$have_xz" = xno -a "x$enable_xz" = xyes; then
-                AC_MSG_ERROR([*** XZ support requested but libraries not found])
-        fi
-fi
+                [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available])
+                 have_xz=yes],
+                 have_xz=no)
+        AS_IF([test "x$have_xz" = xno -a "x$enable_xz" = xyes],
+              [AC_MSG_ERROR([*** XZ support requested but libraries not found])])
+])
 AM_CONDITIONAL(HAVE_XZ, [test "$have_xz" = "yes"])
 
 # ------------------------------------------------------------------------------
 have_zlib=no
 AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [Disable optional ZLIB support]))
-if test "x$enable_zlib" != "xno"; then
+AS_IF([test "x$enable_zlib" != "xno"], [
         PKG_CHECK_MODULES(ZLIB, [ zlib ],
-                [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available]) have_zlib=yes], have_zlib=no)
-        if test "x$have_zlib" = xno -a "x$enable_zlib" = xyes; then
-                AC_MSG_ERROR([*** ZLIB support requested but libraries not found])
-        fi
-fi
+                [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available])
+                 have_zlib=yes],
+                 have_zlib=no)
+        AS_IF([test "x$have_zlib" = xno -a "x$enable_zlib" = xyes],
+              [AC_MSG_ERROR([*** ZLIB support requested but libraries not found])])
+])
 AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"])
 
 # ------------------------------------------------------------------------------
@@ -557,20 +558,24 @@ have_bzip2=no
 AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Disable optional BZIP2 support]))
 AS_IF([test "x$enable_bzip2" != "xno"], [
         AC_CHECK_HEADERS(bzlib.h,
-                [AC_DEFINE(HAVE_BZIP2, 1, [Define in BZIP2 is available])
+                [AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available])
                  have_bzip2=yes],
-                [AS_IF([test "x$have_bzip2" = xyes], [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])])
-        ])
+                [AS_IF([test "x$enable_bzip2" = xyes],
+                       [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])])]
+        )
 ])
 AM_CONDITIONAL(HAVE_BZIP2, [test "$have_bzip2" = "yes"])
 
 # ------------------------------------------------------------------------------
 have_lz4=no
-AC_ARG_ENABLE(lz4, AS_HELP_STRING([--enable-lz4], [Enable optional LZ4 support]))
-AS_IF([test "x$enable_lz4" = "xyes"], [
-        AC_CHECK_HEADERS(lz4.h,
-               [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available]) have_lz4=yes],
-               [AC_MSG_ERROR([*** LZ4 support requested but headers not found])])
+AC_ARG_ENABLE(lz4, AS_HELP_STRING([--disable-lz4], [Disable optional LZ4 support]))
+AS_IF([test "x$enable_lz4" != "xno"], [
+        PKG_CHECK_MODULES(LZ4, [ liblz4 >= 125 ],
+               [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available])
+                have_lz4=yes],
+                have_lz4=no)
+        AS_IF([test "x$have_lz4" = xno -a "x$enable_lz4" = xyes],
+              [AC_MSG_ERROR([*** LZ4 support requested but libraries not found])])
 ])
 AM_CONDITIONAL(HAVE_LZ4, [test "$have_lz4" = "yes"])
 
@@ -789,14 +794,6 @@ if test "x${have_elfutils}" != xno ; then
                         AC_MSG_ERROR([*** ELFUTILS headers not found.])
                 fi])
 
-        AC_CHECK_LIB(
-                [dw],
-                [dwfl_begin],
-                [],
-                [if test "x$have_elfutils" = xyes ; then
-                        AC_MSG_ERROR([*** ELFUTILS libs not found.])
-                fi])
-
         AC_CHECK_LIB(
                 [dw],
                 [dwfl_core_file_attach],
@@ -1107,10 +1104,12 @@ AM_CONDITIONAL(ENABLE_POLKIT, [test "x$have_polkit" = "xyes"])
 # ------------------------------------------------------------------------------
 have_resolved=no
 AC_ARG_ENABLE(resolved, AS_HELP_STRING([--disable-resolved], [disable resolve daemon]))
-if test "x$enable_resolved" != "xno"; then
+AS_IF([test "x$enable_resolved" != "xno"], [
+        AC_CHECK_LIB([dl], [dlsym], [true], [AC_MSG_ERROR([*** Dynamic linking loader library not found])])
+
         have_resolved=yes
         M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED"
-fi
+])
 AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"])
 
 AC_ARG_WITH(dns-servers,
@@ -1286,7 +1285,12 @@ AM_CONDITIONAL(ENABLE_HWDB, [test x$enable_hwdb = xyes])
 # ------------------------------------------------------------------------------
 have_manpages=no
 AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages]))
-AS_IF([test "x$enable_manpages" != xno], [have_manpages=yes])
+AS_IF([test "x$enable_manpages" != xno], [
+       have_manpages=yes
+       AC_PATH_PROG([XSLTPROC], [xsltproc])
+       AS_IF([test -z "$XSLTPROC"],
+             AC_MSG_ERROR([*** xsltproc is required for man pages]))
+])
 AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"])
 
 # ------------------------------------------------------------------------------
index 1dd642678d310737bd0031f3d811db422166fea5..a825e744e10fb09e1c8bcb0de797d0754f84847c 100644 (file)
@@ -1982,3 +1982,87 @@ bluetooth:v0291*
 
 bluetooth:v0292*
  ID_VENDOR_FROM_DATABASE=SwiftSensors
+
+bluetooth:v0293*
+ ID_VENDOR_FROM_DATABASE=Blue Bite
+
+bluetooth:v0294*
+ ID_VENDOR_FROM_DATABASE=ELIAS GmbH
+
+bluetooth:v0295*
+ ID_VENDOR_FROM_DATABASE=Sivantos GmbH
+
+bluetooth:v0296*
+ ID_VENDOR_FROM_DATABASE=Petzl
+
+bluetooth:v0297*
+ ID_VENDOR_FROM_DATABASE=storm power ltd
+
+bluetooth:v0298*
+ ID_VENDOR_FROM_DATABASE=EISST Ltd
+
+bluetooth:v0299*
+ ID_VENDOR_FROM_DATABASE=Inexess Technology Simma KG
+
+bluetooth:v029A*
+ ID_VENDOR_FROM_DATABASE=Currant, Inc.
+
+bluetooth:v029B*
+ ID_VENDOR_FROM_DATABASE=C2 Development, Inc.
+
+bluetooth:v029C*
+ ID_VENDOR_FROM_DATABASE=Blue Sky Scientific, LLC
+
+bluetooth:v029D*
+ ID_VENDOR_FROM_DATABASE=ALOTTAZS LABS, LLC
+
+bluetooth:v029E*
+ ID_VENDOR_FROM_DATABASE=Kupson spol. s r.o.
+
+bluetooth:v029F*
+ ID_VENDOR_FROM_DATABASE=Areus Engineering GmbH
+
+bluetooth:v02A0*
+ ID_VENDOR_FROM_DATABASE=Impossible Camera GmbH
+
+bluetooth:v02A1*
+ ID_VENDOR_FROM_DATABASE=InventureTrack Systems
+
+bluetooth:v02A2*
+ ID_VENDOR_FROM_DATABASE=LockedUp
+
+bluetooth:v02A3*
+ ID_VENDOR_FROM_DATABASE=Itude
+
+bluetooth:v02A4*
+ ID_VENDOR_FROM_DATABASE=Pacific Lock Company
+
+bluetooth:v02A5*
+ ID_VENDOR_FROM_DATABASE=Tendyron Corporation ( 天地融科技股份有限公司 )
+
+bluetooth:v02A6*
+ ID_VENDOR_FROM_DATABASE=Robert Bosch GmbH
+
+bluetooth:v02A7*
+ ID_VENDOR_FROM_DATABASE=Illuxtron international B.V.
+
+bluetooth:v02A8*
+ ID_VENDOR_FROM_DATABASE=miSport Ltd.
+
+bluetooth:v02A9*
+ ID_VENDOR_FROM_DATABASE=Chargelib
+
+bluetooth:v02AA*
+ ID_VENDOR_FROM_DATABASE=Doppler Lab
+
+bluetooth:v02AB*
+ ID_VENDOR_FROM_DATABASE=BBPOS Limited
+
+bluetooth:v02AC*
+ ID_VENDOR_FROM_DATABASE=RTB Elektronik GmbH & Co. KG
+
+bluetooth:v02AD*
+ ID_VENDOR_FROM_DATABASE=Rx Networks, Inc.
+
+bluetooth:v02AE*
+ ID_VENDOR_FROM_DATABASE=WeatherFlow, Inc.
index 58d7337a1dc787a7c4602c6855dd2fa3d5dac8f2..f7a82ee26cb8b8d3cf1a2a9dae822082cc43ff80 100644 (file)
@@ -99,6 +99,22 @@ evdev:name:ETPS/2 Elantech Touchpad:dmi:bvn*:bvr*:bd*:svnASUSTeKComputerInc.:pnK
  EVDEV_ABS_35=::18
  EVDEV_ABS_36=::16
 
+#########################################
+# Dell
+#########################################
+
+# Dell Vostro 1510
+evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510*
+ EVDEV_ABS_00=::14
+ EVDEV_ABS_01=::18
+
+# Dell Inspiron N5040
+evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040*
+ EVDEV_ABS_00=25:2000:22
+ EVDEV_ABS_01=0:1351:28
+ EVDEV_ABS_35=25:2000:22
+ EVDEV_ABS_36=0:1351:28
+
 #########################################
 # Google
 #########################################
@@ -119,11 +135,9 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230*
  EVDEV_ABS_01=::100
  EVDEV_ABS_36=::100
 
-#########################################
-# Dell
-#########################################
-
-# Dell Vostro 1510
-evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510*
- EVDEV_ABS_00=::14
- EVDEV_ABS_01=::18
+# Lenovo T510
+evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510*
+ EVDEV_ABS_00=778:6239:72
+ EVDEV_ABS_01=841:5330:100
+ EVDEV_ABS_35=778:6239:72
+ EVDEV_ABS_36=841:5330:100
index 24db0d2ba6a1363effe6689cc131f35597548e71..94906abcbfe6788d5696227543f2b870f66c254f 100644 (file)
@@ -495,6 +495,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook450G0:pvr*
  KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
 
+# HP ProBook 6555b
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:*
+ KEYBOARD_KEY_b2=www                                    # Earth
+
 ###########################################################
 # IBM
 ###########################################################
@@ -648,11 +652,6 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
  KEYBOARD_KEY_f1=f21
 
-# Thinkpad Yoga 12 (2015)
-evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPadS1Yoga12*
- KEYBOARD_KEY_d8=direction
- KEYBOARD_KEY_d9=direction
-
 # enhanced USB keyboard
 evdev:input:b0003v04B3p301B*
  KEYBOARD_KEY_90001=prog1 # ThinkVantage
index 55e68a913839606b12c9f7e82d43e114c2f430fe..2383d586a3bbac6170abd734490c3afa5dcfc1e9 100644 (file)
@@ -311,6 +311,9 @@ mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
 mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
 # Logitech V500 Cordless Notebook Mouse
 mouse:usb:v046dpc510:name:Logitech USB Receiver:
+# Logitech M560 Wireless Mouse
+mouse:usb:v046dp402d:name:Logitech M560:
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d:
  MOUSE_DPI=1000@125
 
 # Logitech V220 Cordless Optical Mouse
index bf6ca0bf9e9f6f62a20d73450da529da20834421..f6ac7e6ae2adb89967fbbc462755994df197f699 100644 (file)
@@ -86,7 +86,7 @@
         <term><varname>Frequency=25</varname></term>
         <listitem><para>Configure the sample log frequency. This can
         be a fractional number, but must be larger than 0.0. Most
-        systems can cope with values under 25-50 without impacting
+        systems can cope with values under 2550 without impacting
         boot time severely.</para></listitem>
       </varlistentry>
 
index 63ad9392ebc7442c24c9087e65b921166940b1a3..ebd58750d3ed4bd671eebca9a98d54e58465565e 100644 (file)
     system.</para>
 
     <para><command>bootctl status</command> checks and prints the
-    currently installed versions of the boot loader binaries and the
+    currently installed versions of the boot loader binaries and
     all current EFI boot variables.</para>
 
     <para><command>bootctl update</command> updates all installed
     versions of systemd-boot, if the current version is newer than the
     version installed in the EFI system partition. This also includes
     the EFI default/fallback loader at /EFI/Boot/boot*.efi. A
-    systemd-boot entry in the EFI boot variables is created, if there
+    systemd-boot entry in the EFI boot variables is created if there
     is no current entry. The created entry will be added to the end of
     the boot order list.</para>
 
@@ -89,7 +89,7 @@
     versions of systemd-boot from the EFI system partition, and removes
     systemd-boot from the EFI boot variables.</para>
 
-    <para>If no command is passed <command>status</command> is
+    <para>If no command is passed, <command>status</command> is
     implied.</para>
   </refsect1>
 
 
   <refsect1>
     <title>Exit status</title>
-    <para>On success 0 is returned, a non-zero failure
+    <para>On success, 0 is returned, a non-zero failure
     code otherwise.</para>
   </refsect1>
 
index 4f0b2a7051f76f6d62159dfcd86bb0a91cfa9958..d8c1085021e5c5a645d89e2b9a5dc034b2113942 100644 (file)
         <term><option>--size=</option></term>
 
         <listitem>
-          <para>When used with the <command>capture</command> command
+          <para>When used with the <command>capture</command> command,
           specifies the maximum bus message size to capture
           ("snaplen"). Defaults to 4096 bytes.</para>
         </listitem>
         <term><option>--list</option></term>
 
         <listitem>
-          <para>When used with the <command>tree</command> command shows a
+          <para>When used with the <command>tree</command> command, shows a
           flat list of object paths instead of a tree.</para>
         </listitem>
       </varlistentry>
         <term><option>--quiet</option></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command
+          <para>When used with the <command>call</command> command,
           suppresses display of the response message payload. Note that even
-          if this option is specified errors returned will still be
+          if this option is specified, errors returned will still be
           printed and the tool will indicate success or failure with
           the process exit code.</para>
         </listitem>
 
         <listitem>
           <para>When used with the <command>call</command> or
-          <command>get-property</command> command shows output in a
+          <command>get-property</command> command, shows output in a
           more verbose format.</para>
         </listitem>
       </varlistentry>
         <term><option>--expect-reply=</option><replaceable>BOOL</replaceable></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command
+          <para>When used with the <command>call</command> command,
           specifies whether <command>busctl</command> shall wait for
           completion of the method call, output the returned method
           response data, and return success or failure via the process
-          exit code. If this is set to <literal>no</literal> the
+          exit code. If this is set to <literal>no</literal>, the
           method call will be issued but no response is expected, the
           tool terminates immediately, and thus no response can be
           shown, and no success or failure is returned via the exit
-          code. To only suppress output of the reply message payload
+          code. To only suppress output of the reply message payload,
           use <option>--quiet</option> above. Defaults to
           <literal>yes</literal>.</para>
         </listitem>
         <term><option>--auto-start=</option><replaceable>BOOL</replaceable></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command specifies
+          <para>When used with the <command>call</command> command, specifies
           whether the method call should implicitly activate the
-          called service should it not be running yet but is
+          called service, should it not be running yet but is
           configured to be auto-started. Defaults to
           <literal>yes</literal>.</para>
         </listitem>
         <term><option>--allow-interactive-authorization=</option><replaceable>BOOL</replaceable></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command
+          <para>When used with the <command>call</command> command,
           specifies whether the services may enforce interactive
           authorization while executing the operation, if the security
           policy is configured for this. Defaults to
         <term><option>--timeout=</option><replaceable>SECS</replaceable></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command
+          <para>When used with the <command>call</command> command,
           specifies the maximum time to wait for method call
-          completion. If no time unit is specified assumes
+          completion. If no time unit is specified, assumes
           seconds. The usual other units are understood, too (ms, us,
           s, min, h, d, w, month, y). Note that this timeout does not
-          apply if <option>--expect-reply=no</option> is used as the
+          apply if <option>--expect-reply=no</option> is used, as the
           tool does not wait for any reply message then. When not
-          specified or when set to 0 the default of
+          specified or when set to 0, the default of
           <literal>25s</literal> is assumed.</para>
         </listitem>
       </varlistentry>
           <para>Controls whether credential data reported by
           <command>list</command> or <command>status</command> shall
           be augmented with data from
-          <filename>/proc</filename>. When this is turned on the data
+          <filename>/proc</filename>. When this is turned on, the data
           shown is possibly inconsistent, as the data read from
-          <filename>/proc</filename> might be more recent than rest of
+          <filename>/proc</filename> might be more recent than the rest of
           the credential information. Defaults to <literal>yes</literal>.</para>
         </listitem>
       </varlistentry>
         <term><command>list</command></term>
 
         <listitem><para>Show all peers on the bus, by their service
-        names. By default shows both unique and well-known names, but
+        names. By default, shows both unique and well-known names, but
         this may be changed with the <option>--unique</option> and
         <option>--acquired</option> switches. This is the default
         operation if no command is specified.</para></listitem>
         <replaceable>SERVICE</replaceable> is specified, show messages
         to or from this peer, identified by its well-known or unique
         name. Otherwise, show all messages on the bus. Use Ctrl-C to
-        terminate dump.</para></listitem>
+        terminate the dump.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><command>capture</command> <arg choice="opt" rep="repeat"><replaceable>SERVICE</replaceable></arg></term>
 
         <listitem><para>Similar to <command>monitor</command> but
-        writes the output in pcap format (for details see the <ulink
+        writes the output in pcap format (for details, see the <ulink
         url="http://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap
         File Format</ulink> description. Make sure to redirect the
         output to STDOUT to a file. Tools like
 
         <listitem><para>Show interfaces, methods, properties and
         signals of the specified object (identified by its path) on
-        the specified service. If the interface argument is passed the
+        the specified service. If the interface argument is passed, the
         output is limited to members of the specified
         interface.</para></listitem>
       </varlistentry>
 
         <listitem><para>Invoke a method and show the response. Takes a
         service name, object path, interface name and method name. If
-        parameters shall be passed to the method call a signature
+        parameters shall be passed to the method call, a signature
         string is required, followed by the arguments, individually
         formatted as strings. For details on the formatting used, see
-        below. To suppress output of the returned data use the
+        below. To suppress output of the returned data, use the
         <option>--quiet</option> option.</para></listitem>
       </varlistentry>
 
         <listitem><para>Retrieve the current value of one or more
         object properties. Takes a service name, object path,
         interface name and property name. Multiple properties may be
-        specified at once in which case their values will be shown one
-        after the other, separated by newlines. The output is by
-        default in terse format. Use <option>--verbose</option> for a
+        specified at once, in which case their values will be shown one
+        after the other, separated by newlines. The output is, by
+        default, in terse format. Use <option>--verbose</option> for a
         more elaborate output format.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><command>set-property</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain"><replaceable>PROPERTY</replaceable></arg> <arg choice="plain"><replaceable>SIGNATURE</replaceable></arg> <arg choice="plain" rep="repeat"><replaceable>ARGUMENT</replaceable></arg></term>
 
-        <listitem><para>Set the current value an object
+        <listitem><para>Set the current value of an object
         property. Takes a service name, object path, interface name,
         property name, property signature, followed by a list of
         parameters formatted as strings.</para></listitem>
     <para>The <command>call</command> and
     <command>set-property</command> commands take a signature string
     followed by a list of parameters formatted as string (for details
-    on D-Bus signature strings see the <ulink
+    on D-Bus signature strings, see the <ulink
     url="http://dbus.freedesktop.org/doc/dbus-specification.html#type-system">Type
     system chapter of the D-Bus specification</ulink>). For simple
-    types each parameter following the signature should simply be the
+    types, each parameter following the signature should simply be the
     parameter's value formatted as string. Positive boolean values may
     be formatted as <literal>true</literal>, <literal>yes</literal>,
-    <literal>on</literal>, <literal>1</literal>; negative boolean
+    <literal>on</literal>, or <literal>1</literal>; negative boolean
     values may be specified as <literal>false</literal>,
-    <literal>no</literal>, <literal>off</literal>,
+    <literal>no</literal>, <literal>off</literal>, or
     <literal>0</literal>. For arrays, a numeric argument for the
     number of entries followed by the entries shall be specified. For
-    variants the signature of the contents shall be specified,
-    followed by the contents. For dictionaries and structs the
+    variants, the signature of the contents shall be specified,
+    followed by the contents. For dictionaries and structs, the
     contents of them shall be directly specified.</para>
 
     <para>For example,
     array that maps strings to variants, consisting of three
     entries. The string <literal>One</literal> is assigned the
     string <literal>Eins</literal>. The string
-    <literal>Two</literal> is assigned the 32bit unsigned
+    <literal>Two</literal> is assigned the 32-bit unsigned
     integer 2. The string <literal>Yes</literal> is assigned a
     positive boolean.</para>
 
@@ -456,8 +456,8 @@ ARRAY "s" {
       of the <literal>org.freedesktop.systemd1</literal>
       service, and passes it two strings
       <literal>cups.service</literal> and
-      <literal>replace</literal>. As result of the method
-      call a single object path parameter is received and
+      <literal>replace</literal>. As result of the method
+      call, a single object path parameter is received and
       shown:</para>
 
       <programlisting># busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartUnit ss "cups.service" "replace"
index 8e71f7d4ec93f84faee777bf7437523a07a48bad..a0a497b46760b081bd1f41f8abd71a8969890b3e 100644 (file)
@@ -98,7 +98,7 @@
         <term><varname>Compress=</varname></term>
 
         <listitem><para>Controls compression for external
-        storage. Takes a boolean argument, defaults to
+        storage. Takes a boolean argument, which defaults to
         <literal>yes</literal>.</para>
         </listitem>
       </varlistentry>
         coredumps are processed. Note that old coredumps are also
         removed based on time via
         <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Set
-        either value to 0 to turn off size based
+        either value to 0 to turn off size-based
         clean-up.</para></listitem>
       </varlistentry>
     </variablelist>
index d4ff760adcb89c7a771ac4f40dec7193c1bb4a7d..1de834a045847a9bfa8d090a64d126f3ed3b77d5 100644 (file)
         at the beginning. This is different from the <option>--offset</option>
         option with respect to the sector numbers used in initialization vector
         (IV) calculation. Using <option>--offset</option> will shift the IV
-        calculation by the same negative amount.  Hence, if <option>--offset n</option>,
+        calculation by the same negative amount.  Hence, if <option>--offset n</option> is given,
         sector n will  get a sector number of 0 for the IV calculation.
         Using <option>--skip</option> causes sector n to also be the first
-        sector of the mapped device, but with its number for IV generation is n.</para>
+        sector of the mapped device, but with its number for IV generation being n.</para>
 
         <para>This option is only relevant for plain devices.</para>
         </listitem>
index 3e266e4a7f9c9be695981209037b093a251dd0af..84c23014e4bf255e045828a72ab933dd288687f1 100644 (file)
 
 <!--
   - helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template
-  - this conflict resolution is necessary to prevent malformed HTML output (multiple id attributes with the same value)
+  - this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value)
   - and it fixes xsltproc warnings during compilation of HTML man pages
   -
   - A simple top-to-bottom numbering scheme is implemented for nodes with the same ID value to derive unique ID values for HTML output.
   <!--
     - If stable URLs with fragment markers (references to the ID) turn out not to be important:
     - generatedID could simply take the value of generate-id(), and various other helper templates may be dropped entirely.
-    - Alternatively if xsltproc is patched to generate reproducible generate-id() output the same simplifications can be
+    - Alternatively, if xsltproc is patched to generate reproducible generate-id() output, the same simplifications can be
     - applied at the cost of breaking compatibility with URLs generated from output of previous versions of this stylesheet.
    -->
   <xsl:variable name="generatedID">
index a8bbfc055b62f7f1cff4d0b1f9b37f212bb9244e..b6125cb5c7f6fa2a5318bb39e8e033d3e231cd95 100644 (file)
       configured address redundant. Another often suggested trigger
       for service activation is low system load. However, here too, a
       more convincing approach might be to make proper use of features
-      of the operating system, in particular, the CPU or IO scheduler
+      of the operating system, in particular, the CPU or I/O scheduler
       of Linux. Instead of scheduling jobs from userspace based on
       monitoring the OS scheduler, it is advisable to leave the
       scheduling of processes to the OS scheduler itself. systemd
-      provides fine-grained access to the CPU and IO schedulers. If a
+      provides fine-grained access to the CPU and I/O schedulers. If a
       process executed by the init system shall not negatively impact
-      the amount of CPU or IO bandwidth available to other processes,
+      the amount of CPU or I/O bandwidth available to other processes,
       it should be configured with
       <varname>CPUSchedulingPolicy=idle</varname> and/or
       <varname>IOSchedulingClass=idle</varname>. Optionally, this may
index 058998b51f12d315a2ad001f410b7382c4bdf940..345c56cefa772ba2a2613f58bf315f513b5a16f7 100644 (file)
@@ -84,7 +84,7 @@
       <varlistentry>
         <term><filename>/boot</filename></term>
         <listitem><para>The boot partition used for bringing up the
-        system. On EFI systems this is possibly the EFI System
+        system. On EFI systems, this is possibly the EFI System
         Partition, also see
         <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
         This directory is usually strictly local to the host, and
         directory is usually mounted as a <literal>tmpfs</literal>
         instance, and should hence not be used for larger files. (Use
         <filename>/var/tmp</filename> for larger files.) Since the
-        directory is accessible to other users of the system it is
+        directory is accessible to other users of the system, it is
         essential that this directory is only written to with the
         <citerefentry project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
         <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>
         and related calls. This directory is usually flushed at
         boot-up. Also, files that are not accessed within a certain
         time are usually automatically deleted. If applications find
-        the environment variable <varname>$TMPDIR</varname> set they
+        the environment variable <varname>$TMPDIR</varname> set, they
         should prefer using the directory specified in it over
         directly referencing <filename>/tmp</filename> (see
         <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
 
       <varlistentry>
         <term><filename>/usr/bin</filename></term>
-        <listitem><para>Binaries and executables for user commands,
+        <listitem><para>Binaries and executables for user commands
         that shall appear in the <varname>$PATH</varname> search path.
         It is recommended not to place binaries in this directory that
         are not useful for invocation from a shell (such as daemon
 
       <varlistentry>
         <term><filename>/usr/lib/<replaceable>arch-id</replaceable></filename></term>
-        <listitem><para>Location for placing dynamic libraries, also
+        <listitem><para>Location for placing dynamic libraries into, also
         called <varname>$libdir</varname>. The architecture identifier
         to use is defined on <ulink
         url="https://wiki.debian.org/Multiarch/Tuples">Multiarch
         <term><filename>/usr/share/factory/var</filename></term>
 
         <listitem><para>Similar to
-        <filename>/usr/share/factory/etc</filename> but for vendor
+        <filename>/usr/share/factory/etc</filename>, but for vendor
         versions of files in the variable, persistent data directory
         <filename>/var</filename>.</para></listitem>
 
       <varlistentry>
         <term><filename>/var/tmp</filename></term>
         <listitem><para>The place for larger and persistent temporary
-        files. In contrast to <filename>/tmp</filename> this directory
+        files. In contrast to <filename>/tmp</filename>, this directory
         is usually mounted from a persistent physical file system and
         can thus accept larger files. (Use <filename>/tmp</filename>
         for smaller files.) This directory is generally not flushed at
         <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>
         or similar calls should be used to make use of this directory.
         If applications find the environment variable
-        <varname>$TMPDIR</varname> set they should prefer using the
+        <varname>$TMPDIR</varname> set, they should prefer using the
         directory specified in it over directly referencing
         <filename>/var/tmp</filename> (see
         <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     <variablelist>
       <varlistentry>
         <term><filename>/dev</filename></term>
-        <listitem><para>The root directory for device nodes. Usually
+        <listitem><para>The root directory for device nodes. Usually,
         this directory is mounted as a <literal>devtmpfs</literal>
         instance, but might be of a different type in
         sandboxed/containerized setups. This directory is managed
         write access to this directory, special care should be taken
         to avoid name clashes and vulnerabilities. For normal users,
         shared memory segments in this directory are usually deleted
-        when the user logs out. Usually it is a better idea to use
+        when the user logs out. Usually, it is a better idea to use
         memory mapped files in <filename>/run</filename> (for system
         programs) or <varname>$XDG_RUNTIME_DIR</varname> (for user
-        programs) instead of POSIX shared memory segments, since those
+        programs) instead of POSIX shared memory segments, since these
         directories are not world-writable and hence not vulnerable to
         security-sensitive name clashes.</para></listitem>
       </varlistentry>
         that exposes a number of kernel tunables. The primary way to
         configure the settings in this API file tree is via
         <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        files. In sandboxed/containerized setups this directory is
+        files. In sandboxed/containerized setups, this directory is
         generally mounted read-only.</para></listitem>
       </varlistentry>
 
         discovered devices and other functionality. This file system
         is mostly an API to interface with the kernel and not a place
         where normal files may be stored. In sandboxed/containerized
-        setups this directory is generally mounted read-only. A number
+        setups, this directory is generally mounted read-only. A number
         of special purpose virtual file systems might be mounted below
         this directory.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><filename>/lib64</filename></term>
 
-        <listitem><para>On some architecture ABIs this compatibility
+        <listitem><para>On some architecture ABIs, this compatibility
         symlink points to <varname>$libdir</varname>, ensuring that
         binaries referencing this legacy path correctly find their
         dynamic loader. This symlink only exists on architectures
         directory should have no effect on operation of programs,
         except for increased runtimes necessary to rebuild these
         caches. If an application finds
-        <varname>$XDG_CACHE_HOME</varname> set is should use the
+        <varname>$XDG_CACHE_HOME</varname> set, it should use the
         directory specified in it instead of this
         directory.</para></listitem>
       </varlistentry>
         <term><filename>~/.config</filename></term>
 
         <listitem><para>Application configuration and state. When a
-        new user is created this directory will be empty or not exist
+        new user is created, this directory will be empty or not exist
         at all. Applications should fall back to defaults should their
         configuration or state in this directory be missing. If an
-        application finds <varname>$XDG_CONFIG_HOME</varname> set is
+        application finds <varname>$XDG_CONFIG_HOME</varname> set, it
         should use the directory specified in it instead of this
         directory.</para></listitem>
       </varlistentry>
         invocation from a shell; these should be placed in a
         subdirectory of <filename>~/.local/lib</filename> instead.
         Care should be taken when placing architecture-dependent
-        binaries in this place which might be problematic if the home
+        binaries in this place, which might be problematic if the home
         directory is shared between multiple hosts with different
         architectures.</para></listitem>
       </varlistentry>
         <term><filename>~/.local/lib/<replaceable>arch-id</replaceable></filename></term>
 
         <listitem><para>Location for placing public dynamic libraries.
-        The architecture identifier to use, is defined on <ulink
+        The architecture identifier to use is defined on <ulink
         url="https://wiki.debian.org/Multiarch/Tuples">Multiarch
         Architecture Specifiers (Tuples)</ulink>
         list.</para></listitem>
         such as fonts or artwork. Usually, the precise location and
         format of files stored below this directory is subject to
         specifications that ensure interoperability. If an application
-        finds <varname>$XDG_DATA_HOME</varname> set is should use the
+        finds <varname>$XDG_DATA_HOME</varname> set, it should use the
         directory specified in it instead of this
         directory.</para></listitem>
       </varlistentry>
     <filename>/run/user</filename>) of the user, which are all
     writable.</para>
 
-    <para>For unprivileged system processes only
+    <para>For unprivileged system processes, only
     <filename>/tmp</filename>,
     <filename>/var/tmp</filename> and
     <filename>/dev/shm</filename> are writable. If an
-    unprivileged system process needs a private, writable directory in
+    unprivileged system process needs a private writable directory in
     <filename>/var</filename> or <filename>/run</filename>, it is
     recommended to either create it before dropping privileges in the
     daemon code, to create it via
 
     <para>It is strongly recommended that <filename>/dev</filename> is
     the only location below which device nodes shall be placed.
-    Similar, <filename>/run</filename> shall be the only location to
+    Similarly, <filename>/run</filename> shall be the only location to
     place sockets and FIFOs. Regular files, directories and symlinks
     may be used in all directories.</para>
   </refsect1>
         <tbody>
           <row>
       <entry><filename>/usr/bin</filename></entry>
-      <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path, compiled for any of the supported architectures compatible with the operating system. It is not recommended to place internal binaries or binaries that are not commonly invoked from the shell in this directory, such as daemon binaries. As this directory is shared with most other packages of the system special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry>
+      <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path, compiled for any of the supported architectures compatible with the operating system. It is not recommended to place internal binaries or binaries that are not commonly invoked from the shell in this directory, such as daemon binaries. As this directory is shared with most other packages of the system, special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry>
           </row>
           <row>
       <entry><filename>/usr/lib/<replaceable>arch-id</replaceable></filename></entry>
           </row>
           <row>
       <entry><filename>/usr/lib/<replaceable>package</replaceable></filename></entry>
-      <entry>Private, static vendor resources of the package, including private binaries and libraries, or any other kind of read-only vendor data.</entry>
+      <entry>Private static vendor resources of the package, including private binaries and libraries, or any other kind of read-only vendor data.</entry>
           </row>
           <row>
       <entry><filename>/usr/lib/<replaceable>arch-id</replaceable>/<replaceable>package</replaceable></filename></entry>
     </table>
 
     <para>Additional static vendor files may be installed in the
-    <filename>/usr/share</filename> hierarchy, to the locations
+    <filename>/usr/share</filename> hierarchy to the locations
     defined by the various relevant specifications.</para>
 
-    <para>During runtime and for local configuration and state
+    <para>During runtime, and for local configuration and state,
     additional directories are defined:</para>
 
     <table>
           </row>
           <row>
       <entry><filename>/var/cache/<replaceable>package</replaceable></filename></entry>
-      <entry>Persistent cache data of the package. If this directory is flushed the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry>
+      <entry>Persistent cache data of the package. If this directory is flushed, the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry>
           </row>
           <row>
       <entry><filename>/var/lib/<replaceable>package</replaceable></filename></entry>
     when placing their own files in the user's home directory. The
     following table lists recommended locations in the home directory
     for specific types of files supplied by the vendor if the
-    application is installed in the home directory. (Note however,
+    application is installed in the home directory. (Note, however,
     that user applications installed system-wide should follow the
     rules outlined above regarding placing vendor files.)</para>
 
         <tbody>
           <row>
       <entry><filename>~/.local/bin</filename></entry>
-      <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path. It is not recommended to place internal executables or executables that are not commonly invoked from the shell in this directory, such as daemon executables. As this directory is shared with most other packages of the user special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry>
+      <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path. It is not recommended to place internal executables or executables that are not commonly invoked from the shell in this directory, such as daemon executables. As this directory is shared with most other packages of the user, special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry>
           </row>
           <row>
       <entry><filename>~/.local/lib/<replaceable>arch-id</replaceable></filename></entry>
     </table>
 
     <para>Additional static vendor files may be installed in the
-    <filename>~/.local/share</filename> hierarchy, to the locations
+    <filename>~/.local/share</filename> hierarchy to the locations
     defined by the various relevant specifications.</para>
 
-    <para>During runtime and for local configuration and state
+    <para>During runtime, and for local configuration and state,
     additional directories are defined:</para>
 
     <table>
           </row>
           <row>
       <entry><filename>~/.cache/<replaceable>package</replaceable></filename></entry>
-      <entry>Persistent cache data of the package. If this directory is flushed the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry>
+      <entry>Persistent cache data of the package. If this directory is flushed, the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry>
           </row>
         </tbody>
       </tgroup>
index 80939dd95df47d7d5ebbb544b7567ece6af61048..2b1e60fb2224d662e0c0462aee3b638a53a38b58 100644 (file)
@@ -34,7 +34,7 @@
 
   <refsect1><title>Description</title>
     <para>The hardware database is a key-value store for associating modalias-like keys to
-    udev-properties-like values. It is used primarily by udev to add the relevant properties
+    udev-property-like values. It is used primarily by udev to add the relevant properties
     to matching devices, but it can also be queried directly.</para>
   </refsect1>
 
@@ -55,9 +55,9 @@
 
       <para>The hwdb file contains data records consisting of matches and
       associated key-value pairs. Every record in the hwdb starts with one or
-      more match string, specifying a shell glob to compare the database
+      more match strings, specifying a shell glob to compare the database
       lookup string against. Multiple match lines are specified in additional
-      consecutive lines. Every match line is compared individually, they are
+      consecutive lines. Every match line is compared individually, and they are
       combined by OR. Every match line must start at the first character of
       the line.</para>
 
@@ -71,7 +71,7 @@
       and compiled to a binary database located at <filename>/etc/udev/hwdb.bin</filename>,
       or alternatively <filename>/usr/lib/udev/hwdb.bin</filename> if you want ship the compiled
       database in an immutable image.
-      During runtime only the binary database is used.</para>
+      During runtime, only the binary database is used.</para>
   </refsect1>
 
   <refsect1>
index db3f166e65349c35961c19598f9393ec819f4c95..b57afb6ebfbcefef384c127a6a8e94e2d0f212b7 100644 (file)
@@ -82,7 +82,7 @@
       matches apply to the same field, then they are automatically
       matched as alternatives, i.e. the resulting output will show
       entries matching any of the specified matches for the same
-      field. Finally, the character <literal>+</literal> may appears
+      field. Finally, the character <literal>+</literal> may appear
       as a separate word between other terms on the command line. This
       causes all matches before and after to be combined in a
       disjunction (i.e. logical OR).</para>
@@ -95,7 +95,7 @@
       <literal>_KERNEL_DEVICE=</literal> match for the device.</para>
 
       <para>Additional constraints may be added using options
-      <option>--boot</option>, <option>--unit=</option>, etc, to
+      <option>--boot</option>, <option>--unit=</option>, etc., to
       further limit what entries will be shown (logical AND).</para>
 
       <para>Output is interleaved from all accessible journal files,
           <option>-n1000</option> to guarantee that the pager will not
           buffer logs of unbounded size. This may be overridden with
           an explicit <option>-n</option> with some other numeric
-          value while <option>-nall</option> will disable this cap.
+          value, while <option>-nall</option> will disable this cap.
           Note that this option is only supported for the
           <citerefentry project='man-pages'><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry>
           pager.</para></listitem>
         <term><option>-q</option></term>
         <term><option>--quiet</option></term>
 
-        <listitem><para>Suppresses any warning messages regarding
+        <listitem><para>Suppresses all info messages
+        (i.e. "-- Logs begin at ...", "-- Reboot --"),
+        any warning messages regarding
         inaccessible system journals when run as a normal
         user.</para></listitem>
       </varlistentry>
 
         <para>If the boot ID is omitted, a positive
         <replaceable>offset</replaceable> will look up the boots
-        starting from the beginning of the journal, and a
+        starting from the beginning of the journal, and an
         equal-or-less-than zero <replaceable>offset</replaceable> will
         look up boots starting from the end of the journal. Thus,
         <constant>1</constant> means the first boot found in the
         <replaceable>offset</replaceable> which identifies the boot
         relative to the one given by boot
         <replaceable>ID</replaceable>. Negative values mean earlier
-        boots and positive values mean later boots. If
+        boots and positive values mean later boots. If
         <replaceable>offset</replaceable> is not specified, a value of
         zero is assumed, and the logs for the boot given by
         <replaceable>ID</replaceable> are shown.</para>
 
         <listitem><para>Start showing entries from the location in the
         journal <emphasis>after</emphasis> the location specified by
-        the this cursor.  The cursor is shown when the
+        the passed cursor.  The cursor is shown when the
         <option>--show-cursor</option> option is used.</para>
         </listitem>
       </varlistentry>
       </varlistentry>
 
       <varlistentry>
+        <term><option>-S</option></term>
         <term><option>--since=</option></term>
+        <term><option>-U</option></term>
         <term><option>--until=</option></term>
 
         <listitem><para>Start showing entries on or newer than the
         respectively. <literal>now</literal> refers to the current
         time. Finally, relative times may be specified, prefixed with
         <literal>-</literal> or <literal>+</literal>, referring to
-        times before or after the current time, respectively.</para>
+        times before or after the current time, respectively. For complete
+        time and date specification, see
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+        </para>
         </listitem>
       </varlistentry>
 
         <listitem><para>Removes archived journal files until the disk
         space they use falls below the specified size (specified with
         the usual <literal>K</literal>, <literal>M</literal>,
-        <literal>G</literal>, <literal>T</literal> suffixes), or all
+        <literal>G</literal> and <literal>T</literal> suffixes), or all
         journal files contain no data older than the specified
         timespan (specified with the usual <literal>s</literal>,
         <literal>min</literal>, <literal>h</literal>,
         <literal>days</literal>, <literal>months</literal>,
-        <literal>weeks</literal>, <literal>years</literal> suffixes),
+        <literal>weeks</literal> and <literal>years</literal> suffixes),
         or no more than the specified number of separate journal files
         remain. Note that running <option>--vacuum-size=</option> has
-        only indirect effect on the output shown by
-        <option>--disk-usage</option> as the latter includes active
-        journal files, while the the vacuuming operation only operates
-        on archived journal files. Similar,
+        only an indirect effect on the output shown by
+        <option>--disk-usage</option>, as the latter includes active
+        journal files, while the vacuuming operation only operates
+        on archived journal files. Similarly,
         <option>--vacuum-files=</option> might not actually reduce the
         number of journal files to below the specified number, as it
         will not remove active journal
         the <option>--verify</option> operation.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--sync</option></term>
+
+        <listitem><para>Asks the journal daemon to write all yet
+        unwritten journal data to the backing file system and
+        synchronize all journals. This call does not return until the
+        synchronization operation is complete. This command guarantees
+        that any log messages written before its invocation are safely
+        stored on disk at the time it returns.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--flush</option></term>
 
-        <listitem><para>Asks the Journal daemon to flush any log data
+        <listitem><para>Asks the journal daemon to flush any log data
         stored in <filename>/run/log/journal</filename> into
-        <filename>/var/log/journal</filename>, if persistent storage is
-        enabled. This call does not return until the operation is
-        complete.</para></listitem>
+        <filename>/var/log/journal</filename>, if persistent storage
+        is enabled. This call does not return until the operation is
+        complete. Note that this call is idempotent: the data is only
+        flushed from <filename>/run/log/journal</filename> into
+        <filename>/var/log/journal</filename> once during system
+        runtime, and this command exits cleanly without executing any
+        operation if this has already has happened. This command
+        effectively guarantees that all data is flushed to
+        <filename>/var/log/journal</filename> at the time it
+        returns.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--rotate</option></term>
 
-        <listitem><para>Asks the Journal daemon to rotate journal files.
-        </para></listitem>
+        <listitem><para>Asks the journal daemon to rotate journal
+        files. This call does not return until the rotation operation
+        is complete.</para></listitem>
       </varlistentry>
+
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
       <xi:include href="standard-options.xml" xpointer="no-pager" />
       <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>coredumpctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     </para>
   </refsect1>
 </refentry>
index 4464fe53ad769873be9ce5f214e576f9cf9e5b05..a9690e8138022d5722ed38bd73a1de829527dbd2 100644 (file)
 
         <para><varname>SystemMaxUse=</varname> and
         <varname>RuntimeMaxUse=</varname> control how much disk space
-        the journal may use up at maximum.
+        the journal may use up at most.
         <varname>SystemKeepFree=</varname> and
         <varname>RuntimeKeepFree=</varname> control how much disk
         space systemd-journald shall leave free for other uses.
         enough free space before and journal files were created, and
         subsequently something else causes the file system to fill up,
         journald will stop using more space, but it will not be
-        removing existing files to reduce footprint again
+        removing existing files to reduce the footprint again,
         either.</para>
 
         <para><varname>SystemMaxFileSize=</varname> and
         <varname>RuntimeMaxFileSize=</varname> control how large
-        individual journal files may grow at maximum. This influences
+        individual journal files may grow at most. This influences
         the granularity in which disk space is made available through
         rotation, i.e. deletion of historic data. Defaults to one
         eighth of the values configured with
         rotated journal files are kept as history.</para>
 
         <para>Specify values in bytes or use K, M, G, T, P, E as
-        units for the specified sizes (equal to 1024, 1024²,... bytes).
+        units for the specified sizes (equal to 1024, 1024², ... bytes).
         Note that size limits are enforced synchronously when journal
         files are extended, and no explicit rotation step triggered by
         time is needed.</para>
 
         <para><varname>SystemMaxFiles=</varname> and
         <varname>RuntimeMaxFiles=</varname> control how many
-        individual journal files to keep at maximum. Note that only
+        individual journal files to keep at most. Note that only
         archived files are deleted to reduce the number of files until
         this limit is reached; active files will stay around. This
-        means that in effect there might still be more journal files
+        means that, in effect, there might still be more journal files
         around in total than this limit after a vacuuming operation is
         complete. This setting defaults to 100.</para></listitem>
       </varlistentry>
         <literal>notice</literal>,
         <literal>info</literal>,
         <literal>debug</literal>,
-        or integer values in the range of 0..7 (corresponding to the
+        or integer values in the range of 07 (corresponding to the
         same levels). Messages equal or below the log level specified
         are stored/forwarded, messages above are dropped. Defaults to
         <literal>debug</literal> for <varname>MaxLevelStore=</varname>
 
     <para>
       Journal events can be transferred to a different logging daemon
-      in two different ways. In the first method, messages are
+      in two different ways. With the first method, messages are
       immediately forwarded to a socket
       (<filename>/run/systemd/journal/syslog</filename>), where the
       traditional syslog daemon can read them. This method is
-      controlled by <varname>ForwardToSyslog=</varname> option.  In a
+      controlled by the <varname>ForwardToSyslog=</varname> option. With a
       second method, a syslog daemon behaves like a normal journal
       client, and reads messages from the journal files, similarly to
       <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
-      In this method, messages do not have to be read immediately,
+      With this, messages do not have to be read immediately,
       which allows a logging daemon which is only started late in boot
       to access all messages since the start of the system. In
       addition, full structured meta-data is available to it. This
index 2f81746b5eb30598bf7972cfb618e79557eec6cb..309220632e3c5877b98c2c9890fbaae8b38d1b1e 100644 (file)
@@ -66,7 +66,7 @@
 
     <para>For command line parameters understood by the initial RAM
     disk, please see
-    <citerefentry project='die-net'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+    <citerefentry project='man-pages'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
     or the documentation of the specific initrd implementation of your
     installation.</para>
   </refsect1>
           from the previous boot. For details, see
           <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
           and
-          <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+          <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
           </para>
         </listitem>
       </varlistentry>
       <para>
         <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
         <citerefentry project='man-pages'><refentrytitle>bootparam</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
-        <citerefentry project='die-net'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+        <citerefentry project='man-pages'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-fsck@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
       </para>
   </refsect1>
index 5660b9d990d29ddcab502aab27791523ecbf5f29..7ef978463cedcbe6d5e6fa79d271180e2a594fee 100644 (file)
@@ -75,7 +75,7 @@
     a udev context. Furthermore, multiple different udev contexts can
     be used in parallel by multiple threads. However, a single context
     must not be accessed by multiple threads in parallel. The caller
-    is responsible of providing suitable locking if they intend to use
+    is responsible for providing suitable locking if they intend to use
     it from multiple threads.</para>
 
     <para>To introspect a local device on a system, a udev device
 
     <para>Furthermore, libudev also exports legacy APIs that should
     not be used by new software (and as such are not documented as
-    part of this manual). This includes the hardware-database known
+    part of this manual). This includes the hardware database known
     as <constant>udev_hwdb</constant> (please use the new
     <citerefentry><refentrytitle>sd-hwdb</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     API instead) and the <constant>udev_queue</constant> object to
-    query the udev-daemon (which should not be used by new software
+    query the udev daemon (which should not be used by new software
     at all).</para>
   </refsect1>
 
index 2c32d1609415fef92d612d7a6f8137a3f235ed2a..2fe731113a00625d8a41ca683d0c1b866787fe48 100644 (file)
@@ -54,7 +54,7 @@
     <title>Description</title>
 
     <para>The <filename>/etc/locale.conf</filename> file configures
-    system-wide locale settings. It is read at early-boot by
+    system-wide locale settings. It is read at early boot by
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
 
     <para>The basic file format of <filename>locale.conf</filename> is
index 9dda14d4548df1da386bde21a8317281da380000..f41acc6a1b8bc9340632f8fd5aee539d48871cbc 100644 (file)
         <listitem><para>Show terse runtime status information about
         one or more sessions, followed by the most recent log data
         from the journal. Takes one or more session identifiers as
-        parameters. If no session identifiers are passed the status of
+        parameters. If no session identifiers are passed, the status of
         the caller's session is shown. This function is intended to
         generate human-readable output. If you are looking for
         computer-parsable output, use <command>show-session</command>
         <term><command>activate</command> <optional><replaceable>ID</replaceable></optional></term>
 
         <listitem><para>Activate a session. This brings a session into
-        the foreground, if another session is currently in the
+        the foreground if another session is currently in the
         foreground on the respective seat. Takes a session identifier
-        as argument. If no argument is specified the session of the
+        as argument. If no argument is specified, the session of the
         caller is put into foreground.</para></listitem>
       </varlistentry>
 
         <listitem><para>Activates/deactivates the screen lock on one
         or more sessions, if the session supports it. Takes one or
         more session identifiers as arguments. If no argument is
-        specified the session of the caller is locked/unlocked.
+        specified, the session of the caller is locked/unlocked.
         </para></listitem>
       </varlistentry>
 
         <listitem><para>Show terse runtime status information about
         one or more logged in users, followed by the most recent log
         data from the journal. Takes one or more user names or numeric
-        user IDs as parameters. If no parameters are passed the status
+        user IDs as parameters. If no parameters are passed, the status
         of the caller's user is shown. This function is intended to
         generate human-readable output. If you are looking for
         computer-parsable output, use <command>show-user</command>
         spawned for the user at boot and kept around after logouts.
         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
+        argument. If no argument is specified, enables/disables
         lingering for the user of the session of the caller.
         </para></listitem>
       </varlistentry>
         seat. The devices should be specified via device paths in the
         <filename>/sys</filename> file system. To create a new seat,
         attach at least one graphics card to a previously unused seat
-        name. Seat names may consist only of a-z, A-Z, 0-9,
+        name. Seat names may consist only of a–z, A–Z, 0–9,
         <literal>-</literal> and <literal>_</literal> and must be
         prefixed with <literal>seat</literal>. To drop assignment of a
         device to a specific seat, just reassign it to a different
index 2b79547275caf7f2b470d1113d807f0a7d552e5c..43d1ffbd3cf75cdb24645af1f1fe5358a4783afb 100644 (file)
 
         <listitem><para>Specifies the timeout after system startup or
         system resume in which systemd will hold off on reacting to
-        LID events. This is required for the system to properly
-        detect any hotplugged devices so systemd can ignore LID events
+        lid events. This is required for the system to properly
+        detect any hotplugged devices so systemd can ignore lid events
         if external monitors, or docks, are connected. If set to 0,
         systemd will always react immediately, possibly before the
         kernel fully probed all hotplugged devices. This is safe, as
index 916f1dab663882be2813167696e9e9cd848c0739..351133670b9d49fead01f8be07c6c6f99230e024 100644 (file)
         <literal>tablet</literal>,
         <literal>handset</literal>,
         <literal>watch</literal>, and
-        <literal>embedded</literal>
+        <literal>embedded</literal>,
         as well as the special chassis types
         <literal>vm</literal> and
         <literal>container</literal> for
index e2be01742712dfc72eea29f00c9217e9c61c5d28..0e18953700396d99846c40b18aa4aef624628e20 100644 (file)
@@ -83,9 +83,9 @@
     </itemizedlist>
 
     <para>Machines are identified by names that follow the same rules
-    as UNIX and DNS host names, for details see below. Machines are
-    instantiated from disk or file system images, that frequently but not
-    necessarily carry the same name as machines running from
+    as UNIX and DNS host names, for details, see below. Machines are
+    instantiated from disk or file system images that frequently — but not
+    necessarily — carry the same name as machines running from
     them. Images in this sense are considered:</para>
 
     <itemizedlist>
       <varlistentry>
         <term><option>--mkdir</option></term>
 
-        <listitem><para>When used with <command>bind</command> creates
+        <listitem><para>When used with <command>bind</command>, creates
         the destination directory before applying the bind
         mount.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><option>--read-only</option></term>
 
-        <listitem><para>When used with <command>bind</command> applies
+        <listitem><para>When used with <command>bind</command>, applies
         a read-only bind mount.</para></listitem>
       </varlistentry>
 
         specify whether the image shall be verified before it is made
         available. Takes one of <literal>no</literal>,
         <literal>checksum</literal> and <literal>signature</literal>.
-        If <literal>no</literal> no verification is done. If
-        <literal>checksum</literal> is specified the download is
-        checked for integrity after transfer is complete, but no
+        If <literal>no</literal>, no verification is done. If
+        <literal>checksum</literal> is specified, the download is
+        checked for integrity after the transfer is complete, but no
         signatures are verified. If <literal>signature</literal> is
         specified, the checksum is verified and the images's signature
         is checked against a local keyring of trustable vendors. It is
         <term><option>--format=</option></term>
 
         <listitem><para>When used with the <option>export-tar</option>
-        or <option>export-raw</option> commands specifies the
+        or <option>export-raw</option> commands, specifies the
         compression format to use for the resulting file. Takes one of
         <literal>uncompressed</literal>, <literal>xz</literal>,
-        <literal>gzip</literal>, <literal>bzip2</literal>. By default
+        <literal>gzip</literal>, <literal>bzip2</literal>. By default,
         the format is determined automatically from the image file
         name passed.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><command>status</command> <replaceable>NAME</replaceable>...</term>
 
-        <listitem><para>Show terse runtime status information about
+        <listitem><para>Show runtime status information about
         one or more virtual machines and containers, followed by the
         most recent log data from the journal. This function is
         intended to generate human-readable output. If you are looking
         are suppressed. Use <option>--all</option> to show those too.
         To select specific properties to show, use
         <option>--property=</option>. This command is intended to be
-        used whenever computer-parsable output is required. Use
+        used whenever computer-parsable output is required, and does
+        not print the cgroup tree or journal entries. Use
         <command>status</command> if you are looking for formatted
         human-readable output.</para></listitem>
       </varlistentry>
         image by the specified name in
         <filename>/var/lib/machines/</filename> (and other search
         paths, see below) and runs it. Use
-        <command>list-images</command> (see below), for listing
+        <command>list-images</command> (see below) for listing
         available container images to start.</para>
 
         <para>Note that
         <term><command>login</command> [<replaceable>NAME</replaceable>]</term>
 
         <listitem><para>Open an interactive terminal login session in
-        a container or on the local host. If an argument is supplied
+        a container or on the local host. If an argument is supplied,
         it refers to the container machine to connect to. If none is
         specified, or the container name is specified as the empty
         string, or the special machine name <literal>.host</literal>
         instead. This works similar to <command>login</command> but
         immediately invokes a user process. This command runs the
         specified executable with the specified arguments, or
-        <filename>/bin/sh</filename> if none is specified. By default
+        <filename>/bin/sh</filename> if none is specified. By default,
         opens a <literal>root</literal> shell, but by using
         <option>--uid=</option>, or by prefixing the machine name with
         a username and an <literal>@</literal> character, a different
         environment variables for the executed process.</para>
 
         <para>When using the <command>shell</command> command without
-        arguments (thus invoking the executed shell or command on the
-        local host) it is similar in many ways to a <citerefentry
+        arguments, (thus invoking the executed shell or command on the
+        local host), it is in many ways similar to a <citerefentry
         project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-        session, but unlike <command>su</command> completely isolates
+        session, but, unlike <command>su</command>, completely isolates
         the new session from the originating session, so that it
         shares no process or session properties, and is in a clean and
         well-defined state. It will be tracked in a new utmp, login,
         environment variables or resource limits, among other
         properties.</para>
 
-        <para>Note that the
+        <para>Note that
         <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         may be used in place of the <command>shell</command> command,
         and allows more detailed, low-level configuration of the
         specified container. The first directory argument is the
         source directory on the host, the second directory argument
         is the destination directory in the container. When the
-        latter is omitted the destination path in the container is
+        latter is omitted, the destination path in the container is
         the same as the source path on the host. When combined with
-        the <option>--read-only</option> switch a ready-only bind
+        the <option>--read-only</option> switch, a ready-only bind
         mount is created. When combined with the
-        <option>--mkdir</option> switch the destination path is first
+        <option>--mkdir</option> switch, the destination path is first
         created before the mount is applied. Note that this option is
         currently only supported for
         <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         <listitem><para>Copies files or directories from the host
         system into a running container. Takes a container name,
         followed by the source path on the host and the destination
-        path in the container. If the destination path is omitted the
+        path in the container. If the destination path is omitted, the
         same as the source path is used.</para></listitem>
       </varlistentry>
 
         <listitem><para>Copies files or directories from a container
         into the host system. Takes a container name, followed by the
         source path in the container the destination path on the host.
-        If the destination path is omitted the same as the source path
+        If the destination path is omitted, the same as the source path
         is used.</para></listitem>
       </varlistentry>
     </variablelist></refsect2>
         directories and subvolumes in
         <filename>/var/lib/machines/</filename> (and other search
         paths, see below). Use <command>start</command> (see above) to
-        run a container off one of the listed images. Note that by
-        default containers whose name begins with a dot
+        run a container off one of the listed images. Note that, by
+        default, containers whose name begins with a dot
         (<literal>.</literal>) are not shown. To show these too,
         specify <option>--all</option>. Note that a special image
         <literal>.host</literal> always implicitly exists and refers
 
         <listitem><para>Removes one or more container or VM images.
         The special image <literal>.host</literal>, which refers to
-        the host's own directory tree may not be
+        the host's own directory tree, may not be
         removed.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><command>set-limit</command> [<replaceable>NAME</replaceable>] <replaceable>BYTES</replaceable></term>
 
-        <listitem><para>Sets the maximum size in bytes a specific
-        container or VM image, or all images may grow up to on disk
+        <listitem><para>Sets the maximum size in bytes that a specific
+        container or VM image, or all images, may grow up to on disk
         (disk quota). Takes either one or two parameters. The first,
         optional parameter refers to a container or VM image name. If
-        specified the size limit of the specified image is changed. If
-        omitted the overall size limit of the sum of all images stored
+        specified, the size limit of the specified image is changed. If
+        omitted, the overall size limit of the sum of all images stored
         locally is changed. The final argument specifies the size
         limit in bytes, possibly suffixed by the usual K, M, G, T
         units. If the size limit shall be disabled, specify
         <literal>-</literal> as size.</para>
 
         <para>Note that per-container size limits are only supported
-        on btrfs file systems. Also note that if
-        <command>set-limit</command> is invoked without image
+        on btrfs file systems. Also note that, if
+        <command>set-limit</command> is invoked without an image
         parameter, and <filename>/var/lib/machines</filename> is
         empty, and the directory is not located on btrfs, a btrfs
         loopback file is implicitly created as
         loopback may later be readjusted with
         <command>set-limit</command>, as well. If such a
         loopback-mounted <filename>/var/lib/machines</filename>
-        directory is used <command>set-limit</command> without image
+        directory is used, <command>set-limit</command> without an image
         name alters both the quota setting within the file system as
         well as the loopback file and file system size
         itself.</para></listitem>
         <literal>https://</literal>, and must refer to a
         <filename>.tar</filename>, <filename>.tar.gz</filename>,
         <filename>.tar.xz</filename> or <filename>.tar.bz2</filename>
-        archive file. If the local machine name is omitted it
+        archive file. If the local machine name is omitted, it
         is automatically derived from the last component of the URL,
         with its suffix removed.</para>
 
         <para>The image is verified before it is made available,
         unless <option>--verify=no</option> is specified. Verification
-        is done via SHA256SUMS and SHA256SUMS.gpg files, that need to
+        is done via SHA256SUMS and SHA256SUMS.gpg files that need to
         be made available on the same web server, under the same URL
         as the <filename>.tar</filename> file, but with the last
         component (the filename) of the URL replaced. With
-        <option>--verify=checksum</option> only the SHA256 checksum
+        <option>--verify=checksum</option>, only the SHA256 checksum
         for the file is verified, based on the
         <filename>SHA256SUMS</filename> file. With
-        <option>--verify=signature</option> the SHA256SUMS file is
+        <option>--verify=signature</option>, the SHA256SUMS file is
         first verified with detached GPG signature file
         <filename>SHA256SUMS.gpg</filename>. The public key for this
         verification step needs to be available in
 
         <para>The container image will be downloaded and stored in a
         read-only subvolume in
-        <filename>/var/lib/machines/</filename>, that is named after
+        <filename>/var/lib/machines/</filename> that is named after
         the specified URL and its HTTP etag. A writable snapshot is
         then taken from this subvolume, and named after the specified
         local name. This behavior ensures that creating multiple
         be a <filename>.qcow2</filename> or raw disk image, optionally
         compressed as <filename>.gz</filename>,
         <filename>.xz</filename>, or <filename>.bz2</filename>. If the
-        local machine name is omitted it is automatically
+        local machine name is omitted, it is automatically
         derived from the last component of the URL, with its suffix
         removed.</para>
 
         <listitem><para>Imports a TAR or RAW container or VM image,
         and places it under the specified name in
         <filename>/var/lib/machines/</filename>. When
-        <command>import-tar</command> is used the file specified as
-        first argument should be a tar archive, possibly compressed
+        <command>import-tar</command> is used, the file specified as
+        the first argument should be a tar archive, possibly compressed
         with xz, gzip or bzip2. It will then be unpacked into its own
         subvolume in <filename>/var/lib/machines</filename>. When
-        <command>import-raw</command> is used the file should be a
+        <command>import-raw</command> is used, the file should be a
         qcow2 or raw disk image, possibly compressed with xz, gzip or
         bzip2. If the second argument (the resulting image name) is
-        not specified it is automatically derived from the file
-        name. If the file name is passed as <literal>-</literal> the
+        not specified, it is automatically derived from the file
+        name. If the file name is passed as <literal>-</literal>, the
         image is read from standard input, in which case the second
         argument is mandatory.</para>
 
         <para>Similar as with <command>pull-tar</command>,
         <command>pull-raw</command> the file system
         <filename>/var/lib/machines.raw</filename> is increased in
-        size of necessary and appropriate. Optionally the
+        size of necessary and appropriate. Optionally, the
         <option>--read-only</option> switch may be used to create a
         read-only container or VM image. No cryptographic validation
         is done when importing the images.</para>
         stores it in the specified file. The first parameter should be
         a VM or container image name. The second parameter should be a
         file path the TAR or RAW image is written to. If the path ends
-        in <literal>.gz</literal> the file is compressed with gzip, if
-        it ends in <literal>.xz</literal> with xz, and if it ends in
-        <literal>.bz2</literal> with bzip2. If the path ends in
-        neither the file is left uncompressed. If the second argument
-        is missing the image is written to standard output. The
+        in <literal>.gz</literal>, the file is compressed with gzip, if
+        it ends in <literal>.xz</literal>, with xz, and if it ends in
+        <literal>.bz2</literal>, with bzip2. If the path ends in
+        neither, the file is left uncompressed. If the second argument
+        is missing, the image is written to standard output. The
         compression may also be explicitly selected with the
         <option>--format=</option> switch. This is in particular
         useful if the second parameter is left unspecified.</para>
         aborted with
         <command>cancel-transfer</command>.</para>
 
-        <para>Note that currently only directory and subvolume images
+        <para>Note that, currently, only directory and subvolume images
         may be exported as TAR images, and only raw disk images as RAW
         images.</para></listitem>
       </varlistentry>
     <title>Machine and Image Names</title>
 
     <para>The <command>machinectl</command> tool operates on machines
-    and images, whose names must be chosen following strict
+    and images whose names must be chosen following strict
     rules. Machine names must be suitable for use as host names
     following a conservative subset of DNS and UNIX/Linux
     semantics. Specifically, they must consist of one or more
     non-empty label strings, separated by dots. No leading or trailing
     dots are allowed. No sequences of multiple dots are allowed. The
-    label strings may only consists of alphanumeric characters as well
+    label strings may only consist of alphanumeric characters as well
     as the dash and underscore. The maximum length of a machine name
     is 64 characters.</para>
 
     <para>A special machine with the name <literal>.host</literal>
     refers to the running host system itself. This is useful for execution
-    operations or inspecting the host system as well. Not that
+    operations or inspecting the host system as well. Note that
     <command>machinectl list</command> will not show this special
     machine unless the <option>--all</option> switch is specified.</para>
 
-    <para>Requirements on image names are less strict, however must be
+    <para>Requirements on image names are less strict, however, they must be
     valid UTF-8, must be suitable as file names (hence not be the
     single or double dot, and not include a slash), and may not
     contain control characters. Since many operations search for an
-    image by the name of a requested machine it is recommended to name
+    image by the name of a requested machine, it is recommended to name
     images in the same strict fashion as machines.</para>
 
     <para>A special image with the name <literal>.host</literal>
-    refers to the image of the running host system. It is hence
+    refers to the image of the running host system. It hence
     conceptually maps to the special <literal>.host</literal> machine
     name described above. Note that <command>machinectl
-    list-images</command> won't show this special image either, unless
+    list-images</command> will not show this special image either, unless
     <option>--all</option> is specified.</para>
   </refsect1>
 
     <para>Machine images are preferably stored in
     <filename>/var/lib/machines/</filename>, but are also searched for
     in <filename>/usr/local/lib/machines/</filename> and
-    <filename>/usr/lib/machines/</filename>. For compatibility reasons
+    <filename>/usr/lib/machines/</filename>. For compatibility reasons,
     the directory <filename>/var/lib/container/</filename> is
     searched, too. Note that images stored below
     <filename>/usr</filename> are always considered read-only. It is
       <listitem><para>A simple directory tree, containing the files
       and directories of the container to boot.</para></listitem>
 
-      <listitem><para>A subvolume (on btrfs file systems), which are
+      <listitem><para>Subvolumes (on btrfs file systems), which are
       similar to the simple directories, described above. However,
       they have additional benefits, such as efficient cloning and
       quota reporting.</para></listitem>
 
     <para>See
     <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    for more information on image formats, in particular it's
+    for more information on image formats, in particular its
     <option>--directory=</option> and <option>--image=</option>
     options.</para>
   </refsect1>
 # machinectl login Fedora-Cloud-Base-20141203-21</programlisting>
 
       <para>This downloads the specified <filename>.raw</filename>
-      image with verification disabled. Then a shell is opened in it
+      image with verification disabled. Then, a shell is opened in it
       and a root password is set. Afterwards the shell is left, and
       the machine started as system service. With the last command a
       login prompt into the container is requested.</para>
 
       <programlisting># machinectl export-tar fedora myfedora.tar.xz</programlisting>
 
-      <para>Exports the container <literal>fedora</literal> in an
-      xz-compress tar file <filename>myfedora.tar.xz</filename> in the
+      <para>Exports the container <literal>fedora</literal> as an
+      xz-compressed tar file <filename>myfedora.tar.xz</filename> into the
       current directory.</para>
     </example>
 
 
       <programlisting># machinectl shell --uid=lennart</programlisting>
 
-      <para>This creates a new shell session on the local host, for
+      <para>This creates a new shell session on the local host for
       the user ID <literal>lennart</literal>, in a <citerefentry
       project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>-like
       fashion.</para>
index 46dab58d612d0077ba3b66c56b74bc099f7ecb43..c688714b307ca653dc03964b60ae7b729ac4b08b 100644 (file)
@@ -129,7 +129,7 @@ IDX LINK         TYPE     OPERATIONAL SETUP
           configured DNS servers, etc.</para>
 
           <para>When no links are specified, routable links are
-          shown. See also option <option>--all</option>.</para>
+          shown. Also see the option <option>--all</option>.</para>
 
           <para>Produces output similar to
           <programlisting>
index 4481fdf8cb8aa4b77dc381ff4cac0b6b1fca0b1a..859bec29e3ec5dc0fe7dc895da7558cc0debab81 100644 (file)
@@ -59,7 +59,7 @@
 
     <para><command>nss-myhostname</command> is a plugin for the GNU
     Name Service Switch (NSS) functionality of the GNU C Library
-    (<command>glibc</command>) primarily providing hostname resolution
+    (<command>glibc</command>), primarily providing hostname resolution
     for the locally configured system hostname as returned by
     <citerefentry><refentrytitle>gethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
     The precise hostnames resolved by this module are:</para>
@@ -89,9 +89,9 @@
     time as changing the hostname. This is problematic since it
     requires a writable <filename>/etc</filename> file system and is
     fragile because the file might be edited by the administrator at
-    the same time. With <command>nss-myhostname</command> enabled
+    the same time. With <command>nss-myhostname</command> enabled,
     changing <filename>/etc/hosts</filename> is unnecessary, and on
-    many systems the file becomes entirely optional.</para>
+    many systems, the file becomes entirely optional.</para>
 
     <para>To activate the NSS modules, <literal>myhostname</literal>
     has to be added to the line starting with
 
     <para>It is recommended to place <literal>myhostname</literal>
     last in the <filename>nsswitch.conf</filename> line to make sure
-    that this mapping is only used as fallback, and any DNS or
+    that this mapping is only used as fallback, and that any DNS or
     <filename>/etc/hosts</filename> based mapping takes
     precedence.</para>
   </refsect1>
   <refsect1>
     <title>Example</title>
 
-    <para>Here's an example <filename>/etc/nsswitch.conf</filename>
-    file, that enables <command>myhostname</command> correctly:</para>
+    <para>Here is an example <filename>/etc/nsswitch.conf</filename>
+    file that enables <command>myhostname</command> correctly:</para>
 
 <programlisting>passwd:         compat mymachines
 group:          compat mymachines
@@ -135,7 +135,7 @@ netgroup:       nis</programlisting>
 127.0.0.2       DGRAM
 127.0.0.2       RAW</programlisting>
 
-    <para>In this case the local hostname is <varname>omega</varname>.</para>
+    <para>In this case, the local hostname is <varname>omega</varname>.</para>
 
   </refsect1>
 
index 92c72846c177431a5051dfd8714343a0859e6359..d2bec763bb600e50237c0c0390a48f27f42099a1 100644 (file)
@@ -58,8 +58,8 @@
 
     <para><command>nss-mymachines</command> is a plugin for the GNU
     Name Service Switch (NSS) functionality of the GNU C Library
-    (<command>glibc</command>) providing hostname resolution for
-    container names of containers running locally, that are registered
+    (<command>glibc</command>), providing hostname resolution for
+    container names of containers running locally that are registered
     with
     <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
     The container names are resolved to the IP addresses of the
 
     <para>It is recommended to place <literal>mymachines</literal>
     near the end of the <filename>nsswitch.conf</filename> lines to
-    make sure that its mappings are only used as fallback, and any
+    make sure that its mappings are only used as fallback, and that any
     other mappings, such as DNS or <filename>/etc/hosts</filename>
-    based mappings take precedence.</para>
+    based mappings, take precedence.</para>
   </refsect1>
 
   <refsect1>
     <title>Example</title>
 
-    <para>Here's an example <filename>/etc/nsswitch.conf</filename>
-    file, that enables <command>mymachines</command> correctly:</para>
+    <para>Here is an example <filename>/etc/nsswitch.conf</filename>
+    file that enables <command>mymachines</command> correctly:</para>
 
     <programlisting>passwd:         compat <command>mymachines</command>
 group:          compat <command>mymachines</command>
index 7d291b83c19908746fb08151ac53e47db1b7ca6c..8b0928145f0efa30d856c678fe2eaf1edeb9c489 100644 (file)
@@ -79,8 +79,8 @@
   <refsect1>
     <title>Example</title>
 
-    <para>Here's an example <filename>/etc/nsswitch.conf</filename>
-    file, that enables <command>resolve</command> correctly:</para>
+    <para>Here is an example <filename>/etc/nsswitch.conf</filename>
+    file that enables <command>resolve</command> correctly:</para>
 
 <programlisting>passwd:         compat mymachines
 group:          compat mymachines
index d2e2598204df7a08e213fe22b518763c54960f17..4557abc4a32a620d7fd3561a2519fccd9b3f991c 100644 (file)
@@ -67,7 +67,7 @@
     without implementing a shell compatible execution engine. Variable
     assignment values must be enclosed in double or single quotes if
     they include spaces, semicolons or other special characters
-    outside of A-Z, a-z, 0-9. Shell special characters ("$", quotes,
+    outside of A–Z, a–z, 0–9. Shell special characters ("$", quotes,
     backslash, backtick) must be escaped with backslashes, following
     shell style. All strings should be in UTF-8 format, and
     non-printable characters should not be used. It is not supported
         <term><varname>ID=</varname></term>
 
         <listitem><para>A lower-case string (no spaces or other
-        characters outside of 0-9, a-z, ".", "_" and "-") identifying
+        characters outside of 0–9, a–z, ".", "_" and "-") identifying
         the operating system, excluding any version information and
         suitable for processing by scripts or usage in generated
         filenames. If not set, defaults to
         <term><varname>VERSION_ID=</varname></term>
 
         <listitem><para>A lower-case string (mostly numeric, no spaces
-        or other characters outside of 0-9, a-z, ".", "_" and "-")
+        or other characters outside of 0–9, a–z, ".", "_" and "-")
         identifying the operating system version, excluding any OS
         name information or release code name, and suitable for
         processing by scripts or usage in generated filenames. This
 
         <listitem><para>
         A lower-case string (no spaces or other characters outside of
-        0-9, a-z, ".", "_" and "-"), identifying a specific variant or
+        0–9, a–z, ".", "_" and "-"), identifying a specific variant or
         edition of the operating system. This may be interpreted by
         other packages in order to determine a divergent default
         configuration. This field is optional and may not be
index b4a3f502b443389d1db889d45347494e4c4c00d8..ddda81bc90b5b576694c3a36e0a51d8b2134260e 100644 (file)
         as <constant>AF_UNIX</constant> sockets, FIFOs, PID files and
         similar. It is guaranteed that this directory is local and
         offers the greatest possible file system feature set the
-        operating system provides. For further details see the <ulink
+        operating system provides. For further details, see the <ulink
         url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG
         Base Directory Specification</ulink>.</para></listitem>
       </varlistentry>
index 8047a4ea750a00dbf16ac0b797f4f339401028ae..811e33f4fa4370dd2b242b09ca580cad02e9aa88 100644 (file)
@@ -59,7 +59,7 @@
     <title>Description</title>
 
     <para>These configuration files control local DNS and LLMNR
-    name resolving.</para>
+    name resolution.</para>
 
   </refsect1>
 
 
       <varlistentry>
         <term><varname>DNS=</varname></term>
-        <listitem><para>A space separated list of IPv4 and IPv6
+        <listitem><para>A space-separated list of IPv4 and IPv6
         addresses to be used as system DNS servers. DNS requests are
         sent to one of the listed DNS servers in parallel to any
         per-interface DNS servers acquired from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-        For compatibility reasons, if set to the empty list the DNS
+        For compatibility reasons, if set to the empty list, the DNS
         servers listed in <filename>/etc/resolv.conf</filename> are
         used, if any are configured there. This setting defaults to
         the empty list.</para></listitem>
@@ -85,7 +85,7 @@
 
       <varlistentry>
         <term><varname>FallbackDNS=</varname></term>
-        <listitem><para>A space separated list of IPv4 and IPv6
+        <listitem><para>A space-separated list of IPv4 and IPv6
         addresses to be used as the fallback DNS servers. Any
         per-interface DNS servers obtained from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         <literal>resolve</literal>. Controls Link-Local Multicast Name
         Resolution support (<ulink
         url="https://tools.ietf.org/html/rfc4795">RFC 4794</ulink>) on
-        the local host. If true enables full LLMNR responder and
-        resolver support. If false disable both. If set to
-        <literal>resolve</literal> only resolving support is enabled,
+        the local host. If true, enables full LLMNR responder and
+        resolver support. If false, disables both. If set to
+        <literal>resolve</literal>, only resolution support is enabled,
         but responding is disabled. Note that
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         also maintains per-interface LLMNR settings. LLMNR will be
index fc1f52385519f82babf569807b70f27ada153259..ca29c7c22cd8705a414fd467481351f7673f0755 100644 (file)
 
   <refsynopsisdiv>
     <cmdsynopsis>
-      <command>runlevel <arg choice="opt" rep="repeat">options</arg></command>
+      <command>runlevel</command>
+      <arg choice="opt" rep="repeat">options</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
 
+  <refsect1>
+    <title>Overview</title>
+
+    <para>"Runlevels" are an obsolete way to start and stop groups of
+    services used in SysV init. systemd provides a compatibility layer
+    that maps runlevels to targets, and associated binaries like
+    <command>runlevel</command>. Nevertheless, only one runlevel can
+    be "active" at a given time, while systemd can activate multiple
+    targets concurrently, so the mapping to runlevels is confusing
+    and only approximate. Runlevels should not be used in new code,
+    and are mostly useful as a shorthand way to refer the matching
+    systemd targets in kernel boot parameters.</para>
+
+    <table>
+      <title>Mapping between runlevels and systemd targets</title>
+      <tgroup cols='2' align='left' colsep='1' rowsep='1'>
+        <colspec colname="runlevel" />
+        <colspec colname="target" />
+        <thead>
+          <row>
+            <entry>Runlevel</entry>
+            <entry>Target</entry>
+          </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry>0</entry>
+            <entry><filename>poweroff.target</filename></entry>
+          </row>
+          <row>
+            <entry>1</entry>
+            <entry><filename>rescue.target</filename></entry>
+          </row>
+          <row>
+            <entry>2, 3, 4</entry>
+            <entry><filename>multi-user.target</filename></entry>
+          </row>
+          <row>
+            <entry>5</entry>
+            <entry><filename>graphical.target</filename></entry>
+          </row>
+          <row>
+            <entry>6</entry>
+            <entry><filename>reboot.target</filename></entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
   <refsect1>
     <title>Description</title>
 
     </variablelist>
   </refsect1>
 
-  <refsect1>
-    <title>Notes</title>
-
-    <para>This is a legacy command available for compatibility only.
-    It should not be used anymore, as the concept of runlevels is
-    obsolete.</para>
-  </refsect1>
-
   <refsect1>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
index a1e8462858a2d2263421fb6a8f6d91780d6a95a2..055af7a6822ff64e877f521467bf5f049d1cdcd6 100644 (file)
     <title>Description</title>
 
     <para>In addition to the error names user programs define, D-Bus
-    knows a number of generic, standardized error names, that are
+    knows a number of generic, standardized error names that are
     listed below.</para>
 
-    <para>In addition to this list, in sd-bus the special error
+    <para>In addition to this list, in sd-bus, the special error
     namespace <literal>System.Error.</literal> is used to map
     arbitrary Linux system errors (as defined by <citerefentry
     project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
       <varlistentry>
         <term><varname>SD_BUS_ERROR_IO_ERROR</varname></term>
         <listitem><para>Generic input/output error, for example when
-        accessing a socket or other IO context.</para></listitem>
+        accessing a socket or other I/O context.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_BAD_ADDRESS</varname></term>
       </varlistentry>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_ACCESS_DENIED</varname></term>
-        <listitem><para>Access to a resource has been denied, due to security restrictions.</para></listitem>
+        <listitem><para>Access to a resource has been denied due to security restrictions.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_AUTH_FAILED</varname></term>
       </varlistentry>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_FILE_EXISTS</varname></term>
-        <listitem><para>The requested file exists already.</para></listitem>
+        <listitem><para>The requested file already exists.</para></listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_UNKNOWN_METHOD</varname></term>
       <varlistentry>
         <term><varname>SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED</varname></term>
         <listitem><para>Access to the requested operation is not
-        permitted, however, it might be available after interactive
+        permitted. However, it might be available after interactive
         authentication. This is usually returned by method calls
         supporting a framework for additional interactive
         authorization, when interactive authorization was not enabled
index 4162fab0650b74b77c360df97b14366bab245a10..aec12bda164246338bb653f0eb0a5dec84b88376 100644 (file)
     to determine the mask of fields available.</para>
 
     <para><function>sd_bus_creds_get_pid()</function> will retrieve
-    the PID (process identifier). Similar,
+    the PID (process identifier). Similarly,
     <function>sd_bus_creds_get_ppid()</function> will retrieve the
     parent PID. Note that PID 1 has no parent process, in which case
     -ENXIO is returned.</para>
     TID (thread identifier).</para>
 
     <para><function>sd_bus_creds_get_uid()</function> will retrieve
-    the numeric UID (user identifier). Similar,
+    the numeric UID (user identifier). Similarly,
     <function>sd_bus_creds_get_euid()</function> returns the effective
     UID, <function>sd_bus_creds_get_suid()</function> the saved UID
     and <function>sd_bus_creds_get_fsuid()</function> the file system
     UID.</para>
 
     <para><function>sd_bus_creds_get_gid()</function> will retrieve the
-    numeric GID (group identifier). Similar,
+    numeric GID (group identifier). Similarly,
     <function>sd_bus_creds_get_egid()</function> returns the effective
     GID, <function>sd_bus_creds_get_sgid()</function> the saved GID
     and <function>sd_bus_creds_get_fsgid()</function> the file system
     <para><function>sd_bus_creds_get_exe()</function> will retrieve
     the path to the program executable (as stored in the
     <filename>/proc/<replaceable>pid</replaceable>/exe</filename>
-    link, but with <literal> (deleted)</literal> suffix removed). Note
+    link, but with the <literal> (deleted)</literal> suffix removed). Note
     that kernel threads do not have an executable path, in which case
     -ENXIO is returned.</para>
 
 
     <para><function>sd_bus_creds_get_unit()</function> will retrieve
     the systemd unit name (in the system instance of systemd) that the
-    process is part of. See
+    process is part of. See
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
-    processes that are not part of a unit returns -ENXIO.
+    processes that are not part of a unit, returns -ENXIO.
     </para>
 
     <para><function>sd_bus_creds_get_user_unit()</function> will
     retrieve the systemd unit name (in the user instance of systemd)
-    that the process is part of. See
+    that the process is part of. See
     <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For
-    processes that are not part of a user unit returns -ENXIO.
+    processes that are not part of a user unit, returns -ENXIO.
     </para>
 
     <para><function>sd_bus_creds_get_slice()</function> will retrieve
     the systemd slice (a unit in the system instance of systemd) that
-    the process is part of. See
-    <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Similar,
+    the process is part of. See
+    <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Similarly,
     <function>sd_bus_creds_get_user_slice()</function> retrieves the
     systemd slice of the process, in the user instance of systemd.
     </para>
 
     <para><function>sd_bus_creds_get_session()</function> will
     retrieve the identifier of the login session that the process is
-    part of. See
+    part of. See
     <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. For
-    processes that are not part of a session returns -ENXIO.
+    processes that are not part of a session, returns -ENXIO.
     </para>
 
     <para><function>sd_bus_creds_get_owner_uid()</function> will
     retrieve the numeric UID (user identifier) of the user who owns
-    the login session that the process is part of. See
+    the login session that the process is part of. See
     <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-    For processes that are not part of a session returns -ENXIO.
+    For processes that are not part of a session, returns -ENXIO.
     </para>
 
     <para><function>sd_bus_creds_has_effective_cap()</function> will
       <varlistentry>
         <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>Given field is not available in the
+        <listitem><para>The given field is not available in the
         credentials object <parameter>c</parameter>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>Given field is not specified for the described
+        <listitem><para>The given field is not specified for the described
         process or peer. This will be returned by
         <function>sd_bus_get_unit()</function>,
         <function>sd_bus_get_slice()</function>,
         slice, or logind session. It will also be returned by
         <function>sd_bus_creds_get_exe()</function> and
         <function>sd_bus_creds_get_cmdline()</function> for kernel
-        threads (since these aren't started from an executable binary
-        or have a command line),
+        threads (since these are not started from an executable binary,
+        nor have a command line), and by
         <function>sd_bus_creds_get_audit_session_id()</function> and
         <function>sd_bus_creds_get_audit_login_uid()</function> when
         the process is not part of an audit session, and
index a78d3f5717a91d04aadb4655737322ed091d7195..84dd509744360a78d8d4a54d05b5c66b514d86f0 100644 (file)
     <para><function>sd_bus_creds_new_from_pid()</function> creates a
     new credentials object and fills it with information about the
     process <parameter>pid</parameter>. The pointer to this object
-    will be stored in <parameter>ret</parameter> pointer. Note that
+    will be stored in the <parameter>ret</parameter> pointer. Note that
     credential objects may also be created and retrieved via
     <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     <constant>SD_BUS_CREDS_AUDIT_LOGIN_UID</constant>,
     <constant>SD_BUS_CREDS_TTY</constant>,
     <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>,
-    <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>,
+    <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>, and
     <constant>SD_BUS_CREDS_DESCRIPTION</constant>. Use the special
     value <constant>_SD_BUS_CREDS_ALL</constant> to request all
     supported fields. The <constant>SD_BUS_CREDS_AUGMENT</constant>
-    may not be ORed into the mask for invocations of
+    constant may not be ORed into the mask for invocations of
     <function>sd_bus_creds_new_from_pid()</function>.</para>
 
     <para>Fields can be retrieved from the credentials object using
     subset of fields requested in <parameter>creds_mask</parameter>.
     </para>
 
-    <para>Similar to <function>sd_bus_creds_get_mask()</function> the
+    <para>Similar to <function>sd_bus_creds_get_mask()</function>, the
     function <function>sd_bus_creds_get_augmented_mask()</function>
     returns a bitmask of field constants. The mask indicates which
     credential fields have been retrieved in a non-atomic fashion. For
     credential objects created via
-    <function>sd_bus_creds_new_from_pid()</function> this mask will be
+    <function>sd_bus_creds_new_from_pid()</function>, this mask will be
     identical to the mask returned by
     <function>sd_bus_creds_get_mask()</function>. However, for
     credential objects retrieved via
-    <function>sd_bus_get_name_creds()</function> this mask will be set
+    <function>sd_bus_get_name_creds()</function>, this mask will be set
     for the credential fields that could not be determined atomically
     at peer connection time, and which were later added by reading
     augmenting credential data from
-    <filename>/proc</filename>. Similar, for credential objects
-    retrieved via <function>sd_bus_get_owner_creds()</function> the
+    <filename>/proc</filename>. Similarly, for credential objects
+    retrieved via <function>sd_bus_get_owner_creds()</function>, the
     mask is set for the fields that could not be determined atomically
-    at bus creation time, but have been augmented. Similar, for
+    at bus creation time, but have been augmented. Similarly, for
     credential objects retrieved via
-    <function>sd_bus_message_get_creds()</function> the mask is set
+    <function>sd_bus_message_get_creds()</function>, the mask is set
     for the fields that could not be determined atomically at message
-    send time, but have been augmented. The mask returned by
+    sending time, but have been augmented. The mask returned by
     <function>sd_bus_creds_get_augmented_mask()</function> is always a
     subset of (or identical to) the mask returned by
     <function>sd_bus_creds_get_mask()</function> for the same
     object. The latter call hence returns all credential fields
     available in the credential object, the former then marks the
     subset of those that have been augmented. Note that augmented
-    fields are unsuitable for authorization decisions as they may be
-    retrieved at different times, thus being subject to races. Hence
+    fields are unsuitable for authorization decisions, as they may be
+    retrieved at different times, thus being subject to races. Hence,
     augmented fields should be used exclusively for informational
     purposes.
     </para>
index 1cf2cb8f9ae77d08efa84a4e31bdfef3a4197218..6d5a90de72fa2c27756dbc5273db31813f23a5ee 100644 (file)
     connection object to the user bus when invoked in user context, or
     to the system bus otherwise. The connection object is associated
     with the calling thread. Each time the function is invoked from
-    the same thread the same object is returned, but its reference
+    the same thread, the same object is returned, but its reference
     count is increased by one, as long as at least one reference is
     kept. When the last reference to the connection is dropped (using
     the
     call), the connection is terminated. Note that the connection is
     not automatically terminated when the associated thread ends. It
     is important to drop the last reference to the bus connection
-    explicitly before the thread ends or otherwise the connection will
-    be leaked. Also, queued but unread or unwritten messages keep the
+    explicitly before the thread ends, as otherwise, the connection will
+    leak. Also, queued but unread or unwritten messages keep the
     bus referenced, see below.</para>
 
     <para><function>sd_bus_default_user()</function> returns a user
     <function>sd_bus_open_system()</function> does the same, but
     connects to the system bus. In contrast to
     <function>sd_bus_default()</function>,
-    <function>sd_bus_default_user()</function>,
-    <function>sd_bus_default_system()</function> these calls return
+    <function>sd_bus_default_user()</function>, and
+    <function>sd_bus_default_system()</function>, these calls return
     new, independent connection objects that are not associated with
     the invoking thread and are not shared between multiple
     invocations. It is recommended to share connections per thread to
     efficiently make use the available resources. Thus, it is
     recommended to use <function>sd_bus_default()</function>,
-    <function>sd_bus_default_user()</function>,
+    <function>sd_bus_default_user()</function> and
     <function>sd_bus_default_system()</function> to connect to the
     user or system buses.</para>
 
 
     <para>Queued but unwritten/unread messages also keep a reference
     to their bus connection object. For this reason, even if an
-    application dropped all references to a bus connection it might
-    not get destroyed right-away. Until all incoming queued
+    application dropped all references to a bus connection, it might
+    not get destroyed right away. Until all incoming queued
     messages are read, and until all outgoing unwritten messages are
     written, the bus object will stay
     alive. <function>sd_bus_flush()</function> may be used to write
     all outgoing queued messages so they drop their references. To
-    flush the unread incoming messages use
+    flush the unread incoming messages, use
     <function>sd_bus_close()</function>, which will also close the bus
-    connection. When using the default bus logic it is a good idea to
+    connection. When using the default bus logic, it is a good idea to
     first invoke <function>sd_bus_flush()</function> followed by
     <function>sd_bus_close()</function> when a thread or process
     terminates, and thus its bus connection object should be
     freed.</para>
 
-    <para>The life-cycle of the default bus connection should be the
+    <para>The life cycle of the default bus connection should be the
     responsibility of the code that creates/owns the thread the
     default bus connection object is associated with. Library code
     should neither call <function>sd_bus_flush()</function> nor
     <function>sd_bus_close()</function> on default bus objects unless
     it does so in its own private, self-allocated thread. Library code
     should not use the default bus object in other threads unless it
-    is clear that the program using it will life-cycle the bus
+    is clear that the program using it will life cycle the bus
     connection object and flush and close it before exiting from the
     thread. In libraries where it is not clear that the calling
-    program will life-cycle the bus connection object it is hence
+    program will life cycle the bus connection object, it is hence
     recommended to use <function>sd_bus_open_system()</function>
     instead of <function>sd_bus_default_system()</function> and
     related calls.</para>
index 6dc4541eb19e38afe7d4fdb6126a93c3d96ada20..c2d7ee389bd001af90fccb38ea1e53cf0af5bf96 100644 (file)
     <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     but additional domain-specific errors may be defined by
     applications. The <structfield>message</structfield> field usually
-    contains a human readable string describing the details, but might
+    contains a human-readable string describing the details, but might
     be NULL. An unset <structname>sd_bus_error</structname> structure
     should have both fields initialized to NULL. Set an error
     structure to <constant>SD_BUS_ERROR_NULL</constant> in order to
     for a list of well-known error names. Additional error mappings
     may be defined with
     <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If
-    <parameter>e</parameter> is NULL no error structure is initialized
+    <parameter>e</parameter> is NULL, no error structure is initialized,
     but the error is still converted into an
     <varname>errno</varname>-style error. If
     <parameter>name</parameter> is <constant>NULL</constant>, it is
     assumed that no error occurred, and 0 is returned. This means that
     this function may be conveniently used in a
     <function>return</function> statement. If
-    <parameter>message</parameter> is NULL no message is set. This
+    <parameter>message</parameter> is NULL, no message is set. This
     call can fail if no memory may be allocated for the name and
     message strings, in which case an
     <constant>SD_BUS_ERROR_NO_MEMORY</constant> error might be set
-    instead and -ENOMEM returned. Do not use this call on error
+    instead and -ENOMEM be returned. Do not use this call on error
     structures that are already initialized. If you intend to reuse an
-    error structure free the old data stored in it with
+    error structure, free the old data stored in it with
     <function>sd_bus_error_free()</function> first.</para>
 
     <para><function>sd_bus_error_setf()</function> is similar to
     are not copied internally, and must hence remain constant and
     valid for the lifetime of <parameter>e</parameter>. Use this call
     to avoid memory allocations when setting error structures. Since
-    this call does not allocate memory it will not fail with an
-    out-of-memory condition, as
+    this call does not allocate memory, it will not fail with an
+    out-of-memory condition as
     <function>sd_bus_error_set()</function> can, as described
     above. Alternatively, the
     <constant>SD_BUS_ERROR_MAKE_CONST()</constant> macro may be used
     convenient usage in <function>return</function> statements. This
     call might fail due to lack of memory, in which case an
     <constant>SD_BUS_ERROR_NO_MEMORY</constant> error is set instead,
-    and -ENOMEM returned.</para>
+    and -ENOMEM is returned.</para>
 
     <para><function>sd_bus_error_set_errnof()</function> is similar to
     <function>sd_bus_error_set_errno()</function>, but in addition to
     <parameter>format</parameter> and the arguments.</para>
 
     <para><function>sd_bus_error_set_errnofv()</function> is similar to
-    <function>sd_bus_error_set_errnof()</function> but takes the
+    <function>sd_bus_error_set_errnof()</function>, but takes the
     format string parameters as <citerefentry
     project='man-pages'><refentrytitle>va_arg</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     parameter list.</para>
     <title>Return Value</title>
 
     <para>The functions <function>sd_bus_error_set()</function>,
-    <function>sd_bus_error_setf()</function>,
+    <function>sd_bus_error_setf()</function>, and
     <function>sd_bus_error_set_const()</function>, when successful,
     return the negative errno value corresponding to the
-    <parameter>name</parameter> parameter. Functions
+    <parameter>name</parameter> parameter. The functions
     <function>sd_bus_error_set_errno()</function>,
     <function>sd_bus_error_set_errnof()</function> and
     <function>sd_bus_error_set_errnofv()</function>, when successful,
     <title>Reference ownership</title>
     <para><structname>sd_bus_error</structname> is not reference
     counted. Users should destroy resources held by it by calling
-    <function>sd_bus_error_free()</function>. Usually error structures
+    <function>sd_bus_error_free()</function>. Usually, error structures
     are allocated on the stack or passed in as function parameters,
     but they may also be allocated dynamically, in which case it is
     the duty of the caller to <citerefentry
index 3fca63be4a25fd843d73e402b35e19be770e7c35..139bd77d8c2ed64b5501e45b9dacf525bc3f1e7f 100644 (file)
@@ -87,7 +87,7 @@
     <citerefentry><refentrytitle>sd_bus_error_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     or
     <citerefentry><refentrytitle>sd_bus_error_get_errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>. By
-    default a number of generic, standardized mappings are known, as
+    default, a number of generic, standardized mappings are known, as
     documented in
     <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Use
     this call to add further, application-specific mappings.</para>
     <para>The function takes a pointer to an array of
     <structname>sd_bus_error_map</structname> structures. A reference
     to the specified array is added to the lookup tables for error
-    mappings. Note that the structure is not copied, it is hence
+    mappings. Note that the structure is not copied, and that it is hence
     essential that the array stays available and constant during the
     entire remaining runtime of the process.</para>
 
     <para>The mapping array should be put together with a series of
-    <constant>SD_BUS_ERROR_MAP()</constant> macro invocations, that
+    <constant>SD_BUS_ERROR_MAP()</constant> macro invocations that
     take a literal name string and a (positive)
     <varname>errno</varname>-style error number. The last entry of the
     array should be an invocation of the
index 0ee849dca7aa5a9c64b44c42eb55425a3f75fe99..77fce02eae596904f3ff904430e13afb4041eb5f 100644 (file)
@@ -70,7 +70,7 @@
     appends a sequence of fields to the D-Bus message object
     <parameter>m</parameter>. The type string
     <parameter>types</parameter> describes the types of the field
-    arguments that follow. For each type specified in the type string
+    arguments that follow. For each type specified in the type string,
     one or more arguments need to be specified, in the same order as
     declared in the type string.</para>
 
index 37cadb9d0f2367865451ce4a8b15ff68ae6afb3c..27db2a96c3bb7e0fe97fbc74b6d283f950b75826 100644 (file)
     <parameter>type</parameter>. However, as a special exception, if
     the offset is specified as zero and the size specified as
     UINT64_MAX the full memory file descriptor contents is used. The
-    memory file descriptor is sealed by this call if it hasn't been
-    sealed yet, and cannot be modified a after this call. See
+    memory file descriptor is sealed by this call if it has not been
+    sealed yet, and cannot be modified after this call. See
     <citerefentry
     project='man-pages'><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>
     for details about memory file descriptors. Appending arrays with
     process. Not all protocol transports support passing memory file
     descriptors between participants, in which case this call will
     automatically fall back to copying. Also, as memory file
-    descriptor passing is inefficient for smaller amounts of data
+    descriptor passing is inefficient for smaller amounts of data,
     copying might still be enforced even where memory file descriptor
     passing is supported.</para>
 
     function appends an array of a trivial type to the message
     <parameter>m</parameter>, similar to
     <function>sd_bus_message_append_array()</function>. Contents of
-    the IO vector array <parameter>iov</parameter> are used as the
+    the I/O vector array <parameter>iov</parameter> are used as the
     contents of the array. The total size of
     <parameter>iov</parameter> payload (the sum of
     <structfield>iov_len</structfield> fields) must be a multiple of
     the size of the type <parameter>type</parameter>. The
     <parameter>iov</parameter> argument must point to
-    <parameter>n</parameter> IO vector structures. Each structure may
+    <parameter>n</parameter> I/O vector structures. Each structure may
     have the <structname>iov_base</structname> field set, in which
     case the memory pointed to will be copied into the message, or
     unset (set to zero), in which case a block of zeros of length
     copying items to the message, it returns a pointer to the
     destination area to the caller in pointer
     <parameter>p</parameter>. The caller should subsequently write the
-    array contents to this memory. Modifications of the memory
+    array contents to this memory. Modifications to the memory
     pointed to should only occur until the next operation on the bus
-    message is invoked, most importantly the memory should not be
+    message is invoked. Most importantly, the memory should not be
     altered anymore when another field has been added to the message
     or the message has been sealed.</para>
   </refsect1>
index 4c2c06e903ede5aaa87f45b83558b01e252a886e..2c0a8a5d54c98efa782b7ef1f4c14b4b0483f981 100644 (file)
@@ -83,7 +83,7 @@
     <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>
     for details.</para>
 
-    <para>Similar,
+    <para>Similarly,
     <function>sd_bus_message_get_realtime_usec()</function> returns
     the realtime (wallclock) timestamp of the time the message was
     sent. This value is in microseconds since Jan 1st, 1970, i.e. in
index f53ea9e41aaeecbe716bfe1b619aeaa28c64ea61..a538b13cf02244fad6477863706245f47b582900 100644 (file)
     <citerefentry><refentrytitle>sd_bus_message_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_bus_message_get_seqnum</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     to query the timestamps of incoming messages. If negotiation is
-    disabled or not supported these calls will fail with
+    disabled or not supported, these calls will fail with
     <constant>-ENODATA</constant>. Note that not all transports
     support timestamping of messages. Specifically, timestamping is
     only available on the kdbus transport, but not on dbus1. The
 
     <para><function>sd_bus_negotiate_creds()</function> controls
     whether and which implicit sender credentials shall be attached
-    automatically to all incoming messages. Takes a bus object, a
+    automatically to all incoming messages. Takes a bus object and a
     boolean indicating whether to enable or disable the credential
     parts encoded in the bit mask value argument. Note that not all
     transports support attaching sender credentials to messages, or do
     <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Both
     <function>sd_bus_negotiate_timestamp()</function> and
     <function>sd_bus_negotiate_creds()</function> may also be called
-    after a connection has been set up. Note that when operating on a
+    after a connection has been set up. Note that, when operating on a
     connection that is shared between multiple components of the same
     program (for example via
-    <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
+    <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>),
     it is highly recommended to only enable additional per message
     metadata fields, but never disable them again, in order not to
     disable functionality needed by other components.</para>
index aff2ed2e8395b2fae3821e58bbf139bae3c251af..e1cab6e567b1cfd782619ad35a3a9bd7177bbd76 100644 (file)
@@ -84,7 +84,7 @@
     or a related call, and then start the connection with
     <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
-    <para>In most cases it's a better idea to invoke
+    <para>In most cases, it is a better idea to invoke
     <citerefentry><refentrytitle>sd_bus_default_user</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>sd_bus_default_system</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     or related calls instead of the more low-level
index 696dfd00ba89a11e3e9ca825dda3196f7d4159a5..3088243e4561bd26cfb112f61f7b9cae5238d2d3 100644 (file)
 
     <para><function>sd_bus_path_encode_many()</function> works like
     its counterpart <function>sd_bus_path_encode()</function>, but
-    takes a path-template as argument and encodes multiple labels
+    takes a path template as argument and encodes multiple labels
     according to its embedded directives. For each
     <literal>%</literal> character found in the template, the caller
-    must provide a string via var-args, which will be encoded and
+    must provide a string via varargs, which will be encoded and
     embedded at the position of the <literal>%</literal> character.
     Any other character in the template is copied verbatim into the
     encoded path.</para>
 
     <para><function>sd_bus_path_decode_many()</function> does the
     reverse of <function>sd_bus_path_encode_many()</function>. It
-    decodes the passed object path, according to the given
-    path-template. For each <literal>%</literal> character in the
+    decodes the passed object path according to the given
+    path template. For each <literal>%</literal> character in the
     template, the caller must provide an output storage
-    (<literal>char **</literal>) via var-args. The decoded label
+    (<literal>char **</literal>) via varargs. The decoded label
     will be stored there. Each <literal>%</literal> character will
     only match the current label. It will never match across labels.
-    Furthermore, only a single such directive is allowed per label.
+    Furthermore, only a single directive is allowed per label.
     If <literal>NULL</literal> is passed as output storage, the
     label is verified but not returned to the caller.</para>
   </refsect1>
index b62d1ee5e149ac14a2793d7505fcdbbdf662f036..77bec4e706aa6da0931c1566be49c5a295acd7f2 100644 (file)
       <varlistentry>
         <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>An handler is already installed for this
+        <listitem><para>A handler is already installed for this
         child.</para></listitem>
 
       </varlistentry>
index 01504bf01e8341af8343b3e2b2074c8cfc790e3e..826f2fd224a5654083b5ad3e19e329b23f363402 100644 (file)
@@ -90,7 +90,7 @@
   <refsect1>
     <title>Description</title>
 
-    <para>Those three functions add new event sources to an event loop
+    <para>These three functions add new event sources to an event loop
     object. The event loop is specified in
     <parameter>event</parameter>, the event source is returned in the
     <parameter>source</parameter> parameter. The event sources are
index 1d0942b45cef54c8a73c62044533024f594dc264..0923fe0ae7942b8b63cf6eff69b4d13179dcfb84 100644 (file)
@@ -82,7 +82,7 @@
 
     <para><function>sd_event_add_signal()</function> adds a new signal
     event source to an event loop object. The event loop is specified
-    in <parameter>event</parameter>, the event source is returned in
+    in <parameter>event</parameter>, and the event source is returned in
     the <parameter>source</parameter> parameter. The
     <parameter>signal</parameter> parameter specifies the signal to be handled
     (see
       <varlistentry>
         <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>An handler is already installed for this
+        <listitem><para>A handler is already installed for this
         signal or the signal was not blocked previously.</para></listitem>
 
       </varlistentry>
index e5a440556efff992235f13b25d1b9a9df174b063..f6c5d3981485b9b9acba9e2f6449476b8eba4280 100644 (file)
     <function>sd_event_default()</function>, then releasing it, and
     then acquiring a new one with
     <function>sd_event_default()</function> will result in two
-    distinct objects. Note that in order to free an event loop object,
+    distinct objects. Note that, in order to free an event loop object,
     all remaining event sources of the event loop also need to be
     freed as each keeps a reference to it.</para>
   </refsect1>
index 2eab5684c5f9127c81165b62e12e1bcfaf95e7a3..06236fcd1ad25e69f6fc04fb7b63e2dc44bd9a65 100644 (file)
@@ -46,7 +46,7 @@
     <refname>sd_event_run</refname>
     <refname>sd_event_loop</refname>
 
-    <refpurpose>Run libsystemd event loop</refpurpose>
+    <refpurpose>Run the libsystemd event loop</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
@@ -71,8 +71,8 @@
 
     <para><function>sd_event_run()</function> can be used to run one
     iteration of the event loop of libsystemd. This function waits
-    until an event to process is available and dispatches a handler
-    for it. Parameter <parameter>timeout</parameter> specifices the
+    until an event to process is available, and dispatches a handler
+    for it. The <parameter>timeout</parameter> parameter specifices the
     maximum time (in microseconds) to wait. <constant>(uint64_t)
     -1</constant> may be used to specify an infinite timeout.</para>
 
       <varlistentry>
         <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Parameter <parameter>event</parameter> is
+        <listitem><para>The <parameter>event</parameter> parameter is
         <constant>NULL</constant>.</para></listitem>
       </varlistentry>
 
 
     </variablelist>
 
-    <para>Other errors are possible too.</para>
+    <para>Other errors are possible, too.</para>
   </refsect1>
 
   <refsect1>
       <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <ulink url="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html">GLIb Main Event Loop</ulink>.
+      <ulink url="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html">GLib Main Event Loop</ulink>.
     </para>
   </refsect1>
 
index 72aef897c75ca5e9a087e76b5b7460849c54a069..1471e12e599113962cfc573b05f10779059ebbac 100644 (file)
@@ -77,7 +77,7 @@
     <parameter>source</parameter>. This name will be used in error
     messages generated by
     <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    for this source. Specified <parameter>name</parameter> must point
+    for this source. The <parameter>name</parameter> must point
     to a <constant>NUL</constant>-terminated string or be
     <constant>NULL</constant>. In the latter case, the name will be
     unset. The string is copied internally, so the
   <refsect1>
     <title>Notes</title>
 
-    <para>Functions described here are available as a
+    <para>The functions described here are available as a
     shared library, which can be compiled and linked to with the
     <constant>libsystemd</constant> <citerefentry
     project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry>
index 397d52a3e4ab028dbd32254fae62f2f3ecd232df..7ca50aedf9b05d859db401f1c36de91f7dff82f8 100644 (file)
@@ -47,7 +47,7 @@
     <refname>sd_event_prepare</refname>
     <refname>sd_event_dispatch</refname>
 
-    <refpurpose>Run parts of libsystemd event loop</refpurpose>
+    <refpurpose>Run parts of the libsystemd event loop</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
              └──────────┘
     </programlisting>
 
-    <para>All three functions as the first argument take the event
-    loop object <parameter>event</parameter> that is created with with
+    <para>All three functions take, as the first argument, the event
+    loop object <parameter>event</parameter> that is created with
     <function>sd_event_new</function>. The timeout for
     <function>sd_event_wait</function> is specified with
     <parameter>timeout</parameter> in milliseconds.
     <para>On success, these functions return 0 or a positive integer.
     On failure, they return a negative errno-style error code. In case
     of <function>sd_event_prepare</function> and
-    <function>sd_event_wait</function> a positive value means that
+    <function>sd_event_wait</function>, a positive value means that
     events are ready to be processed and 0 means that no events are
-    ready. In case of <function>sd_event_dispatch</function> a
+    ready. In case of <function>sd_event_dispatch</function>, a
     positive value means that the loop is again in the initial state
-    and 0 means the loop is finished. For any of those functions, a
+    and 0 means the loop is finished. For any of these functions, a
     negative return value means the loop must be aborted.</para>
   </refsect1>
 
       <varlistentry>
         <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Parameter <parameter>event</parameter> is
+        <listitem><para>The <parameter>event</parameter> parameter is
         <constant>NULL</constant>.</para></listitem>
       </varlistentry>
 
 
     </variablelist>
 
-    <para>Other errors are possible too.</para>
+    <para>Other errors are possible, too.</para>
   </refsect1>
 
   <refsect1>
index f1981f7ea21ad9026b1bca9d015fccb4a53a9051..37eb3fc8945047de89f780bacacd7021ded1b1f3 100644 (file)
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted).</para></listitem>
+        or NULL, where that is not accepted).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 420f56356a4d1bc573873aa689fdddc51d503971..3b27444f8d777a6407d88ce051bd0f7543a7d1df 100644 (file)
@@ -89,7 +89,7 @@
     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
+    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
index 1afbd7371cd7767412c7d1b0e431d51d6c90d8d4..1f25d068d71542797b7693e96762af28747841fa 100644 (file)
     <function>sd_journal_get_data()</function> or
     <function>sd_journal_enumerate_data()</function>, or the read
     pointer is altered. Note that the data returned will be prefixed
-    with the field name and '='. Also note that by default data fields
+    with the field name and '='. Also note that, by default, data fields
     larger than 64K might get truncated to 64K. This threshold may be
     changed and turned off with
     <function>sd_journal_set_data_threshold()</function> (see
index 3a38f733ab781b62874b00f19cdc20be96824f9e..61293f7f99d3527193b72bdca5f288b23b006938 100644 (file)
@@ -187,7 +187,7 @@ else {
     certain latency. This call will return a positive value if the
     journal changes are detected immediately and zero when they need
     to be polled for and hence might be noticed only with a certain
-    latency. Note that there's usually no need to invoke this function
+    latency. Note that there is usually no need to invoke this function
     directly as <function>sd_journal_get_timeout()</function> on these
     file systems will ask for timeouts explicitly anyway.</para>
   </refsect1>
index fb572802a301c9d4275d9fe82dbf74ab39121da0..fef453f8dcbf53910c9b766a9152728aaa8f67ba 100644 (file)
     <para><function>sd_journal_open()</function> opens the log journal
     for reading. It will find all journal files automatically and
     interleave them automatically when reading. As first argument it
-    takes a pointer to a <varname>sd_journal</varname> pointer, which
-    on success will contain a journal context object. The second
+    takes a pointer to a <varname>sd_journal</varname> pointer, which,
+    on success, will contain a journal context object. The second
     argument is a flags field, which may consist of the following
     flags ORed together: <constant>SD_JOURNAL_LOCAL_ONLY</constant>
     makes sure only journal files generated on the local machine will
index 0cd0b45b9af312d8b71f753c7199a7b01554769a..17fdc9c1f23e8df55ce94da590942cfac2a6dd10 100644 (file)
     be ignored.) The value can be of any size and format. It is highly
     recommended to submit text strings formatted in the UTF-8
     character encoding only, and submit binary fields only when
-    formatting in UTF-8 strings is not sensible. A number of well
-    known fields are defined, see
+    formatting in UTF-8 strings is not sensible. A number of
+    well-known fields are defined, see
     <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     for details, but additional application defined fields may be
     used. A variable may be assigned more than one value per
     <para><function>sd_journal_perror()</function> is a similar to
     <citerefentry project='die-net'><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     and writes a message to the journal that consists of the passed
-    string, suffixed with ": " and a human readable representation of
+    string, suffixed with ": " and a human-readable representation of
     the current error code stored in
     <citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     If the message string is passed as <constant>NULL</constant> or
index ccd1266318e331a6ceecae6a6c4a5432033514ce..93bf8d853fe28e095d9277a58cd337be7ccb65db 100644 (file)
@@ -76,7 +76,7 @@
     daemon to check for file descriptors passed by the service manager as
     part of the socket-based activation logic. It returns the number
     of received file descriptors. If no file descriptors have been
-    received zero is returned. The first file descriptor may be found
+    received, zero is returned. The first file descriptor may be found
     at file descriptor number 3
     (i.e. <constant>SD_LISTEN_FDS_START</constant>), the remaining
     descriptors follow at 4, 5, 6, ..., if any.</para>
     passed file descriptors to avoid further inheritance to children
     of the calling process.</para>
 
-    <para>If multiple socket units activate the same service the order
+    <para>If multiple socket units activate the same service, the order
     of the file descriptors passed to its main process is undefined.
     If additional file descriptors have been passed to the service
     manager using
     variables are no longer inherited by child processes.</para>
 
     <para><function>sd_listen_fds_with_names()</function> is like
-    <function>sd_listen_fds()</function> but optionally also returns
+    <function>sd_listen_fds()</function>, but optionally also returns
     an array of strings with identification names for the passed file
-    descriptors, if that is available, and the
+    descriptors, if that is available and the
     <parameter>names</parameter> parameter is non-NULL. This
     information is read from the <varname>$LISTEN_FDNAMES</varname>
     variable, which may contain a colon-separated list of names. For
     files, see
     <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for details. For file descriptors pushed into the file descriptor
-    store (see above) the name is set via the
+    store (see above), the name is set via the
     <varname>FDNAME=</varname> field transmitted via
     <function>sd_pid_notify_with_fds()</function>. The primary usecase
     for these names are services which accept a variety of file
     <function>sd_is_socket()</function> and related calls is not
     sufficient. Note that the names used are not unique in any
     way. The returned array of strings has as many entries as file
-    descriptors has been received, plus a final NULL pointer
+    descriptors have been received, plus a final NULL pointer
     terminating the array. The caller needs to free the array itself
     and each of its elements with libc's <function>free()</function>
     call after use. If the <parameter>names</parameter> parameter is
-    NULL the call is entirely equivalent to
+    NULL, the call is entirely equivalent to
     <function>sd_listen_fds()</function>.</para>
 
-    <para>Under specific conditions the following automatic file
+    <para>Under specific conditions, the following automatic file
     descriptor names are returned:
 
     <table>
index a8854dd5902f0df65f13ac7ae020d5ac5e57ef97..db21d702529bd215348379a58ee6bf9f3757f813 100644 (file)
@@ -214,7 +214,7 @@ else {
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted). The specified category to
+        or NULL, where that is not accepted). The specified category to
         watch is not known.</para></listitem>
       </varlistentry>
 
index 9ad7f3fc668a60103f15e73a3149061213d5b396..ef604139da65955961deb7e3b613a8d1fe8917b6 100644 (file)
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted).</para></listitem>
+        or NULL, where that is not accepted).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 2d73c27f62ccc9944aeb473ea33eb73aa80b6671..dbf63304530c84e1e6e8f2b8ff0dae8e04fb5c75 100644 (file)
     <para><function>sd_notify()</function> may be called by a service
     to notify the service manager about state changes. It can be used
     to send arbitrary information, encoded in an
-    environment-block-like string. Most importantly it can be used for
+    environment-block-like string. Most importantly, it can be used for
     start-up completion notification.</para>
 
     <para>If the <parameter>unset_environment</parameter> parameter is
         to the service manager that describes the service state. This
         is free-form and can be used for various purposes: general
         state feedback, fsck-like programs could pass completion
-        percentages and failing programs could pass a human readable
+        percentages and failing programs could pass a human-readable
         error message. Example: <literal>STATUS=Completed 66% of file
         system check...</literal></para></listitem>
       </varlistentry>
         <term>FDNAME=...</term>
 
         <listitem><para>When used in combination with
-        <varname>FDSTORE=1</varname> specifies a name for the
+        <varname>FDSTORE=1</varname>, specifies a name for the
         submitted file descriptors. This name is passed to the service
         during activation, and may be queried using
         <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>. File
         descriptors submitted without this field set, will implicitly
-        get the name <literal>stored</literal> assigned. Note that if
-        multiple file descriptors are submitted at once the specified
+        get the name <literal>stored</literal> assigned. Note that, if
+        multiple file descriptors are submitted at once, the specified
         name will be assigned to all of them. In order to assign
         different names to submitted file descriptors, submit them in
         seperate invocations of
         <function>sd_pid_notify_with_fds()</function>. The name may
-        consist of any ASCII characters, but must not contain control
+        consist of any ASCII character, but must not contain control
         characters or <literal>:</literal>. It may not be longer than
         255 characters. If a submitted name does not follow these
-        restrictions it is ignored.</para></listitem>
+        restrictions, it is ignored.</para></listitem>
       </varlistentry>
 
     </variablelist>
     use as originating PID for the message as first argument. This is
     useful to send notification messages on behalf of other processes,
     provided the appropriate privileges are available. If the PID
-    argument is specified as 0 the process ID of the calling process
+    argument is specified as 0, the process ID of the calling process
     is used, in which case the calls are fully equivalent to
     <function>sd_notify()</function> and
     <function>sd_notifyf()</function>.</para>
 
     <xi:include href="libsystemd-pkgconfig.xml" xpointer="pkgconfig-text"/>
 
-    <para>Internally, these functions send a single datagram with the
+    <para>These functions send a single datagram with the
     state string as payload to the <constant>AF_UNIX</constant> socket
     referenced in the <varname>$NOTIFY_SOCKET</varname> environment
     variable. If the first character of
 
       <para>To store an open file descriptor in the service manager,
       in order to continue operation after a service restart without
-      losing state use <literal>FDSTORE=1</literal>:</para>
+      losing state, use <literal>FDSTORE=1</literal>:</para>
 
       <programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &amp;fd, 1);</programlisting>
     </example>
index 035effcaa90f1ded4c26aa6c3f5c66d3ac2c428e..806cff34e443bf6f1180970ed5f3b315d1b7b8a0 100644 (file)
     not all processes are part of a login session (e.g. system service
     processes, user processes that are shared between multiple
     sessions of the same user, or kernel threads). For processes not
-    being part of a login session this function will fail with
+    being part of a login session, this function will fail with
     -ENODATA. The returned string needs to be freed with the libc
     <citerefentry
     project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     unit name is a short string, suitable for usage in file system
     paths. Note that not all processes are part of a system
     unit/service (e.g. user processes, or kernel threads). For
-    processes not being part of a systemd system unit this function
-    will fail with -ENODATA (More specifically: this call will not
+    processes not being part of a systemd system unit, this function
+    will fail with -ENODATA. (More specifically, this call will not
     work for kernel threads.) The returned string needs to be freed
     with the libc <citerefentry
     project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     <para><function>sd_pid_get_user_unit()</function> may be used to
     determine the systemd user unit (i.e. user service or scope unit)
     identifier of a process identified by the specified PID. This is
-    similar to <function>sd_pid_get_unit()</function> but applies to
+    similar to <function>sd_pid_get_unit()</function>, but applies to
     user units instead of system units.</para>
 
     <para><function>sd_pid_get_owner_uid()</function> may be used to
     determine the Unix UID (user identifier) of the owner of the
     session of a process identified the specified PID. Note that this
     function will succeed for user processes which are shared between
-    multiple login sessions of the same user, where
+    multiple login sessions of the same user, whereas
     <function>sd_pid_get_session()</function> will fail. For processes
     not being part of a login session and not being a shared process
-    of a user this function will fail with -ENODATA.</para>
+    of a user, this function will fail with -ENODATA.</para>
 
     <para><function>sd_pid_get_machine_name()</function> may be used
     to determine the name of the VM or container is a member of. The
     paths. The returned string needs to be freed with the libc
     <citerefentry
     project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    call after use. For processes not part of a VM or containers this
+    call after use. For processes not part of a VM or containers, this
     function fails with -ENODATA.</para>
 
     <para><function>sd_pid_get_slice()</function> may be used to
     <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     call after use.</para>
 
-    <para>Similar, <function>sd_pid_get_user_slice()</function>
+    <para>Similarly, <function>sd_pid_get_user_slice()</function>
     returns the user slice (as managed by the user's systemd instance)
     of a process.</para>
 
     group path of the specified process, relative to the root of the
     hierarchy. Returns the path without trailing slash, except for
     processes located in the root control group, where "/" is
-    returned. To find the actual control group path in the file system
+    returned. To find the actual control group path in the file system,
     the returned path needs to be prefixed with
     <filename>/sys/fs/cgroup/</filename> (if the unified control group
     setup is used), or
       <varlistentry>
         <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>Given field is not specified for the described
+        <listitem><para>The given field is not specified for the described
         process or peer.</para>
         </listitem>
       </varlistentry>
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted).</para></listitem>
+        or NULL, where that is not accepted).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 4d3e0822e0fb2bf1a409a488edb02e86fa671dbc..6e1d505dce9e5e49398080c0409250290b69fe80 100644 (file)
       <varlistentry>
         <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>Given field is not specified for the described
+        <listitem><para>The given field is not specified for the described
         seat.</para>
         </listitem>
       </varlistentry>
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted).</para></listitem>
+        or NULL, where that is not accepted).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 7de9523789c4198cb86cfcab2347f46db7cdd95b..a6076b177abac6815d29733c494a8367bc4b3913 100644 (file)
       <varlistentry>
         <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>Given field is not specified for the described
+        <listitem><para>The given field is not specified for the described
         session.</para>
         </listitem>
       </varlistentry>
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted).</para></listitem>
+        or NULL, where that is not accepted).</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 13ddf08c65156f02cc5dcc69a751b730ce6b7938..4cc7405dd655910bffd19ffa8ebfb1c76d64201c 100644 (file)
       <varlistentry>
         <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>Given field is not specified for the described
+        <listitem><para>The given field is not specified for the described
         user.</para>
         </listitem>
       </varlistentry>
         <term><constant>-EINVAL</constant></term>
 
         <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that's not accepted). This is also returned if
+        or NULL, where that is not accepted). This is also returned if
         the passed user ID is 0xFFFF or 0xFFFFFFFF, which are
         undefined on Linux.</para></listitem>
       </varlistentry>
index 991431f33bfadee52cb9927e49577bbb52714191..144ab1db61475be5729cf2ffb60a7c7ad96e9c98 100644 (file)
     systemd-41.</para>
 
     <para><function>sd_watchdog_enabled()</function> function was
-    added in systemd-209. Since that version the
+    added in systemd-209. Since that version, the
     <varname>$WATCHDOG_PID</varname> variable is also set.</para>
   </refsect1>
 
index ffc6f76294afae31de0660d700f3166a4e4117e3..6edbb7ff83aa925aa2910bc76ce8dbff718910cf 100644 (file)
@@ -38,9 +38,9 @@
   <refsection id='main-conf'>
     <title>Configuration Directories and Precedence</title>
 
-    <para>Default configuration is defined during compilation, so a
+    <para>The default configuration is defined during compilation, so a
     configuration file is only needed when it is necessary to deviate
-    from those defaults. By default the configuration file in
+    from those defaults. By default, the configuration file in
     <filename>/etc/systemd/</filename> contains commented out entries
     showing the defaults as a guide to the administrator. This file
     can be edited to create local overrides.
index e5b2bc0ac9f4e78735c84c5e1b3b7cbd21df02a2..ccf6c8e39fb157fd97a820d15f8543ba23781350 100644 (file)
@@ -140,10 +140,10 @@ net.bridge.bridge-nf-call-arptables = 0
 </programlisting>
 
       <para>This method applies settings when the module is
-      loaded. Please note that unless the <filename>br_netfilter</filename>
+      loaded. Please note that, unless the <filename>br_netfilter</filename>
       module is loaded, bridged packets will not be filtered by
-      netfilter (starting with kernel 3.18), so simply not loading the
-      module is suffient to avoid filtering.</para>
+      Netfilter (starting with kernel 3.18), so simply not loading the
+      module is sufficient to avoid filtering.</para>
     </example>
 
     <example>
@@ -162,10 +162,10 @@ net.bridge.bridge-nf-call-arptables = 0
 </programlisting>
 
       <para>This method forces the module to be always loaded. Please
-      note that unless the <filename>br_netfilter</filename> module is
-      loaded, bridged packets will not be filtered with netfilter
+      note that, unless the <filename>br_netfilter</filename> module is
+      loaded, bridged packets will not be filtered with Netfilter
       (starting with kernel 3.18), so simply not loading the module is
-      suffient to avoid filtering.</para>
+      sufficient to avoid filtering.</para>
     </example>
   </refsect1>
 
index 36edc204b73f054cabf4f49c1c51a728341897e4..755a74f9877b5a7509723d27ec4f77146419770e 100644 (file)
         <listitem>
           <para>The argument should be a comma-separated list of unit
           LOAD, SUB, or ACTIVE states. When listing units, show only
-          those in specified states. Use <option>--state=failed</option>
+          those in the specified states. Use <option>--state=failed</option>
           to show only failed units.</para>
 
           <para>As a special case, if one of the arguments is
 
           <para>Properties for units vary by unit type, so showing any
           unit (even a non-existent one) is a way to list properties
-          pertaining to this type. Similarly showing any job will list
+          pertaining to this type. Similarly, showing any job will list
           properties pertaining to all jobs. Properties for units are
           documented in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
           <command>list-dependencies</command>, i.e. follow
           dependencies of type <varname>WantedBy=</varname>,
           <varname>RequiredBy=</varname>,
-          <varname>RequiredByOverridable=</varname>,
           <varname>PartOf=</varname>, <varname>BoundBy=</varname>,
           instead of <varname>Wants=</varname> and similar.
           </para>
 
       <!-- we do not document -failed here, as it has been made
            redundant by -state=failed, which it predates. To keep
-           things simple we only document the new switch, while
+           things simple, we only document the new switch, while
            keeping the old one around for compatibility only. -->
 
       <varlistentry>
         <listitem>
           <para>When used with <command>kill</command>, choose which
           signal to send to selected processes. Must be one of the
-          well known signal specifiers such as <constant>SIGTERM</constant>, <constant>SIGINT</constant> or
+          well-known signal specifiers such as <constant>SIGTERM</constant>, <constant>SIGINT</constant> or
           <constant>SIGSTOP</constant>. If omitted, defaults to
           <option>SIGTERM</option>.</para>
         </listitem>
         <listitem>
           <para>When used with
           <command>enable</command>/<command>disable</command>/<command>is-enabled</command>
-          (and related commands), use alternative root path when
+          (and related commands), use an alternate root path when
           looking for unit files.</para>
         </listitem>
 
 
         <listitem>
           <para>When used with <command>list-dependencies</command>,
-          the output is printed as a list instead of a tree.</para>
+          <command>list-units</command> or <command>list-machines</command>, the
+          the output is printed as a list instead of a tree, and the bullet
+          circles are omitted.</para>
         </listitem>
       </varlistentry>
 
@@ -829,7 +830,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
 
             <para>This function is intended to generate human-readable
             output. If you are looking for computer-parsable output,
-            use <command>show</command> instead. By default this
+            use <command>show</command> instead. By default, this
             function only shows 10 lines of output and ellipsizes
             lines to fit in the terminal window. This can be changes
             with <option>--lines</option> and <option>--full</option>,
@@ -849,7 +850,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             <para>Show properties of one or more units, jobs, or the
             manager itself. If no argument is specified, properties of
             the manager will be shown. If a unit name is specified,
-            properties of the unit is shown, and if a job id is
+            properties of the unit is shown, and if a job ID is
             specified, properties of the job is shown. By default, empty
             properties are suppressed. Use <option>--all</option> to
             show those too. To select specific properties to show, use
@@ -930,9 +931,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             <para>Shows units required and wanted by the specified
             unit. This recursively lists units following the
             <varname>Requires=</varname>,
-            <varname>RequiresOverridable=</varname>,
             <varname>Requisite=</varname>,
-            <varname>RequisiteOverridable=</varname>,
             <varname>ConsistsOf=</varname>,
             <varname>Wants=</varname>, <varname>BindsTo=</varname>
             dependencies. If no unit is specified,
@@ -959,10 +958,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
           <term><command>list-unit-files <optional><replaceable>PATTERN...</replaceable></optional></command></term>
 
           <listitem>
-            <para>List installed unit files. If one or more
-            <replaceable>PATTERN</replaceable>s are specified, only
-            units whose filename (just the last component of the path)
-            matches one of them are shown.</para>
+            <para>List installed unit files and their enablement state
+            (as reported by <command>is-enabled</command>). If one or
+            more <replaceable>PATTERN</replaceable>s are specified,
+            only units whose filename (just the last component of the
+            path) matches one of them are shown.</para>
           </listitem>
         </varlistentry>
 
@@ -981,7 +981,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             starting any of the units being enabled. If this
             is desired, either <option>--now</option> should be used
             together with this command, or an additional <command>start</command>
-            command must be invoked for the unit. Also note that in case of
+            command must be invoked for the unit. Also note that, in case of
             instance enablement, symlinks named the same as instances
             are created in the install location, however they all point to the
             same template unit file.</para>
@@ -1132,7 +1132,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
                 <tbody>
                   <row>
                     <entry><literal>enabled</literal></entry>
-                    <entry morerows='1'>Enabled through a symlink in <filename>.wants</filename> directory (permanently or just in <filename>/run</filename>).</entry>
+                    <entry morerows='1'>Enabled through a symlink in a <filename>.wants/</filename> or <filename>.requires/</filename> subdirectory of <filename>/etc/systemd/system/</filename> (persistently) or <filename>/run/systemd/system/</filename> (transiently).</entry>
                     <entry morerows='1'>0</entry>
                   </row>
                   <row>
@@ -1140,7 +1140,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
                   </row>
                   <row>
                     <entry><literal>linked</literal></entry>
-                    <entry morerows='1'>Made available through a symlink to the unit file (permanently or just in <filename>/run</filename>).</entry>
+                    <entry morerows='1'>Made available through one or more symlinks to the unit file (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/system/</filename>), even though the unit file might reside outside of the unit file search path.</entry>
                     <entry morerows='1'>&gt; 0</entry>
                   </row>
                   <row>
@@ -1148,7 +1148,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
                   </row>
                   <row>
                     <entry><literal>masked</literal></entry>
-                    <entry morerows='1'>Disabled entirely (permanently or just in <filename>/run</filename>).</entry>
+                    <entry morerows='1'>Completely disabled, so that any start operation on it fails (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/systemd/</filename>).</entry>
                     <entry morerows='1'>&gt; 0</entry>
                   </row>
                   <row>
@@ -1156,17 +1156,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
                   </row>
                   <row>
                     <entry><literal>static</literal></entry>
-                    <entry>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> section.</entry>
                     <entry>0</entry>
                   </row>
                   <row>
                     <entry><literal>indirect</literal></entry>
-                    <entry>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> 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.</entry>
+                    <entry>Unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry>
+                    <entry>&gt; 0</entry>
+                  </row>
+                  <row>
+                    <entry><literal>bad</literal></entry>
+                    <entry>Unit file is invalid or another error occured. 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>
@@ -1225,12 +1230,12 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
 
           <listitem>
             <para>Adds <literal>Wants=</literal> or <literal>Requires=</literal>
-            dependency, respectively, to the specified
+            dependencies, respectively, to the specified
             <replaceable>TARGET</replaceable> for one or more units. </para>
 
             <para>This command honors <option>--system</option>,
             <option>--user</option>, <option>--runtime</option> and
-            <option>--global</option> in a similar way as
+            <option>--global</option> in a way similar to
             <command>enable</command>.</para>
 
           </listitem>
@@ -1246,8 +1251,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
 
             <para>Depending on whether <option>--system</option> (the default),
             <option>--user</option>, or <option>--global</option> is specified,
-            this creates a drop-in file for each unit either for the system,
-            for the calling user or for all futures logins of all users. Then,
+            this command creates a drop-in file for each unit either for the system,
+            for the calling user, or for all futures logins of all users. Then,
             the editor (see the "Environment" section below) is invoked on
             temporary files which will be written to the real location if the
             editor exits successfully.</para>
@@ -1259,8 +1264,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             be made temporarily in <filename>/run</filename> and they will be
             lost on the next reboot.</para>
 
-            <para>If the temporary file is empty upon exit the modification of
-            the related unit is canceled</para>
+            <para>If the temporary file is empty upon exit, the modification of
+            the related unit is canceled.</para>
 
             <para>After the units have been edited, systemd configuration is
             reloaded (in a way that is equivalent to <command>daemon-reload</command>).
@@ -1268,7 +1273,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
 
             <para>Note that this command cannot be used to remotely edit units
             and that you cannot temporarily edit units which are in
-            <filename>/etc</filename> since they take precedence over
+            <filename>/etc</filename>, since they take precedence over
             <filename>/run</filename>.</para>
           </listitem>
         </varlistentry>
@@ -1339,46 +1344,6 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
       </variablelist>
     </refsect2>
 
-    <refsect2>
-      <title>Snapshot Commands</title>
-
-      <variablelist>
-        <varlistentry>
-          <term><command>snapshot <optional><replaceable>NAME</replaceable></optional></command></term>
-
-          <listitem>
-            <para>Create a snapshot. If a snapshot name is specified,
-            the new snapshot will be named after it. If none is
-            specified, an automatic snapshot name is generated. In
-            either case, the snapshot name used is printed to standard
-            output, unless <option>--quiet</option> is specified.
-            </para>
-
-            <para>A snapshot refers to a saved state of the systemd
-            manager. It is implemented itself as a unit that is
-            generated dynamically with this command and has dependencies
-            on all units active at the time. At a later time, the user
-            may return to this state by using the
-            <command>isolate</command> command on the snapshot unit.
-            </para>
-
-            <para>Snapshots are only useful for saving and restoring
-            which units are running or are stopped, they do not
-            save/restore any other state. Snapshots are dynamic and lost
-            on reboot.</para>
-          </listitem>
-        </varlistentry>
-        <varlistentry>
-          <term><command>delete <replaceable>PATTERN</replaceable>...</command></term>
-
-          <listitem>
-            <para>Remove a snapshot previously created with
-            <command>snapshot</command>.</para>
-          </listitem>
-        </varlistentry>
-      </variablelist>
-    </refsect2>
-
     <refsect2>
       <title>Environment Commands</title>
 
@@ -1440,7 +1405,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
           <term><command>daemon-reload</command></term>
 
           <listitem>
-            <para>Reload systemd manager configuration. This will
+            <para>Reload the systemd manager configuration. This will
             rerun all generators (see
             <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>),
             reload all unit files, and recreate the entire dependency
@@ -1483,7 +1448,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             maintenance mode, and with no failed services. Failure is
             returned otherwise (exit code non-zero). In addition, the
             current state is printed in a short string to standard
-            output, see table below. Use <option>--quiet</option> to
+            output, see the table below. Use <option>--quiet</option> to
             suppress this output.</para>
 
             <table>
@@ -1682,7 +1647,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
             <para>Switches to a different root directory and executes a
             new system manager process below it. This is intended for
             usage in initial RAM disks ("initrd"), and will transition
-            from the initrd's system manager process (a.k.a "init"
+            from the initrd's system manager process (a.k.a. "init"
             process) to the main system manager process. This call takes two
             arguments: the directory that is to become the new root directory, and
             the path to the new system manager binary below it to
index 90e974c991e7dd02bf2534fd6f75afe06d409103..5fe1a39057a320e8e2ee718a56537492584ebd54 100644 (file)
@@ -61,7 +61,7 @@
     <title>Description</title>
 
     <para><command>systemd-activate</command> can be used to
-    launch a socket activated daemon from the command line for
+    launch a socket-activated daemon from the command line for
     testing purposes. It can also be used to launch single instances
     of the daemon per connection (inetd-style).
     </para>
     </example>
 
     <example>
-      <title>Run a socket activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title>
+      <title>Run a socket-activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title>
 
       <programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting>
     </example>
index d2db265f5858ef525bc1cf002bb7af02e923b27d..bc37765dffd5d4c2cc59a43ca78f58eb5e2c645a 100644 (file)
     <replaceable>TARGET</replaceable></command> changes the current log
     target of the <command>systemd</command> daemon to
     <replaceable>TARGET</replaceable> (accepts the same values as
-    <option>--log-target=</option> described in
+    <option>--log-target=</option>, described in
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
 
     <para><command>systemd-analyze verify</command> will load unit
         <varname>After=</varname> or <varname>Before=</varname> are
         shown. If <option>--require</option> is passed, only
         dependencies of type <varname>Requires=</varname>,
-        <varname>RequiresOverridable=</varname>,
         <varname>Requisite=</varname>,
-        <varname>RequisiteOverridable=</varname>,
         <varname>Wants=</varname> and <varname>Conflicts=</varname>
         are shown. If neither is passed, this shows dependencies of
         all these types.</para></listitem>
index 10bb529b812911780cb8e3bbaf232d76f7092510..6fb322e8499d542433d2c7e4a6e4ba420a962f17 100644 (file)
         cache for the password. If set, then the tool will try to push
         any collected passwords into the kernel keyring of the root
         user, as a key of the specified name. If combined with
-        <option>--accept-cached</option> it will also try to retrieve
-        the such cached passwords from the key in the kernel keyring
-        instead of querying the user right-away. By using this option
+        <option>--accept-cached</option>, it will also try to retrieve
+        such cached passwords from the key in the kernel keyring
+        instead of querying the user right away. By using this option,
         the kernel keyring may be used as effective cache to avoid
         repeatedly asking users for passwords, if there are multiple
         objects that may be unlocked with the same password. The
         <term><option>--accept-cached</option></term>
 
         <listitem><para>If passed, accept cached passwords, i.e.
-        passwords previously typed in. </para></listitem>
+        passwords previously entered.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index a259f5d583cd79d05af03ae34e6314fdd95ee9ab..3459ed8851243b135e42cfeed2b3d4ebab961ae4 100644 (file)
@@ -58,8 +58,8 @@
     that restores the display backlight brightness at early boot and
     saves it at shutdown. On disk, the backlight brightness is stored
     in <filename>/var/lib/systemd/backlight/</filename>. During
-    loading, if udev property <option>ID_BACKLIGHT_CLAMP</option> is
-    not set to false value, the brightness is clamped to a value of at
+    loading, if the udev property <option>ID_BACKLIGHT_CLAMP</option> is
+    not set to false, the brightness is clamped to a value of at
     least 1 or 5% of maximum brightness, whichever is greater. This
     restriction will be removed when the kernel allows user space to
     reliably set a brightness value which does not turn off the
index 66d264389e7e23ce423d087a09f503509154e727..cccfb49ca94017333556d8f9496fa0fb326e6805 100644 (file)
@@ -54,7 +54,7 @@
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-binfmt.service</filename> is an early-boot
+    <para><filename>systemd-binfmt.service</filename> is an early boot
     service that registers additional binary formats for executables
     in the kernel.</para>
 
index 538666760a9f9e0f052438ffabdf594f3fbc09d4..bcee11fd0b2cc37c1b632a0d5902392649fe232c 100644 (file)
@@ -66,7 +66,7 @@
       and logging startup information in the background.
     </para>
     <para>
-      After collecting a certain amount of data (usually 15-30
+      After collecting a certain amount of data (usually 1530
       seconds, default 20 s) the logging stops and a graph is
       generated from the logged information. This graph contains vital
       clues as to which resources are being used, in which order, and
         <term><emphasis>Started as a standalone program</emphasis></term>
         <listitem><para>One can execute
         <command>systemd-bootchart</command> as normal application
-        from the command line. In this mode it is highly recommended
+        from the command line. In this mode, it is highly recommended
         to pass the <option>-r</option> flag in order to not graph the
         time elapsed since boot and before systemd-bootchart was
         started, as it may result in extremely large graphs. The time
         <term><option>--freq <replaceable>f</replaceable></option></term>
         <listitem><para>Specify the sample log frequency, a positive
         real <replaceable>f</replaceable>, in Hz. Most systems can
-        cope with values up to 25-50 without creating too much
+        cope with values up to 2550 without creating too much
         overhead.</para></listitem>
       </varlistentry>
 
index 9b1a8809dc461dd9d6e7fb88c5fe50e3702cfc70..160db9fb5c4cd9e07c48b455e13439ceb9ce93ee 100644 (file)
         <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
         Defaults to <literal>info</literal>. Note that this simply
         controls the default, individual lines may be logged with
-        different levels if they are prefixed accordingly. For details
+        different levels if they are prefixed accordingly. For details,
         see <option>--level-prefix=</option> below.</para></listitem>
       </varlistentry>
 
index 1c90c0a6595a4231f722e331dac66eebafde5968..c76f6469843fe4da091a5c071621363994252dda 100644 (file)
         <term><option>-r</option></term>
         <term><option>--raw</option></term>
 
-       <listitem><para>Format byte counts (as in memory usage and IO metrics)
+       <listitem><para>Format byte counts (as in memory usage and I/O metrics)
        with raw numeric values rather than human-readable
         numbers.</para></listitem>
       </varlistentry>
         <term><option>--cpu=time</option></term>
 
         <listitem><para>Controls whether the CPU usage is shown as
-        percentage or time. By default the CPU usage is shown as
+        percentage or time. By default, the CPU usage is shown as
         percentage. This setting may also be toggled at runtime by
         pressing the <keycap>%</keycap> key.</para></listitem>
       </varlistentry>
         <term><option>-P</option></term>
 
         <listitem><para>Count only userspace processes instead of all
-        tasks. By default all tasks are counted: each kernel thread
-        and each userspace thread individually. With this setting
+        tasks. By default, all tasks are counted: each kernel thread
+        and each userspace thread individually. With this setting,
         kernel threads are excluded from the counting and each
         userspace process only counts as one, regardless how many
         threads it consists of. This setting may also be toggled at
         <term><option>-k</option></term>
 
         <listitem><para>Count only userspace processes and kernel
-        threads instead of all tasks. By default all tasks are
+        threads instead of all tasks. By default, all tasks are
         counted: each kernel thread and each userspace thread
-        individually. With this setting kernel threads are included in
+        individually. With this setting, kernel threads are included in
         the counting and each userspace process only counts as on one,
         regardless how many threads it consists of. This setting may
         also be toggled at runtime by pressing the <keycap>k</keycap>
         <listitem><para>Controls whether the number of processes shown
         for a control group shall include all processes that are
         contained in any of the child control groups as well. Takes a
-        boolean argument, defaults to <literal>yes</literal>. If
-        enabled the processes in child control groups are included, if
-        disabled only the processes in the control group itself are
+        boolean argument, which defaults to <literal>yes</literal>. If
+        enabled, the processes in child control groups are included, if
+        disabled, only the processes in the control group itself are
         counted. This setting may also be toggled at runtime by
         pressing the <keycap>r</keycap> key. Note that this setting
         only applies to process counting, i.e. when the
         <term><keycap>i</keycap></term>
 
         <listitem><para>Sort the control groups by path, number of
-        tasks, CPU load, memory usage, or IO load, respectively.  This
+        tasks, CPU load, memory usage, or I/O load, respectively.  This
         setting may also be controlled using the
         <option>--order=</option> command line
         switch.</para></listitem>
         excluding processes in child control groups in control group
         process counts. This setting may also be controlled using the
         <option>--recursive=</option> command line switch. This key is
-        not available of all tasks are counted, it is only available
+        not available if all tasks are counted, it is only available
         if processes are counted, as enabled with the
         <keycap>P</keycap> or <keycap>k</keycap>
         keys.</para></listitem>
index cb46d41902034869d2d6a489d6395cbf5f29859d..f1598461ef618b95535d96efda62370e9f37402a 100644 (file)
@@ -72,7 +72,7 @@
     in <citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     In particular, the coredump will only be processed when the
     related resource limits are high enough. For programs started by
-    <command>systemd</command> those may be set using
+    <command>systemd</command>, those may be set using
     <varname>LimitCore=</varname> (see
     <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
     </para>
index b6270358eae6ea4a3cb3c2ab5d2334e0b2d02f53..f036ab974461ca27749ef57729fc7fd60f8273e9 100644 (file)
         system and the initrd.</para>
         <para>If /etc/crypttab contains entries with the same UUID,
         then the name, keyfile and options specified there will be
-        used. Otherwise the device will have the name
+        used. Otherwise, the device will have the name
         <literal>luks-UUID</literal>.</para>
         <para>If /etc/crypttab exists, only those UUIDs
         specified on the kernel command line
index 6a6460ffaaa25857ce16c54d9d9ed7c41766d518..99709604aaedfcbb355f60fbb0aedeb278c08659 100644 (file)
@@ -70,7 +70,7 @@
     directories which contain "drop-in" files with configuration
     snippets which augment the main configuration file. "Drop-in"
     files can be overridden in the same way by placing files with the
-    same name in a directory of higher priority (except that in case
+    same name in a directory of higher priority (except that, in case
     of "drop-in" files, both the "drop-in" file name and the name of
     the containing directory, which corresponds to the name of the
     main configuration file, must match). For a fuller explanation,
index 9ea9141d4d08855ecb95e1503894c1646fb2daeb..5d19322cdcb561241d878122a85ee053278bf82d 100644 (file)
@@ -22,7 +22,7 @@
 -->
 
 <refentry id="systemd-detect-virt"
-    xmlns:xi="http://www.w3.org/2001/XInclude">
+          xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refentryinfo>
     <title>systemd-detect-virt</title>
@@ -62,7 +62,7 @@
     technology and can distinguish full VM virtualization from
     container virtualization. <filename>systemd-detect-virt</filename>
     exits with a return value of 0 (success) if a virtualization
-    technology is detected, and non-zero (error) otherwise. By default
+    technology is detected, and non-zero (error) otherwise. By default,
     any type of virtualization is detected, and the options
     <option>--container</option> and <option>--vm</option> can be used
     to limit what types of virtualization are detected.</para>
         <colspec colname="product" />
         <thead>
           <row>
-      <entry>Type</entry>
-      <entry>ID</entry>
-      <entry>Product</entry>
+            <entry>Type</entry>
+            <entry>ID</entry>
+            <entry>Product</entry>
           </row>
         </thead>
         <tbody>
           <row>
-      <entry morerows="9">VM</entry>
-      <entry><varname>qemu</varname></entry>
-      <entry>QEMU software virtualization</entry>
+            <entry morerows="9">VM</entry>
+            <entry><varname>qemu</varname></entry>
+            <entry>QEMU software virtualization</entry>
           </row>
 
           <row>
-      <entry><varname>kvm</varname></entry>
-      <entry>Linux KVM kernel virtual machine</entry>
+            <entry><varname>kvm</varname></entry>
+            <entry>Linux KVM kernel virtual machine</entry>
           </row>
 
           <row>
-      <entry><varname>zvm</varname></entry>
-      <entry>s390 z/VM</entry>
+            <entry><varname>zvm</varname></entry>
+            <entry>s390 z/VM</entry>
           </row>
 
           <row>
-      <entry><varname>vmware</varname></entry>
-      <entry>VMware Workstation or Server, and related products</entry>
+            <entry><varname>vmware</varname></entry>
+            <entry>VMware Workstation or Server, and related products</entry>
           </row>
 
           <row>
-      <entry><varname>microsoft</varname></entry>
-      <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry>
+            <entry><varname>microsoft</varname></entry>
+            <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry>
           </row>
 
           <row>
-      <entry><varname>oracle</varname></entry>
-      <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry>
+            <entry><varname>oracle</varname></entry>
+            <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry>
           </row>
 
           <row>
-      <entry><varname>xen</varname></entry>
-      <entry>Xen hypervisor (only domU, not dom0)</entry>
+            <entry><varname>xen</varname></entry>
+            <entry>Xen hypervisor (only domU, not dom0)</entry>
           </row>
 
           <row>
-      <entry><varname>bochs</varname></entry>
-      <entry>Bochs Emulator</entry>
+            <entry><varname>bochs</varname></entry>
+            <entry>Bochs Emulator</entry>
           </row>
 
           <row>
-      <entry><varname>uml</varname></entry>
-      <entry>User-mode Linux</entry>
+            <entry><varname>uml</varname></entry>
+            <entry>User-mode Linux</entry>
           </row>
 
           <row>
-      <entry><varname>parallels</varname></entry>
-      <entry>Parallels Desktop, Parallels Server</entry>
+            <entry><varname>parallels</varname></entry>
+            <entry>Parallels Desktop, Parallels Server</entry>
           </row>
 
           <row>
-      <entry morerows="5">container</entry>
-      <entry><varname>openvz</varname></entry>
-      <entry>OpenVZ/Virtuozzo</entry>
+            <entry morerows="5">Container</entry>
+            <entry><varname>openvz</varname></entry>
+            <entry>OpenVZ/Virtuozzo</entry>
           </row>
 
           <row>
-      <entry><varname>lxc</varname></entry>
-      <entry>Linux container implementation by LXC</entry>
+            <entry><varname>lxc</varname></entry>
+            <entry>Linux container implementation by LXC</entry>
           </row>
 
           <row>
-      <entry><varname>lxc-libvirt</varname></entry>
-      <entry>Linux container implementation by libvirt</entry>
+            <entry><varname>lxc-libvirt</varname></entry>
+            <entry>Linux container implementation by libvirt</entry>
           </row>
 
           <row>
-       <entry><varname>systemd-nspawn</varname></entry>
-       <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry>
+            <entry><varname>systemd-nspawn</varname></entry>
+            <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry>
           </row>
 
           <row>
-      <entry><varname>docker</varname></entry>
-      <entry>Docker container manager</entry>
+            <entry><varname>docker</varname></entry>
+            <entry>Docker container manager</entry>
+          </row>
+
+          <row>
+            <entry><varname>rkt</varname></entry>
+            <entry>rkt app container runtime</entry>
           </row>
         </tbody>
       </tgroup>
         hardware virtualization).</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>-r</option></term>
+        <term><option>--chroot</option></term>
+
+        <listitem><para>Detect whether invoked in a
+        <citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        environment. In this mode, no output is written, but the return
+        value indicates whether the process was invoked in a
+        <function>chroot()</function>
+        environment or not.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>-q</option></term>
         <term><option>--quiet</option></term>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 0c3b2305264bf279c11e8477a8213d9743b7187d..5407773f2369790017d73957d7e85e18bbe8d266 100644 (file)
     and will process them individually, one after the other. It will
     output them separated by spaces to stdout.</para>
 
-    <para>By default this command will escape the strings passed,
+    <para>By default, this command will escape the strings passed,
     unless <option>--unescape</option> is passed which results in the
-    inverse operation being applied. If <option>--mangle</option> a
-    special mode of escaping is applied instead, which assumes a
-    string to be already escaped but will escape everything that
+    inverse operation being applied. If <option>--mangle</option> is given, a
+    special mode of escaping is applied instead, which assumes the
+    string is already escaped but will escape everything that
     appears obviously non-escaped.</para>
   </refsect1>
 
index 67289daa26768b1e64d26a9c9307e422280efa68..b269e4811352b08fbbcbde35066ead30f245545e 100644 (file)
       <listitem><para>The root user's password</para></listitem>
     </itemizedlist>
 
-    <para>Each of the fields may either be queried interactively from
-    the users, set non-interactively on the tool's command line, or be
+    <para>Each of the fields may either be queried interactively by
+    users, set non-interactively on the tool's command line, or be
     copied from a host system that is used to set up the system
     image.</para>
 
-    <para>If a setting is already initialized it will not be
+    <para>If a setting is already initialized, it will not be
     overwritten and the user will not be prompted for the
     setting.</para>
 
         <citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         file. This setting exists in two forms:
         <option>--root-password=</option> accepts the password to set
-        directly on the command line,
+        directly on the command line, and
         <option>--root-password-file=</option> reads it from a file.
-        Note that it is not recommended specifying passwords on the
-        command line as other users might be able to see them simply
+        Note that it is not recommended to specify passwords on the
+        command line, as other users might be able to see them simply
         by invoking
         <citerefentry project='die-net'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
       </varlistentry>
index 6d05e90e7bc3177aa3e67b9aa35d7d65d3ea2ef4..933c3247ad5062f414ca876aff0ad17fce4f4d4c 100644 (file)
     device that is configured for file system checking.
     <filename>systemd-fsck-root.service</filename> is responsible for
     file system checks on the root file system, but only if the
-    root filesystem wasn't checked in the initramfs.
+    root filesystem was not checked in the initramfs.
     <filename>systemd-fsck@.service</filename> is used for all other
     file systems and for the root file system in the initramfs.</para>
 
-    <para>Those services are started at boot if
+    <para>These services are started at boot if
     <option>passno</option> in <filename>/etc/fstab</filename> for the
     file system is set to a value greater than zero. The file system
     check for root is performed before the other file systems. Other
-    file systems may be checked in parallel, except when they are one
+    file systems may be checked in parallel, except when they are on
     the same rotating disk.</para>
 
     <para><filename>systemd-fsck</filename> does not know any details
index c09ed4b4da2dc143b29412836382987fe0109030..a971cb36750f42818cc880f4069b57f4dd2361c9 100644 (file)
         <varname>mount.usr=</varname> will default to the value set in
         <varname>root=</varname>.</para>
 
-        <para>Otherwise this parameter defaults to the
+        <para>Otherwise, this parameter defaults to the
         <filename>/usr</filename> entry found in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
         <varname>mount.usrfstype=</varname> will default to the value
         set in <varname>rootfstype=</varname>.</para>
 
-        <para>Otherwise this value will be read from the
+        <para>Otherwise, this value will be read from the
         <filename>/usr</filename> entry in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
         <varname>mount.usrflags=</varname> will default to the value
         set in <varname>rootflags=</varname>.</para>
 
-        <para>Otherwise this value will be read from the
+        <para>Otherwise, this value will be read from the
         <filename>/usr</filename> entry in
         <filename>/etc/fstab</filename> on the root filesystem.</para>
 
index f569ea3cde8a848e4b75b5c4073e1232c6e092b3..e890c4dce2bae9555338bc10dc382d3339fc1cfc 100644 (file)
     </table>
 
     <para>The <filename>/home</filename> and <filename>/srv</filename>
-    partitions may be encrypted in LUKS format. In this case a device
+    partitions may be encrypted in LUKS format. In this case, a device
     mapper device is set up under the names
     <filename>/dev/mapper/home</filename> and
     <filename>/dev/mapper/srv</filename>. Note that this might create
     device name.</para>
 
     <para>Mount and automount units for the EFI System Partition (ESP),
-    mounting it to <filename>/boot</filename> are generated on EFI
-    systems, where the boot loader communicates the used ESP to the operating
+    mounting it to <filename>/boot</filename>, are generated on EFI
+    systems where the boot loader communicates the used ESP to the operating
     system. Since this generator creates an automount unit, the mount will
     only be activated on-demand, when accessed. On systems where
     <filename>/boot</filename> is an explicitly configured mount
index f1a14025b00ce1bdbea4205a373c8657fa159f95..2b363c77f29e4ef3589f45d9bf46861641222af8 100644 (file)
@@ -64,7 +64,7 @@
         <term><option>-r</option></term>
         <term><option>--root=<replaceable>PATH</replaceable></option></term>
         <listitem>
-          <para>Alternative root path in the filesystem.</para>
+          <para>Alternate root path in the filesystem.</para>
         </listitem>
       </varlistentry>
     </variablelist>
index 597f2a2d3e8ffa5f7c24c380367f55b166c67ef7..f9723dea89d7c7ec6ec81d1171aef2c9ac2b9b8b 100644 (file)
       <programlisting>openssl req -newkey rsa:2048 -days 3650 -x509 -nodes \
       -out ca.pem -keyout ca.key -subj '/CN=Certificate authority/'
 
-cat >ca.conf &lt;&lt;EOF
+cat &gt;ca.conf &lt;&lt;EOF
 [ ca ]
 default_ca = this
 
@@ -221,7 +221,7 @@ emailAddress            = optional
 EOF
 
 touch index
-echo 0001 serial
+echo 0001 &gt;serial
 
 SERVER=server
 CLIENT=client
@@ -244,7 +244,7 @@ openssl ca -batch -config ca.conf -notext -in $CLIENT.csr -out $CLIENT.pem
       <varname>ServerCertificateFile=</varname>,
       <varname>ServerKeyFile=</varname>, in
       <filename>/etc/systemd/journal-remote.conf</filename> and
-      <filename>/etc/systemd/journal-upload.conf</filename>
+      <filename>/etc/systemd/journal-upload.conf</filename>,
       respectively. The default locations can be queried by using
       <command>systemd-journal-remote --help</command> and
       <command>systemd-journal-upload --help</command>.</para>
index bd0082712ee65dca5363599cee43293ee4db8034..f1054b03bb1255591de6b473d942c23e21ca2ffc 100644 (file)
@@ -46,6 +46,7 @@
     <refname>systemd-journald.service</refname>
     <refname>systemd-journald.socket</refname>
     <refname>systemd-journald-dev-log.socket</refname>
+    <refname>systemd-journald-audit.socket</refname>
     <refname>systemd-journald</refname>
     <refpurpose>Journal service</refpurpose>
   </refnamediv>
@@ -54,6 +55,7 @@
     <para><filename>systemd-journald.service</filename></para>
     <para><filename>systemd-journald.socket</filename></para>
     <para><filename>systemd-journald-dev-log.socket</filename></para>
+    <para><filename>systemd-journald-audit.socket</filename></para>
     <para><filename>/usr/lib/systemd/systemd-journald</filename></para>
   </refsynopsisdiv>
 
@@ -129,15 +131,30 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
         this is enabled). This must be used after
         <filename>/var/</filename> is mounted, as otherwise log data
         from <filename>/run</filename> is never flushed to
-        <filename>/var</filename> regardless of the
-        configuration.</para></listitem>
+        <filename>/var</filename> regardless of the configuration. The
+        <command>journalctl --flush</command> command uses this signal
+        to request flushing of the journal files, and then waits for
+        the operation to complete. See
+        <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        for details.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term>SIGUSR2</term>
 
         <listitem><para>Request immediate rotation of the journal
-        files.</para></listitem>
+        files. The <command>journalctl --rotate</command> command uses
+        this signal to request journal file
+        rotation.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>SIGRTMIN+1</term>
+
+        <listitem><para>Request that all unwritten log data is written
+        to disk. The <command>journalctl --sync</command> command uses
+        this signal to trigger journal synchronization, and then waits
+        for the operation to complete.</para></listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
@@ -230,7 +247,20 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
         <filename>/var/log/journal</filename> is not available, or
         when <option>Storage=volatile</option> is set in the
         <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        configuration file. </para></listitem>
+        configuration file.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><filename>/dev/kmsg</filename></term>
+        <term><filename>/dev/log</filename></term>
+        <term><filename>/run/systemd/journal/dev-log</filename></term>
+        <term><filename>/run/systemd/journal/socket</filename></term>
+        <term><filename>/run/systemd/journal/stdout</filename></term>
+
+        <listitem><para>Sockets and other paths that
+        <command>systemd-journald</command> will listen on that are
+        visible in the file system. In addition to these, journald can
+        listen for audit events using netlink.</para></listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
@@ -246,7 +276,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting>
       <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
-      <command>pydoc systemd.journal</command>.
+      <command>pydoc systemd.journal</command>
     </para>
   </refsect1>
 
index 10f36b3008f230f8b27fba27d3b8067ac29b231b..39da1922cc39ce276a91d2bad41482d5e41e2a23 100644 (file)
@@ -42,7 +42,7 @@
 
   <refnamediv>
     <refname>systemd-machine-id-commit.service</refname>
-    <refpurpose>Commit a transient machine-id to disk</refpurpose>
+    <refpurpose>Commit a transient machine ID to disk</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
@@ -53,7 +53,7 @@
     <title>Description</title>
 
     <para><filename>systemd-machine-id-commit.service</filename> is an
-    early-boot service responsible for committing transient
+    early boot service responsible for committing transient
     <filename>/etc/machine-id</filename> files to a writable disk file
     system. See
     <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
@@ -74,7 +74,7 @@
 
     <para>The main use case of this service are systems where
     <filename>/etc/machine-id</filename> is read-only and initially
-    not initialized. In this case the system manager will generate a
+    not initialized. In this case, the system manager will generate a
     transient machine ID file on a memory file system, and mount it
     over <filename>/etc/machine-id</filename>, during the early boot
     phase. This service is then invoked in a later boot phase, as soon
index efcf408332cf9de34bf563bef166b375a804b6f5..bfcd74f4365111bf2efb68e0c3652c809e83b463 100644 (file)
@@ -71,7 +71,7 @@
     for more information about this file.</para>
 
     <para>If the tool is invoked without the <option>--commit</option>
-    switch <filename>/etc/machine-id</filename> is initialized with a
+    switch, <filename>/etc/machine-id</filename> is initialized with a
     valid, new machined ID if it is missing or empty. The new machine
     ID will be acquired in the following fashion:</para>
 
       and is different for every booted instance of the
       VM.</para></listitem>
 
-      <listitem><para>Similar, if run inside a Linux container
-      environment and a UUID is configured for the container this is
-      used to initialize the machine ID. For details see the
+      <listitem><para>Similarly, if run inside a Linux container
+      environment and a UUID is configured for the container, this is
+      used to initialize the machine ID. For details, see the
       documentation of the <ulink
       url="http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface">Container
       Interface</ulink>.</para></listitem>
 
-      <listitem><para>Otherwise a new ID is randomly
+      <listitem><para>Otherwise, a new ID is randomly
       generated.</para></listitem>
     </orderedlist>
 
 
         <para>This command is primarily used by the
         <citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-        early-boot service.</para></listitem>
+        early boot service.</para></listitem>
       </varlistentry>
 
       <xi:include href="standard-options.xml" xpointer="help" />
index dacd083baddbf0938386403205e84743af2b62a7..b25929b2e409fc7891c2e17aea839fb120d8eaa7 100644 (file)
@@ -55,7 +55,7 @@
     <title>Description</title>
 
     <para><filename>systemd-modules-load.service</filename> is an
-    early-boot service that loads kernel modules based on static
+    early boot service that loads kernel modules based on static
     configuration.</para>
 
     <para>See
index bcc5776a8d51aa74fe09366f19ea677805b9118d..e21c805342b1619f00322b63f807a2a7d47546cc 100644 (file)
@@ -86,7 +86,7 @@
       <varlistentry>
         <term><option>--ignore=</option></term>
         <listitem><para>Network interfaces to be ignored when deciding
-        if the system is online. By default only the loopback
+        if the system is online. By default, only the loopback
         interface is ignored. This option may be used more than once
         to ignore multiple network interfaces. </para></listitem>
       </varlistentry>
index 71d501f435eadcca71c02d0bb3e9a56595ed070b..a5f4077166ffe6a4fc07710a2a772dda411c22b5 100644 (file)
@@ -60,7 +60,7 @@
     <para><command>systemd-notify</command> may be called by daemon
     scripts to notify the init system about status changes. It can be
     used to send arbitrary information, encoded in an
-    environment-block-like list of strings. Most importantly it can be
+    environment-block-like list of strings. Most importantly, it can be
     used for start-up completion notification.</para>
 
     <para>This is mostly just a wrapper around
         message is sent. This option is hence unrelated to the other
         options. For details about the semantics of this option, see
         <citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An
-        alternative way to check for this state is to call
+        alternate way to check for this state is to call
         <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         with the <command>is-system-running</command> command. It will
         return <literal>offline</literal> if the system was not booted
index 4b0e72113e78db4d8c2579ca7e22c70708ad3567..a97b7c44eb913cba2eb500eb43ab9be09edd0971 100644 (file)
       <varlistentry>
         <term><option>--private-users=</option></term>
 
-        <listitem><para>Enables user namespacing. If enabled the
+        <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
         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
+        container's directory tree. By default, no user namespacing is
         applied.</para>
 
         <para>Note that user namespacing currently requires OS trees
         must be shifted to the container UID base that is
         used during container runtime.</para>
 
-        <para>It is recommended to assign as least 65536 UIDs to each
+        <para>It is recommended to assign at least 65536 UIDs to each
         container, so that the usable UID range in the container
-        covers 16bit. For best security do not assign overlapping UID
+        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 16bit of the host 32bit UIDs as container
-        identifier, while the lower 16bit encode the container UID
+        the upper 16 bit of the host 32-bit UIDs as container
+        identifier, while the lower 16 bit encode the container UID
         used.</para>
 
-        <para>When user namespaces are used the GID range assigned to
+        <para>When user namespaces are used, the GID range assigned to
         each container is always chosen identical to the UID
         range.</para></listitem>
       </varlistentry>
         <option>--private-network</option>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--network-veth-extra=</option></term>
+
+        <listitem><para>Adds an additional virtual Ethernet link
+        between host and container. Takes a colon-separated pair of
+        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
+        used multiple times, and allows configuration of the network
+        interface names. Note that <option>--network-bridge=</option>
+        has no effect on interfaces created with
+        <option>--network-veth-extra=</option>.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><option>--network-bridge=</option></term>
 
         which case <literal>tcp</literal> is assumed. The container
         port number and its colon may be omitted, in which case the
         same port as the host port is implied. This option is only
-        supported if private networking is used, such as
+        supported if private networking is used, such as with
         <option>--network-veth</option> or
         <option>--network-bridge=</option>.</para></listitem>
       </varlistentry>
         <term><option>--bind-ro=</option></term>
 
         <listitem><para>Bind mount a file or directory from the host
-        into the container. Takes one of: a path argument -- in which
+        into the container. Takes one of: a path argument — in which
         case the specified path will be mounted from the host to the
-        same path in the container --, or a colon-separated pair of
-        paths -- in which case the first specified path is the source
+        same path in the container —, or a colon-separated pair of
+        paths — in which case the first specified path is the source
         in the host, and the second path is the destination in the
-        container --, or a colon-separated triple of source path,
-        destination path and mount options. Mount options are comma
-        separated and currently only "rbind" and "norbind"
-        are allowed. Defaults to "rbind". Backslash escapes are interpreted so
+        container —, or a colon-separated triple of source path,
+        destination path and mount options. Mount options are
+        comma-separated and currently, only "rbind" and "norbind"
+        are allowed. Defaults to "rbind". Backslash escapes are interpreted, so
         <literal>\:</literal> may be used to embed colons in either path.
         This option may be specified multiple times for
         creating multiple independent bind mount points. The
         mount the tmpfs instance to (in which case the directory
         access mode will be chosen as 0755, owned by root/root), or
         optionally a colon-separated pair of path and mount option
-        string, that is used for mounting (in which case the kernel
+        string that is used for mounting (in which case the kernel
         default for access mode and owner will be chosen, unless
         otherwise specified). This option is particularly useful for
         mounting directories such as <filename>/var</filename> as
         tmpfs, to allow state-less systems, in particular when
         combined with <option>--read-only</option>.
-        Backslash escapes are interpreted in the path so
+        Backslash escapes are interpreted in the path, so
         <literal>\:</literal> may be used to embed colons in the path.
         </para></listitem>
       </varlistentry>
         overlay file system. The left-most path is hence the lowest
         directory tree, the second-to-last path the highest directory
         tree in the stacking order. If <option>--overlay-ro=</option>
-        is used instead of <option>--overlay=</option> a read-only
+        is used instead of <option>--overlay=</option>, a read-only
         overlay file system is created. If a writable overlay file
-        system is created all changes made to it are written to the
+        system is created, all changes made to it are written to the
         highest directory tree in the stacking order, i.e. the
         second-to-last specified.</para>
 
         <listitem><para>Controls whether the container is registered
         with
         <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-        Takes a boolean argument, defaults to <literal>yes</literal>.
+        Takes a boolean argument, which defaults to <literal>yes</literal>.
         This option should be enabled when the container runs a full
         Operating System (more specifically: an init system), and is
         useful to ensure that the container is accessible via
 
         <listitem><para>Boots the container in volatile mode. When no
         mode parameter is passed or when mode is specified as
-        <option>yes</option> full volatile mode is enabled. This
-        means the root directory is mounted as mostly unpopulated
+        <option>yes</option>, full volatile mode is enabled. This
+        means the root directory is mounted as mostly unpopulated
         <literal>tmpfs</literal> instance, and
         <filename>/usr</filename> from the OS tree is mounted into it,
         read-only (the system thus starts up with read-only OS
         resources, but pristine state and configuration, any changes
         to the either are lost on shutdown). When the mode parameter
-        is specified as <option>state</option> the OS tree is
+        is specified as <option>state</option>, the OS tree is
         mounted read-only, but <filename>/var</filename> is mounted as
-        <literal>tmpfs</literal> instance into it (the system thus
+        <literal>tmpfs</literal> instance into it (the system thus
         starts up with read-only OS resources and configuration, but
-        pristine state, any changes to the latter are lost on
+        pristine state, and any changes to the latter are lost on
         shutdown). When the mode parameter is specified as
-        <option>no</option> (the default) the whole OS tree is made
+        <option>no</option> (the default), the whole OS tree is made
         available writable.</para>
 
         <para>Note that setting this to <option>yes</option> or
         special values <option>override</option> or
         <option>trusted</option>.</para>
 
-        <para>If enabled (the default) a settings file named after the
+        <para>If enabled (the default), a settings file named after the
         machine (as specified with the <option>--machine=</option>
         setting, or derived from the directory or image file name)
         with the suffix <filename>.nspawn</filename> is searched in
         <filename>/etc/systemd/nspawn/</filename> and
         <filename>/run/systemd/nspawn/</filename>. If it is found
         there, its settings are read and used. If it is not found
-        there it is subsequently searched in the same directory as the
+        there, it is subsequently searched in the same directory as the
         image file or in the immediate parent of the root directory of
-        the container. In this case, if the file is found its settings
+        the container. In this case, if the file is found, its settings
         will be also read and used, but potentially unsafe settings
-        are ignored. Note that in both these cases settings on the
+        are ignored. Note that in both these cases, settings on the
         command line take precedence over the corresponding settings
         from loaded <filename>.nspawn</filename> files, if both are
         specified. Unsafe settings are considered all settings that
         elevate the container's privileges or grant access to
         additional resources such as files or directories of the
         host. For details about the format and contents of
-        <filename>.nspawn</filename> files consult
+        <filename>.nspawn</filename> files, consult
         <citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
-        <para>If this option is set to <option>override</option> the
-        file is searched, read and used the same way, however the order of
+        <para>If this option is set to <option>override</option>, the
+        file is searched, read and used the same way, however, the order of
         precedence is reversed: settings read from the
         <filename>.nspawn</filename> file will take precedence over
         the corresponding command line options, if both are
         specified.</para>
 
-        <para>If this option is set to <option>trusted</option> the
+        <para>If this option is set to <option>trusted</option>, the
         file is searched, read and used the same way, but regardless
-        if found in <filename>/etc/systemd/nspawn/</filename>,
+        of being found in <filename>/etc/systemd/nspawn/</filename>,
         <filename>/run/systemd/nspawn/</filename> or next to the image
         file or container root directory, all settings will take
-        effect, however command line arguments still take precedence
+        effect, however, command line arguments still take precedence
         over corresponding settings.</para>
 
-        <para>If disabled no <filename>.nspawn</filename> file is read
+        <para>If disabled, no <filename>.nspawn</filename> file is read
         and no settings except the ones on the command line are in
         effect.</para></listitem>
       </varlistentry>
     <example>
       <title>Build and boot a minimal Fedora distribution in a container</title>
 
-      <programlisting># dnf -y --releasever=21 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd dnf fedora-release vim-minimal
+      <programlisting># dnf -y --releasever=23 --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora --enablerepo=updates install systemd passwd dnf fedora-release vim-minimal
 # systemd-nspawn -bD /srv/mycontainer</programlisting>
 
       <para>This installs a minimal Fedora distribution into the
index 4f790d2cdab41f219791ca1dea8bd10fa40d2e87..da6026e3b38928a06d2eb02d6ea64d0568622740 100644 (file)
     <citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     queriable.</para>
 
-    <para>When invoked without arguments a list of known paths and
+    <para>When invoked without arguments, a list of known paths and
     their current values is shown. When at least one argument is
-    passed the path with this name is queried and its value shown.
+    passed, the path with this name is queried and its value shown.
     The variables whose name begins with <literal>search-</literal>
-    don't refer to individual paths, but instead to a list of
+    do not refer to individual paths, but instead to a list of
     colon-separated search paths, in their order of precedence.</para>
   </refsect1>
 
index 8c836688fecc467cd2c133c80b15223f7b2681a4..f3b5a947dafc4f5e74919ad65dcc76415c5e4f0c 100644 (file)
@@ -55,7 +55,7 @@
     <title>Description</title>
 
     <para><filename>systemd-random-seed.service</filename> is a
-    service that restores the random seed of the system at early-boot
+    service that restores the random seed of the system at early boot
     and saves it at shutdown. See
     <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>
     for details. Saving/restoring the random seed across boots
index 9bc07fcdda10420037f52b23882128fe15ed1d1e..176f2b2d205befdcfe22668c5c9ed8e778975df2 100644 (file)
@@ -55,7 +55,7 @@
     <title>Description</title>
 
     <para><filename>systemd-remount-fs.service</filename> is an
-    early-boot service that applies mount options listed in
+    early boot service that applies mount options listed in
     <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     to the root file system, the <filename>/usr</filename> file system,
     and the kernel API file systems. This is required so that the
index 96dc4f66205dd66e885d58e081b98a4975c7a0cd..43d568c6f7ed1626511a9a0c3c6488f09dfe6640 100644 (file)
@@ -73,9 +73,9 @@
     <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     and
     <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    for details. To improve compatibility
+    for details. To improve compatibility,
     <filename>/etc/resolv.conf</filename> is read in order to discover
-    configured system DNS servers, however only if it is not a symlink
+    configured system DNS servers, but only if it is not a symlink
     to <filename>/run/systemd/resolve/resolv.conf</filename> (see above).</para>
 
     <para><command>systemd-resolved</command> synthesizes DNS RRs for the following cases:</para>
     <para>If lookups are routed to multiple interfaces, the first
     successful response is returned (thus effectively merging the
     lookup zones on all matching interfaces). If the lookup failed on
-    all interfaces the last failing response is returned.</para>
+    all interfaces, the last failing response is returned.</para>
 
     <para>Routing of lookups may be influenced by configuring
-    per-interface domain names, see
+    per-interface domain names. See
     <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     for details. Lookups for a hostname ending in one of the
     per-interface domains are exclusively routed to the matching
index 8850735a346678ab986df9bcaf6bd630eeafb356..414e1c8335f54b8c8f50d3381cccdbe24b9ac052 100644 (file)
@@ -80,7 +80,7 @@
     and thus shows up in the output of <command>systemctl
     list-units</command> like any other unit. It will run in a clean
     and detached execution environment, with the service manager as
-    its parent process. In this mode <command>systemd-run</command>
+    its parent process. In this mode, <command>systemd-run</command>
     will start the service asynchronously in the background and return
     after the command has begun execution.</para>
 
         <term><option>--pty</option></term>
         <term><option>-t</option></term>
 
-        <listitem><para>When invoking a command as service connects
+        <listitem><para>When invoking a command, the service connects
         its standard input and output to the invoking tty via a
         pseudo TTY device. This allows invoking binaries as services
         that expect interactive user input, such as interactive
@@ -355,7 +355,7 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.
 
     <para>The following command invokes the
     <citerefentry project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    tool, but lowers the block IO weight for it to 10. See
+    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>
index 2a2c7b2a132acd4e47ddb438c2cc61e2442873d5..9027ff0f3fce3a6025ee9b1b398616f2f0068016 100644 (file)
@@ -59,7 +59,7 @@
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-sysctl.service</filename> is an early-boot
+    <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>
index 56db9ff17eb1bd9be573264802f976bf9553746a..54ce992b8566d068d472e804d8156025d813ed98 100644 (file)
         <term><varname>CPUAffinity=</varname></term>
 
         <listitem><para>Configures the initial CPU affinity for the
-        init process. Takes a space-separated list of CPU
-        indices.</para></listitem>
+        init process. Takes a list of CPU indices or ranges separated
+        by either whitespace or commas. CPU ranges are specified by
+        the lower and upper CPU indices separated by a
+        dash.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         resource limits for units. See
         <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         for details. Use the string <varname>infinity</varname> to
-        configure no limit on a specific resource. These settings may
-        be overridden in individual units using the corresponding
+        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. DefaultLimitAS=16G). These
+        settings may be overridden in individual units using the corresponding
         LimitXXX= directives. Note that these resource limits are only
         defaults for units, they are not applied to PID 1
         itself.</para></listitem>
index a0c0f996ac0574cca14a7d98ce75e2347df6cfba..4892caad12937a73f41add5d9f92444d816ca14c 100644 (file)
@@ -74,7 +74,7 @@
     specified in
     <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     are searched for a matching file. If the string
-    <filename>-</filename> is specified as filenames entries from the
+    <filename>-</filename> is specified as filename, entries from the
     standard input of the process are read.</para>
   </refsect1>
 
index f2d56cbcd290ae3daa379a9fc8a84683db573200..bb5cc55e9f3f10df0493fa01e4eae3cf30ce2832 100644 (file)
@@ -63,7 +63,7 @@
     <para><ulink url="http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">LSB headers</ulink>
     in SysV init scripts are interpreted, and the ordering specified
     in the header is turned into dependencies between the generated
-    unit and other units. LSB facilities
+    unit and other units. The LSB facilities
     <literal>$remote_fs</literal>, <literal>$network</literal>,
     <literal>$named</literal>, <literal>$portmap</literal>,
     <literal>$time</literal> are supported and will be turned into
@@ -73,7 +73,7 @@
 
     <para>SysV runlevels have corresponding systemd targets
     (<filename>runlevel<replaceable>X</replaceable>.target</filename>).
-    Wrapper unit that is generated will be wanted by those targets
+    The wrapper unit that is generated will be wanted by those targets
     which correspond to runlevels for which the script is
     enabled.</para>
 
index 01ed0b814928a37cc64809d5ccd1d7e980fd2e6a..6ec384313beb672a1f697a4e3a6444a1292db9b1 100644 (file)
@@ -85,7 +85,7 @@
         <term><filename>/var/lib/systemd/clock</filename></term>
 
         <listitem>
-          <para>This file contains the timestamp of last successful
+          <para>This file contains the timestamp of the last successful
           synchronization.</para>
         </listitem>
       </varlistentry>
index ceec06f840e4b30133526c3a697f471c37d7bbdf..447a7eaa17746b765abc1802b31ac62cca623b8f 100644 (file)
@@ -76,7 +76,7 @@
     </para>
 
     <para>If invoked with no arguments, it applies all directives from
-    all configuration files. If one or more filenames are passed on
+    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
index b19b04d7cb0115fba8c3c4b49a5869ee5d8e21a2..243fd064710cf22ffc8d9a48406e22b50cde0038 100644 (file)
         <term><option>--event-timeout=</option></term>
         <listitem>
           <para>Set the number of seconds to wait for events to finish. After
-          this time the event will be terminated. The default is 180 seconds.</para>
+          this time, the event will be terminated. The default is 180 seconds.</para>
         </listitem>
       </varlistentry>
 
index d65f17541839d9608c23fd1a1eafad154d354e55..a2dad39f01ea007ff9b1496bff91f6eb1586be30 100644 (file)
@@ -58,7 +58,7 @@
     service that is invoked as part of the first boot after the vendor
     operating system resources in <filename>/usr</filename> have been
     updated. This is useful to implement offline updates of
-    <filename>/usr</filename> which might requires updates to
+    <filename>/usr</filename> which might require updates to
     <filename>/etc</filename> or <filename>/var</filename> on the
     following boot.</para>
 
index e75ef11c4eb02dc2875ea922dc3c8bc70e03c7b5..67aba54119334498e0b136ab55c0e1c0d039aff9 100644 (file)
@@ -57,9 +57,9 @@
     <para><filename>systemd-user-sessions.service</filename> is a
     service that controls user logins through
     <citerefentry project='man-pages'><refentrytitle>pam_nologin</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
-    After basic system initialization is complete it removes
+    After basic system initialization is complete, it removes
     <filename>/run/nologin</filename>, thus permitting logins. Before
-    system shutdown it creates <filename>/run/nologin</filename>, thus
+    system shutdown, it creates <filename>/run/nologin</filename>, thus
     prohibiting further logins.</para>
   </refsect1>
 
index 7c6ed089978d3e015085a9b1982f02850d677a0e..ff079761c17f28033137f2e729f0c9740f41f881 100644 (file)
@@ -55,7 +55,7 @@
     <title>Description</title>
 
     <para><filename>systemd-vconsole-setup.service</filename> is an
-    early-boot service that configures the virtual console font and
+    early boot service that configures the virtual console font and
     console keymap. Internally it calls
     <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     and
index 9561590c5c89cc51e27a8c3ff76075a59ee7bcdb..1b0ae832dac0c167dd569e148039d0a1614f9996 100644 (file)
 
     <para>Automount units may be used to implement on-demand mounting
     as well as parallelized mounting of file systems.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>If an automount unit is beneath another mount unit in the
+    file system hierarchy, both a requirement and an ordering
+    dependency between both units are created automatically.</para>
+
+    <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>If an automount point is beneath another mount point in the
-    file system hierarchy, a dependency between both units is created
-    automatically.</para>
   </refsect1>
 
   <refsect1>
       </varlistentry>
       <varlistentry>
         <term><varname>TimeoutIdleSec=</varname></term>
-        <listitem><para>Configures an idleness timeout. Once the mount has been
+        <listitem><para>Configures an idle timeout. Once the mount has been
         idle for the specified time, systemd will attempt to unmount. Takes a
         unit-less value in seconds, or a time span value such as "5min 20s".
         Pass 0 to disable the timeout logic. The timeout is disabled by
index ac6deafb182e521825f4a8ff9bc396b83f7f93c4..effed098dd89c8692c6d5928218105fdaabe7f90 100644 (file)
     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>
+  </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Many unit types automatically acquire dependencies on device
+    units of devices they require. For example,
+    <filename>.socket</filename> unit acquire dependencies on the
+    device units of the network interface specified in
+    <varname>BindToDevice=</varname>. Similar, swap and mount units
+    acquire dependencies on the units encapsulating their backing
+    block devices.</para>
   </refsect1>
 
   <refsect1>
index d3f56fee408a467a3534bad433fd2083350bd621..6dda6c5e69fa316df09153c4d8201e401a4d2e5b 100644 (file)
     unit type.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>A few execution parameters result in additional, automatic
+    dependencies to be added.</para>
+
+    <para>Units with <varname>WorkingDirectory=</varname> or
+    <varname>RootDirectory=</varname> set automatically gain
+    dependencies of type <varname>Requires=</varname> and
+    <varname>After=</varname> on all mount units required to access
+    the specified paths. This is equivalent to having them listed
+    explicitly in <varname>RequiresMountsFor=</varname>.</para>
+
+    <para>Similar, units with <varname>PrivateTmp=</varname> enabled
+    automatically get mount unit dependencies for all mounts
+    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>
+  </refsect1>
+
   <refsect1>
     <title>Options</title>
 
 
         <listitem><para>Takes an absolute directory path, or the
         special value <literal>~</literal>. Sets the working directory
-        for executed processes. If set to <literal>~</literal> the
+        for executed processes. If set to <literal>~</literal>, the
         home directory of the user specified in
         <varname>User=</varname> is used. If not set, defaults to the
         root directory when systemd is running as a system instance
         and the respective user's home directory if run as user. If
         the setting is prefixed with the <literal>-</literal>
         character, a missing working directory is not considered
-        fatal.</para></listitem>
+        fatal. Note that setting this parameter might result in
+        additional dependencies to be added to the unit (see
+        above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         system call. If this is used, it must be ensured that the
         process binary and all its auxiliary files are available in
-        the <function>chroot()</function> jail.</para></listitem>
+        the <function>chroot()</function> jail. Note that setting this
+        parameter might result in additional dependencies to be added
+        to the unit (see above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <listitem><para>Sets the supplementary Unix groups the
         processes are executed as. This takes a space-separated list
         of group names or IDs. This option may be specified more than
-        once in which case all listed groups are set as supplementary
-        groups. When the empty string is assigned the list of
+        once, in which case all listed groups are set as supplementary
+        groups. When the empty string is assigned, the list of
         supplementary groups is reset, and all assignments prior to
         this one will have no effect. In any way, this option does not
         override, but extends the list of supplementary groups
       <varlistentry>
         <term><varname>IOSchedulingClass=</varname></term>
 
-        <listitem><para>Sets the IO scheduling class for executed
+        <listitem><para>Sets the I/O scheduling class for executed
         processes. Takes an integer between 0 and 3 or one of the
         strings <option>none</option>, <option>realtime</option>,
         <option>best-effort</option> or <option>idle</option>. See
       <varlistentry>
         <term><varname>IOSchedulingPriority=</varname></term>
 
-        <listitem><para>Sets the IO scheduling priority for executed
+        <listitem><para>Sets the I/O scheduling priority for executed
         processes. Takes an integer between 0 (highest priority) and 7
         (lowest priority). The available priorities depend on the
-        selected IO scheduling class (see above). See
+        selected I/O scheduling class (see above). See
         <citerefentry><refentrytitle>ioprio_set</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         for details.</para></listitem>
       </varlistentry>
         <term><varname>CPUAffinity=</varname></term>
 
         <listitem><para>Controls the CPU affinity of the executed
-        processes. Takes a space-separated list of CPU indices. This
-        option may be specified more than once in which case the
+        processes. Takes a list of CPU indices or ranges separated by
+        either whitespace or commas. CPU ranges are specified by the
+        lower and upper CPU indices separated by a dash.
+        This option may be specified more than once, in which case the
         specified CPU affinity masks are merged. If the empty string
         is assigned, the mask is reset, all assignments prior to this
         will have no effect. See
 
         <listitem><para>Sets environment variables for executed
         processes. Takes a space-separated list of variable
-        assignments. This option may be specified more than once in
+        assignments. This option may be specified more than once, in
         which case all listed variables will be set. If the same
         variable is set twice, the later setting will override the
         earlier setting. If the empty string is assigned to this
         earlier setting.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>PassEnvironment=</varname></term>
+
+        <listitem><para>Pass environment variables from the systemd system
+        manager to executed processes. Takes a space-separated list of variable
+        names. This option may be specified more than once, in which case all
+        listed variables will be set. If the empty string is assigned to this
+        option, the list of environment variables is reset, all prior
+        assignments have no effect. Variables that are not set in the system
+        manager will not be passed and will be silently ignored.</para>
+
+        <para>Variables passed from this setting are overridden by those passed
+        from <varname>Environment=</varname> or
+        <varname>EnvironmentFile=</varname>.</para>
+
+        <para>Example:
+        <programlisting>PassEnvironment=VAR1 VAR2 VAR3</programlisting>
+        passes three variables <literal>VAR1</literal>,
+        <literal>VAR2</literal>, <literal>VAR3</literal>
+        with the values set for those variables in PID1.</para>
+
+        <para>
+        See
+        <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+        for details about environment variables.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>StandardInput=</varname></term>
         <listitem><para>Controls where file descriptor 0 (STDIN) of
         <para>This setting defaults to
         <option>null</option>.</para></listitem>
       </varlistentry>
+
       <varlistentry>
         <term><varname>StandardOutput=</varname></term>
         <listitem><para>Controls where file descriptor 1 (STDOUT) of
         <para>This setting defaults to the value set with
         <option>DefaultStandardOutput=</option> in
         <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-        which defaults to <option>journal</option>.</para></listitem>
+        which defaults to <option>journal</option>. Note that setting
+        this parameter might result in additional dependencies to be
+        added to the unit (see above).</para></listitem>
       </varlistentry>
+
       <varlistentry>
         <term><varname>StandardError=</varname></term>
         <listitem><para>Controls where file descriptor 2 (STDERR) of
         standard error. This setting defaults to the value set with
         <option>DefaultStandardError=</option> in
         <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-        which defaults to <option>inherit</option>.</para></listitem>
+        which defaults to <option>inherit</option>. Note that setting
+        this parameter might result in additional dependencies to be
+        added to the unit (see above).</para></listitem>
       </varlistentry>
+
       <varlistentry>
         <term><varname>TTYPath=</varname></term>
         <listitem><para>Sets the terminal device node to use if
       </varlistentry>
       <varlistentry>
         <term><varname>SyslogLevel=</varname></term>
-        <listitem><para>Default syslog level to use when logging to
+        <listitem><para>The default syslog level to use when logging to
         syslog or the kernel log buffer. One of
         <option>emerg</option>,
         <option>alert</option>,
         different log level which can be used to override the default
         log level specified here. The interpretation of these prefixes
         may be disabled with <varname>SyslogLevelPrefix=</varname>,
-        see below. For details see
+        see below. For details, see
         <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
 
         Defaults to
         of various resources for executed processes. See
         <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         for details. Use the string <varname>infinity</varname> to
-        configure no limit on a specific resource.</para></listitem>
+        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>
+
+        <para>Note that most process resource limits configured with
+        these options are per-process, and processes may fork in order
+        to acquire a new set of resources that are accounted
+        independently of the original process, and may thus escape
+        limits set. Also note that <varname>LimitRSS=</varname> is not
+        implemented on Linux, and setting it has no effect. Often it
+        is advisable to prefer the resource controls listed in
+        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        over these per-process limits, as they apply to services as a
+        whole, may be altered dynamically at runtime, and are
+        generally more expressive. For example,
+        <varname>MemoryLimit=</varname> is a more powerful (and
+        working) replacement for <varname>LimitRSS=</varname>.</para>
 
         <table>
           <title>Limit directives and their equivalent with ulimit</title>
 
-          <tgroup cols='2'>
+          <tgroup cols='3'>
             <colspec colname='directive' />
             <colspec colname='equivalent' />
+            <colspec colname='unit' />
             <thead>
               <row>
                 <entry>Directive</entry>
                 <entry>ulimit equivalent</entry>
+                <entry>Unit</entry>
               </row>
             </thead>
             <tbody>
               <row>
-                <entry>LimitCPU</entry>
+                <entry>LimitCPU=</entry>
                 <entry>ulimit -t</entry>
+                <entry>Seconds</entry>
               </row>
               <row>
-                <entry>LimitFSIZE</entry>
+                <entry>LimitFSIZE=</entry>
                 <entry>ulimit -f</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitDATA</entry>
+                <entry>LimitDATA=</entry>
                 <entry>ulimit -d</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitSTACK</entry>
+                <entry>LimitSTACK=</entry>
                 <entry>ulimit -s</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitCORE</entry>
+                <entry>LimitCORE=</entry>
                 <entry>ulimit -c</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitRSS</entry>
+                <entry>LimitRSS=</entry>
                 <entry>ulimit -m</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitNOFILE</entry>
+                <entry>LimitNOFILE=</entry>
                 <entry>ulimit -n</entry>
+                <entry>Number of File Descriptors</entry>
               </row>
               <row>
-                <entry>LimitAS</entry>
+                <entry>LimitAS=</entry>
                 <entry>ulimit -v</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitNPROC</entry>
+                <entry>LimitNPROC=</entry>
                 <entry>ulimit -u</entry>
+                <entry>Number of Processes</entry>
               </row>
               <row>
-                <entry>LimitMEMLOCK</entry>
+                <entry>LimitMEMLOCK=</entry>
                 <entry>ulimit -l</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitLOCKS</entry>
+                <entry>LimitLOCKS=</entry>
                 <entry>ulimit -x</entry>
+                <entry>Number of Locks</entry>
               </row>
               <row>
-                <entry>LimitSIGPENDING</entry>
+                <entry>LimitSIGPENDING=</entry>
                 <entry>ulimit -i</entry>
+                <entry>Number of Queued Signals</entry>
               </row>
               <row>
-                <entry>LimitMSGQUEUE</entry>
+                <entry>LimitMSGQUEUE=</entry>
                 <entry>ulimit -q</entry>
+                <entry>Bytes</entry>
               </row>
               <row>
-                <entry>LimitNICE</entry>
+                <entry>LimitNICE=</entry>
                 <entry>ulimit -e</entry>
+                <entry>Nice Level</entry>
               </row>
               <row>
-                <entry>LimitRTPRIO</entry>
+                <entry>LimitRTPRIO=</entry>
                 <entry>ulimit -r</entry>
+                <entry>Realtime Priority</entry>
               </row>
               <row>
-                <entry>LimitRTTIME</entry>
+                <entry>LimitRTTIME=</entry>
                 <entry>No equivalent</entry>
+                <entry>Microseconds</entry>
               </row>
             </tbody>
           </tgroup>
-        </table>
+        </table></listitem>
       </varlistentry>
 
       <varlistentry>
         of what <varname>Capabilities=</varname> does. If this option
         is not used, the capability bounding set is not modified on
         process execution, hence no limits on the capabilities of the
-        process are enforced. This option may appear more than once in
+        process are enforced. This option may appear more than once, in
         which case the bounding sets are merged. If the empty string
         is assigned to this option, the bounding set is reset to the
         empty capability set, and all prior settings have no effect.
         <option>no-setuid-fixup-locked</option>,
         <option>noroot</option>, and
         <option>noroot-locked</option>.
-        This option may appear more than once in which case the secure
+        This option may appear more than once, in which case the secure
         bits are ORed. If the empty string is assigned to this option,
         the bits are reset to 0. See
         <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
         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
-        options may be specified more than once in which case all
+        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
         specific list is reset, and all prior assignments have no
         directories read-only for processes invoked by this unit. If
         set to <literal>full</literal>, the <filename>/etc</filename>
         directory is mounted read-only, too. This setting ensures that
-        any modification of the vendor supplied operating system (and
+        any modification of the vendor-supplied operating system (and
         optionally its configuration) is prohibited for the service.
         It is recommended to enable this setting for all long-running
         services, unless they are involved with system updates or need
          invoked process must implement a
          <command>getty</command>-compatible utmp/wtmp logic. If
          <literal>login</literal> is set, first an
-         <constant>INIT_PROCESS</constant> entry, followed by an
+         <constant>INIT_PROCESS</constant> entry, followed by a
          <constant>LOGIN_PROCESS</constant> entry is generated. In
-         this case the invoked process must implement a <citerefentry
+         this case, the invoked process must implement a <citerefentry
          project='die-net'><refentrytitle>login</refentrytitle><manvolnum>1</manvolnum></citerefentry>-compatible
          utmp/wtmp logic. If <literal>user</literal> is set, first an
          <constant>INIT_PROCESS</constant> entry, then a
-         <constant>LOGIN_PROCESS</constant> entry and finally an
+         <constant>LOGIN_PROCESS</constant> entry and finally a
          <constant>USER_PROCESS</constant> entry is generated. In this
-         case the invoked process may be any process that is suitable
+         case, the invoked process may be any process that is suitable
          to be run as session leader. Defaults to
          <literal>init</literal>.</para></listitem>
       </varlistentry>
         <listitem><para>Takes a <option>SMACK64</option> security
         label as argument. The process executed by the unit will be
         started under this label and SMACK will decide whether the
-        processes is allowed to run or not based on it. The process
+        process is allowed to run or not, based on it. The process
         will continue to run under the label specified here unless the
         executable has its own <option>SMACK64EXEC</option> label, in
         which case the process will transition to run under that
         <function>sigreturn</function>,
         <function>exit_group</function>, <function>exit</function>
         system calls are implicitly whitelisted and do not need to be
-        listed explicitly. This option may be specified more than once
+        listed explicitly. This option may be specified more than once,
         in which case the filter masks are merged. If the empty string
         is assigned, the filter is reset, all prior assignments will
         have no effect.</para>
       <varlistentry>
         <term><varname>SystemCallArchitectures=</varname></term>
 
-        <listitem><para>Takes a space separated list of architecture
+        <listitem><para>Takes a space-separated list of architecture
         identifiers to include in the system call filter. The known
         architecture identifiers are <constant>x86</constant>,
         <constant>x86-64</constant>, <constant>x32</constant>,
         <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry project='man-pages'><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry>
index 4514c1afdf1758517694a123d5de15915a35b612..b36aab32598ad2e1edbbaef299f1cc34bc6ad94e 100644 (file)
@@ -87,7 +87,7 @@
     dynamically into native unit files.</para>
 
     <para>Generators are loaded from a set of paths determined during
-    compilation, listed above. System and user generators are loaded
+    compilation, as listed above. System and user generators are loaded
     from directories with names ending in
     <filename>system-generators/</filename> and
     <filename>user-generators/</filename>, respectively. Generators
@@ -96,7 +96,7 @@
     <filename>/dev/null</filename> or an empty file can be used to
     mask a generator, thereby preventing it from running. Please note
     that the order of the two directories with the highest priority is
-    reversed with respect to the unit load path and generators in
+    reversed with respect to the unit load path, and generators in
     <filename>/run</filename> overwrite those in
     <filename>/etc</filename>.</para>
 
             or <command>systemd</command> itself (this means: no
             <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>!). They
             can however rely on the most basic kernel functionality to
-            be available, including mounted <filename>/sys</filename>,
+            be available, including mounted <filename>/sys</filename>,
             <filename>/proc</filename>, <filename>/dev</filename>.
           </para>
         </listitem>
 
         <listitem>
           <para>
-            Units written by generators are removed when configuration
+            Units written by generators are removed when the configuration
             is reloaded. That means the lifetime of the generated
             units is closely bound to the reload cycles of
             <command>systemd</command> itself.
           <para>
             Generators should only be used to generate unit files, not
             any other kind of configuration. Due to the lifecycle
-            logic mentioned above generators are not a good fit to
+            logic mentioned above, generators are not a good fit to
             generate dynamic configuration for other services. If you
-            need to generate dynamic configuration for other services
+            need to generate dynamic configuration for other services,
             do so in normal services you order before the service in
             question.
           </para>
           <para>
             Since
             <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-            is not available (see above) log messages have to be
+            is not available (see above), log messages have to be
             written to <filename>/dev/kmsg</filename> instead.
           </para>
         </listitem>
             Generators may write out dynamic unit files or just hook
             unit files into other units with the usual
             <filename>.wants/</filename> or
-            <filename>.requires/</filename> symlinks. Often it is
+            <filename>.requires/</filename> symlinks. Often, it is
             nicer to simply instantiate a template unit file from
             <filename>/usr</filename> with a generator instead of
-            writing out entirely dynamic unit files. Of course this
+            writing out entirely dynamic unit files. Of course, this
             works only if a single parameter is to be used.
           </para>
         </listitem>
 
         <listitem>
           <para>
-            If you are careful you can implement generators in shell
+            If you are careful, you can implement generators in shell
             scripts. We do recommend C code however, since generators
-            delay are executed synchronously and hence delay the
+            are executed synchronously and hence delay the
             entire boot if they are slow.
           </para>
         </listitem>
           <para>
             Instead of heading off now and writing all kind of
             generators for legacy configuration file formats, please
-            think twice! It's often a better idea to just deprecate
+            think twice! It is often a better idea to just deprecate
             old stuff instead of keeping it artificially alive.
           </para>
         </listitem>
       temporarily redirects <filename>default.target</filename> to
       <filename>system-update.target</filename> if a system update is
       scheduled. Since this needs to override the default user
-      configuration for <filename>default.target</filename> it uses
+      configuration for <filename>default.target</filename>, it uses
       argv[2]. For details about this logic, see
       <ulink url="http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates">Implementing
       Offline System Updates</ulink>.</para>
index 1292f4f51317e05b3693270c7e9966a6eca6affd..13b7ab14dff47c0c7003f1bd4c17ccc2c15c035f 100644 (file)
         <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
         Defaults to <constant>SIGTERM</constant>. </para>
 
-        <para>Note that right after sending the signal specified in
-        this setting systemd will always send
+        <para>Note that, right after sending the signal specified in
+        this setting, systemd will always send
         <constant>SIGCONT</constant>, to ensure that even suspended
         tasks can be terminated cleanly.</para>
         </listitem>
index 7745260a398f4711e16ac5dd2417568141354cc9..a9f8a654c8ceaedce0e915f041043ee8541c4f59 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
+<?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">
 
@@ -70,7 +70,7 @@
     name in <filename>/usr/lib</filename>. This can be used to
     override a system-supplied link file with a local file if needed.
     As a special case, an empty file (file size 0) or symlink with the
-    same name pointing to <filename>/dev/null</filename>, disable the
+    same name pointing to <filename>/dev/null</filename> disables the
     configuration file entirely (it is "masked").</para>
 
     <para>The link file contains a <literal>[Match]</literal> section,
                 generated which is guaranteed to be the same on every
                 boot for the given machine and the given device, but
                 which is otherwise random. This feature depends on ID_NET_NAME_*
-                properties existing for the link, on hardware where these
-                properties are not set the generation of a persistent MAC address
+                properties to exist for the link. On hardware where these
+                properties are not set, the generation of a persistent MAC address
                 will fail.</para>
               </listitem>
             </varlistentry>
                 <para>If the kernel is using a random MAC address,
                 nothing is done. Otherwise, a new address is randomly
                 generated each time the device appears, typically at
-                boot. Either way the random address will have the
+                boot. Either way, the random address will have the
                 <literal>unicast</literal> and
                 <literal>locally administered</literal> bits set.</para>
               </listitem>
   </refsect1>
 
   <refsect1>
-    <title>Example</title>
+    <title>Examples</title>
+
+    <example>
+      <title>/usr/lib/systemd/network/99-default.link</title>
+
+      <para>The link file <filename>99-default.link</filename> that is
+      shipped with systemd defines the default naming policy for
+      links.</para>
+
+      <programlisting>[Link]
+NamePolicy=kernel database onboard slot path
+MACAddressPolicy=persistent</programlisting>
+    </example>
+
+    <example>
+      <title>/etc/systemd/network/10-dmz.link</title>
+
+      <para>This example assigns the fixed name
+      <literal>dmz0</literal> to the interface with the MAC address
+      00:a0:de:63:7a:e6:</para>
+
+      <programlisting>[Match]
+MACAddress=00:a0:de:63:7a:e6
+
+[Link]
+Name=dmz0</programlisting>
+    </example>
+
+    <example>
+      <title>/etc/systemd/network/10-internet.link</title>
+
+      <para>This example assigns the fixed name
+      <literal>internet0</literal> to the interface with the device
+      path <literal>pci-0000:00:1a.0-*</literal>:</para>
+
+      <programlisting>[Match]
+Path=pci-0000:00:1a.0-*
+
+[Link]
+Name=internet0</programlisting>
+    </example>
+
     <example>
       <title>/etc/systemd/network/25-wireless.link</title>
 
+      <para>Here's an overly complex example that shows the use of a large number of [Match] and [Link] settings.</para>
+
       <programlisting>[Match]
 MACAddress=12:34:56:78:9a:bc
 Driver=brcmsmac
index ffffc56936c2b86f406747ee8988c8f46df06193..a724d88584717d71b9ad4ce5df0bcf0dc2b0ad55 100644 (file)
     unit, to allow on-demand or parallelized mounting. See
     <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
 
-    <para>If a mount point is beneath another mount point in the file
-    system hierarchy, a dependency between both units is created
-    automatically.</para>
-
     <para>Mount points created at runtime (independently of unit files
     or <filename>/etc/fstab</filename>) will be monitored by systemd
     and appear like any other mount unit in systemd. See
     File Systems</ulink>.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>If a mount unit is beneath another mount unit in the file
+    system hierarchy, both a requirement dependency and an ordering
+    dependency between both units are created automatically.</para>
+
+    <para>Block device backed file systems automatically gain
+    <varname>BindsTo=</varname> and <varname>After=</varname> type
+    dependencies on the device unit encapsulating the block
+    device (see below).</para>
+
+    <para>If traditional file system quota is enabled for a mount
+    unit, automatic <varname>Wants=</varname> and
+    <varname>Before=</varname> dependencies on
+    <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>Additional implicit dependencies may be added as result of
+    execution and resource control parameters as documented in
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+  </refsect1>
+
   <refsect1>
     <title><filename>fstab</filename></title>
 
     <para>When reading <filename>/etc/fstab</filename> a few special
     mount options are understood by systemd which influence how
     dependencies are created for mount points. systemd will create a
-    dependency of type <option>Wants</option> or
+    dependency of type <varname>Wants=</varname> or
     <option>Requires</option> (see option <option>nofail</option>
     below), from either <filename>local-fs.target</filename> or
     <filename>remote-fs.target</filename>, depending whether the file
       <varlistentry>
         <term><option>x-systemd.idle-timeout=</option></term>
 
-        <listitem><para>Configures the idleness timeout of the
+        <listitem><para>Configures the idle timeout of the
         automount unit. See <varname>TimeoutIdleSec=</varname> in
         <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for details.</para></listitem>
         <listitem><para>Configure how long systemd should wait for a
         device to show up before giving up on an entry from
         <filename>/etc/fstab</filename>. Specify a time in seconds or
-        explicitly append a unit as <literal>s</literal>,
+        explicitly append a unit such as <literal>s</literal>,
         <literal>min</literal>, <literal>h</literal>,
         <literal>ms</literal>.</para>
 
         <para>Note that this option can only be used in
         <filename>/etc/fstab</filename>, and will be
-        ignored when part of <varname>Options=</varname>
+        ignored when part of the <varname>Options=</varname>
         setting in a unit file.</para>
         </listitem>
       </varlistentry>
         <filename>local-fs.target</filename> or
         <filename>remote-fs.target</filename>. This means that it will
         not be mounted automatically during boot, unless it is pulled
-        in by some other unit. Option <option>auto</option> has the
+        in by some other unit. The <option>auto</option> option has the
         opposite meaning and is the default.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><option>nofail</option></term>
 
-        <listitem><para>With <option>nofail</option> this mount will
+        <listitem><para>With <option>nofail</option>, this mount will
         be only wanted, not required, by
         <filename>local-fs.target</filename> or
         <filename>remote-fs.target</filename>. This means that the
index 70311ca9d9e7a2aec7a6254acb273131b6e2bc55..16e41e05b371085e57d09d6b7c96afecf1219ca4 100644 (file)
@@ -81,8 +81,8 @@
     name in <filename>/usr/lib</filename>. This can be used to
     override a system-supplied configuration file with a local file if
     needed. As a special case, an empty file (file size 0) or symlink
-    with the same name pointing to <filename>/dev/null</filename>,
-    disable the configuration file entirely (it is "masked").</para>
+    with the same name pointing to <filename>/dev/null</filename>
+    disables the configuration file entirely (it is "masked").</para>
   </refsect1>
 
   <refsect1>
           <entry>A bond device is an aggregation of all its slave devices. See <ulink url="https://www.kernel.org/doc/Documentation/networking/bonding.txt">Linux Ethernet Bonding Driver HOWTO</ulink> for details.Local configuration</entry></row>
 
           <row><entry><varname>bridge</varname></entry>
-          <entry>A bridge device is a software switch, each of its slave devices and the bridge itself are ports of the switch.</entry></row>
+          <entry>A bridge device is a software switch, and each of its slave devices and the bridge itself are ports of the switch.</entry></row>
 
           <row><entry><varname>dummy</varname></entry>
           <entry>A dummy device drops all packets sent to it.</entry></row>
           <entry>A persistent Level 3 tunnel between a network device and a device node.</entry></row>
 
           <row><entry><varname>veth</varname></entry>
-          <entry>An ethernet tunnel between a pair of network devices.</entry></row>
+          <entry>An Ethernet tunnel between a pair of network devices.</entry></row>
 
           <row><entry><varname>vlan</varname></entry>
           <entry>A VLAN is a stacked device which receives packets from its underlying device based on VLAN tagging. See <ulink url="http://www.ieee802.org/1/pages/802.1Q.html">IEEE 802.1Q</ulink> for details.</entry></row>
 
       <para>The <literal>[Bridge]</literal> section only applies for
       netdevs of kind <literal>bridge</literal>, and accepts the
-      following key:</para>
+      following keys:</para>
 
       <variablelist class='network-directives'>
         <varlistentry>
           <term><varname>HelloTimeSec=</varname></term>
           <listitem>
-            <para>HelloTimeSec specifies the number of seconds a hello packet is
+            <para>HelloTimeSec specifies the number of seconds between two hello packets
             sent out by the root bridge and the designated bridges. Hello packets are
             used to communicate information about the topology throughout the entire
             bridged local area network.</para>
         <term><varname>TTL=</varname></term>
         <listitem>
           <para>A fixed Time To Live N on Virtual eXtensible Local
-          Area Network packets. N is a number in the range 1-255. 0
+          Area Network packets. N is a number in the range 1255. 0
           is a special value meaning that packets inherit the TTL
           value.</para>
         </listitem>
         <term><varname>FDBAgeingSec=</varname></term>
         <listitem>
           <para>The lifetime of Forwarding Database entry learnt by
-          the kernel in seconds.</para>
+          the kernel, in seconds.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>MaximumFDBEntries=</varname></term>
+        <listitem>
+          <para>Configures maximum number of FDB entries.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>ARPProxy=</varname></term>
         <listitem>
-          <para>A boolean. When true, enables ARP proxy.</para>
+          <para>A boolean. When true, enables ARP proxying.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>L3MissNotification=</varname></term>
         <listitem>
-          <para>A boolean. When true, enables netlink IP ADDR miss
+          <para>A boolean. When true, enables netlink IP address miss
           notifications.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>RouteShortCircuit=</varname></term>
         <listitem>
-          <para>A boolean. When true route short circuit is turned
+          <para>A boolean. When true, route short circuiting is turned
           on.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>UDPCheckSum=</varname></term>
         <listitem>
-          <para>A boolean. When true transmitting UDP checksums when doing VXLAN/IPv4 is turned on.</para>
+          <para>A boolean. When true, transmitting UDP checksums when doing VXLAN/IPv4 is turned on.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>UDP6ZeroChecksumTx=</varname></term>
         <listitem>
-          <para>A boolean. When true sending zero checksums in VXLAN/IPv6 is turned on.</para>
+          <para>A boolean. When true, sending zero checksums in VXLAN/IPv6 is turned on.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>UDP6ZeroCheckSumRx=</varname></term>
         <listitem>
-          <para>A boolean. When true receiving zero checksums in VXLAN/IPv6 is turned on.</para>
+          <para>A boolean. When true, receiving zero checksums in VXLAN/IPv6 is turned on.</para>
         </listitem>
       </varlistentry>
     <varlistentry>
       <term><varname>GroupPolicyExtension=</varname></term>
       <listitem>
-        <para>A boolean. When true it enables Group Policy VXLAN extension security label mechanism
-        across network peers based on VXLAN. For details about the Group Policy VXLAN see the
+        <para>A boolean. When true, it enables Group Policy VXLAN extension security label mechanism
+        across network peers based on VXLAN. For details about the Group Policy VXLAN, see the
         <ulink url="https://tools.ietf.org/html/draft-smith-vxlan-group-policy">
         VXLAN Group Policy </ulink> document. Defaults to false.</para>
       </listitem>
         <term><varname>TOS=</varname></term>
         <listitem>
           <para>The Type Of Service byte value for a tunnel interface.
-          For details about the TOS see the
+          For details about the TOS, see the
           <ulink url="http://tools.ietf.org/html/rfc1349"> Type of
           Service in the Internet Protocol Suite </ulink> document.
           </para>
         <term><varname>TTL=</varname></term>
         <listitem>
           <para>A fixed Time To Live N on tunneled packets. N is a
-          number in the range 1-255. 0 is a special value meaning that
+          number in the range 1255. 0 is a special value meaning that
           packets inherit the TTL value. The default value for IPv4
-          tunnels is: inherit. The default value for IPv6 tunnels is:
+          tunnels is: inherit. The default value for IPv6 tunnels is
           64.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>IPv6FlowLabel=</varname></term>
         <listitem>
-          <para>Configures The 20-bit Flow Label (see <ulink url="https://tools.ietf.org/html/rfc6437">
+          <para>Configures the 20-bit flow label (see <ulink url="https://tools.ietf.org/html/rfc6437">
           RFC 6437</ulink>) field in the IPv6 header (see <ulink url="https://tools.ietf.org/html/rfc2460">
-          RFC 2460</ulink>), is used by a node to label packets of a flow.
-          It's only used for IPv6 Tunnels.
-          A Flow Label of zero is used to indicate packets that have
-          not been labeled. Takes following values.
-          When <literal>inherit</literal> it uses the original flowlabel,
-          or can be configured to any value between 0 to 0xFFFFF.</para>
+          RFC 2460</ulink>), which is used by a node to label packets of a flow.
+          It is only used for IPv6 tunnels.
+          A flow label of zero is used to indicate packets that have
+          not been labeled.
+          It can be configured to a value in the range 0–0xFFFFF, or be
+          set to <literal>inherit</literal>, in which case the original flowlabel is used.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
           value of zero means that a packet carrying that option may not enter
           another tunnel before exiting the current tunnel.
           (see <ulink url="https://tools.ietf.org/html/rfc2473#section-4.1.1"> RFC 2473</ulink>).
-          The valid range is 0-255 and <literal>none</literal>. Defaults to 4.
+          The valid range is 0255 and <literal>none</literal>. Defaults to 4.
         </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Mode=</varname></term>
         <listitem>
-          <para>An <literal>ip6tnl</literal> tunnels can have three
+          <para>An <literal>ip6tnl</literal> tunnel can be in one of three
           modes
           <literal>ip6ip6</literal> for IPv6 over IPv6,
           <literal>ipip6</literal> for IPv4 over IPv6 or
 
       <para>The <literal>[Peer]</literal> section only applies for
       netdevs of kind <literal>veth</literal> and accepts the
-      following key:</para>
+      following keys:</para>
 
       <variablelist class='network-directives'>
         <varlistentry>
         <varlistentry>
           <term><varname>MACAddress=</varname></term>
           <listitem>
-            <para>The peer MACAddress, if not set it is generated in
+            <para>The peer MACAddress, if not set, it is generated in
             the same way as the MAC address of the main
             interface.</para>
           </listitem>
         <term><varname>PacketInfo=</varname></term>
         <listitem><para>Takes a boolean argument. Configures whether
         packets should be prepended with four extra bytes (two flag
-        bytes and two protocol bytes). If disabled it indicates that
+        bytes and two protocol bytes). If disabled, it indicates that
         the packets will be pure IP packets. Defaults to
         <literal>no</literal>.</para>
         </listitem>
         <term><varname>LearnPacketIntervalSec=</varname></term>
         <listitem>
           <para>Specifies the number of seconds between instances where the bonding
-          driver sends learning packets to each slaves peer switch.
-          The valid range is 1 - 0x7fffffff; the default value is 1. This Option
-          has effect only in balance-tlb and balance-alb modes.</para>
+          driver sends learning packets to each slave peer switch.
+          The valid range is 1–0x7fffffff; the default value is 1. This option
+          has an effect only for the balance-tlb and balance-alb modes.</para>
         </listitem>
       </varlistentry>
 
         <listitem>
           <para>Specifies the 802.3ad aggregation selection logic to use. Possible values are
           <literal>stable</literal>,
-          <literal>bandwidth</literal>,
-          <literal>count</literal>
+          <literal>bandwidth</literal> and
+          <literal>count</literal>.
           </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>FailOverMACPolicy=</varname></term>
         <listitem>
-          <para>Specifies whether active-backup mode should set all slaves to
-          the same MAC address at enslavement or, when enabled, perform special handling of the
+          <para>Specifies whether the active-backup mode should set all slaves to
+          the same MAC address at the time of enslavement or, when enabled, to perform special handling of the
           bond's MAC address in accordance with the selected policy. The default policy is none.
           Possible values are
           <literal>none</literal>,
-          <literal>active</literal>,
-          <literal>follow</literal>
+          <literal>active</literal> and
+          <literal>follow</literal>.
           </para>
         </listitem>
       </varlistentry>
           monitoring purposes. Possible values are
           <literal>none</literal>,
           <literal>active</literal>,
-          <literal>backup</literal>,
-          <literal>all</literal>
+          <literal>backup</literal> and
+          <literal>all</literal>.
           </para>
         </listitem>
       </varlistentry>
           <para>Specifies the IP addresses to use as ARP monitoring peers when
           ARPIntervalSec is greater than 0. These are the targets of the ARP request
           sent to determine the health of the link to the targets.
-          Specify these values in ipv4 dotted decimal format. At least one IP
+          Specify these values in IPv4 dotted decimal format. At least one IP
           address must be given for ARP monitoring to function. The
           maximum number of targets that can be specified is 16. The
           default value is no IP addresses.
           in order for the ARP monitor to consider a slave as being up.
           This option affects only active-backup mode for slaves with
           ARPValidate enabled. Possible values are
-          <literal>any</literal>,
-          <literal>all</literal>
+          <literal>any</literal> and
+          <literal>all</literal>.
           </para>
         </listitem>
       </varlistentry>
           occurs. This option is designed to prevent flip-flopping between
           the primary slave and other slaves.  Possible values are
           <literal>always</literal>,
-          <literal>better</literal>,
-          <literal>failure</literal>
+          <literal>better</literal> and
+          <literal>failure</literal>.
           </para>
         </listitem>
       </varlistentry>
           <para>Specifies the number of IGMP membership reports to be issued after
           a failover event. One membership report is issued immediately after
           the failover, subsequent packets are sent in each 200ms interval.
-          The valid range is (0 - 255). Defaults to 1. A value of 0
+          The valid range is 0–255. Defaults to 1. A value of 0
           prevents the IGMP membership report from being issued in response
           to the failover event.
           </para>
       <varlistentry>
         <term><varname>PacketsPerSlave=</varname></term>
         <listitem>
-          <para> Specify the number of packets to transmit through a slave before
-            moving to the next one. When set to 0 then a slave is chosen at
-            random. The valid range is (0 - 65535). Defaults to 1. This option
-            has effect only in balance-rr mode.
+          <para>Specify the number of packets to transmit through a slave before
+            moving to the next one. When set to 0, then a slave is chosen at
+            random. The valid range is 0–65535. Defaults to 1. This option
+            only has effect when in balance-rr mode.
           </para>
         </listitem>
       </varlistentry>
         <listitem>
           <para>Specify the number of peer notifications (gratuitous ARPs and
             unsolicited IPv6 Neighbor Advertisements) to be issued after a
-            failover event.  As soon as the link is up on the new slave
+            failover event.  As soon as the link is up on the new slave,
             a peer notification is sent on the  bonding device and each
             VLAN sub-device.  This is repeated at each link monitor interval
             (ARPIntervalSec or MIIMonitorSec, whichever is active) if the number is
-            greater than 1. The valid range is (0 - 255). Default value is 1.
+            greater than 1. The valid range is 0–255. The default value is 1.
             These options affect only the active-backup mode.
           </para>
         </listitem>
       <varlistentry>
         <term><varname>AllSlavesActive=</varname></term>
         <listitem>
-          <para> A boolean. Specifies that duplicate frames (received on inactive ports)
-          should be dropped false or delivered true. Normally, bonding will drop
+          <para>A boolean. Specifies that duplicate frames (received on inactive ports)
+          should be dropped when false, or delivered when true. Normally, bonding will drop
           duplicate frames (received on inactive ports), which is desirable for
           most users. But there are some times it is nice to allow duplicate
           frames to be delivered. The default value is false (drop duplicate frames
index a27f2ff99e1b4d7ff74cebd89c88551e0103df0c..e6dedb027d11a80054ed2398e3a317cc326e43bf 100644 (file)
@@ -77,8 +77,8 @@
     name in <filename>/usr/lib</filename>. This can be used to
     override a system-supplied configuration file with a local file if
     needed. As a special case, an empty file (file size 0) or symlink
-    with the same name pointing to <filename>/dev/null</filename>,
-    disable the configuration file entirely (it is "masked").</para>
+    with the same name pointing to <filename>/dev/null</filename>
+    disables the configuration file entirely (it is "masked").</para>
   </refsect1>
 
   <refsect1>
             <literal>yes</literal>, <literal>no</literal>,
             <literal>ipv4</literal>, or <literal>ipv6</literal>.</para>
 
-            <para>Please note that by default the domain name
+            <para>Note that DHCPv6 will by default be triggered by Router
+            Advertisment, if that is enabled, regardless of this parameter.
+            By enabling DHCPv6 support explicitly, the DHCPv6 client will
+            be started regardless of the presence of routers on the link,
+            or what flags the routers pass. See
+            <literal>IPv6AcceptRouterAdvertisements=</literal>.</para>
+
+            <para>Furthermore, note that by default the domain name
             specified through DHCP is not used for name resolution.
             See option <option>UseDomains=</option> below.</para>
           </listitem>
           <term><varname>IPv6Token=</varname></term>
           <listitem>
             <para>An IPv6 address with the top 64 bits unset. When set, indicates the
-            64 bits interface part of SLAAC IPv6 addresses for this link. By default
+            64-bit interface part of SLAAC IPv6 addresses for this link. By default,
             it is autogenerated.</para>
           </listitem>
         </varlistentry>
           <term><varname>LLMNR=</varname></term>
           <listitem>
             <para>A boolean or <literal>resolve</literal>. When true, enables
-            Link-Local Multicast Name Resolution on the link, when set to
-            <literal>resolve</literal> only resolution is enabled, but not
+            Link-Local Multicast Name Resolution on the link. When set to
+            <literal>resolve</literal>, only resolution is enabled, but not
             announcement. Defaults to true.</para>
           </listitem>
         </varlistentry>
         </varlistentry>
         <varlistentry>
           <term><varname>IPForward=</varname></term>
-          <listitem><para>Configures IP forwarding for the network
-          interface. If enabled incoming packets on the network
-          interface will be forwarded to other interfaces according to
-          the routing table. Takes either a boolean argument, or the
-          values <literal>ipv4</literal> or <literal>ipv6</literal>,
-          which only enables IP forwarding for the specified address
-          family, or <literal>kernel</literal>, which preserves existing sysctl settings.
-          This controls the
-          <filename>net.ipv4.conf.&lt;interface&gt;.forwarding</filename>
-          and
-          <filename>net.ipv6.conf.&lt;interface&gt;.forwarding</filename>
-          sysctl options of the network interface (see <ulink
+          <listitem><para>Configures IP packet forwarding for the
+          system. If enabled, incoming packets on any network
+          interface will be forwarded to any other interfaces
+          according to the routing table. Takes either a boolean
+          argument, or the values <literal>ipv4</literal> or
+          <literal>ipv6</literal>, which only enable IP packet
+          forwarding for the specified address family.  This controls
+          the <filename>net.ipv4.ip_forward</filename> and
+          <filename>net.ipv6.conf.all.forwarding</filename> sysctl
+          options of the network interface (see <ulink
           url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink>
           for details about sysctl options). Defaults to
           <literal>no</literal>.</para>
 
-         <para>Note: unless this option is turned on, or set to <literal>kernel</literal>,
-          no IP forwarding is done on this interface, even if this is
-          globally turned on in the kernel, with the
-          <filename>net.ipv4.ip_forward</filename>,
-          <filename>net.ipv4.conf.all.forwarding</filename>, and
-          <filename>net.ipv6.conf.all.forwarding</filename> sysctl
-          options.</para>
+          <para>Note: this setting controls a global kernel option,
+          and does so one way only: if a network that has this setting
+          enabled is set up the global setting is turned on.  However,
+          it is never turned off again, even after all networks with
+          this setting enabled are shut down again.</para>
+
+          <para>To allow IP packet forwarding only between specific
+          network interfaces use a firewall.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>IPMasquerade=</varname></term>
           <listitem><para>Configures IP masquerading for the network
-          interface. If enabled packets forwarded from the network
+          interface. If enabled, packets forwarded from the network
           interface will be appear as coming from the local host.
           Takes a boolean argument. Implies
           <varname>IPForward=ipv4</varname>. Defaults to
           Privacy Extensions for Stateless Address Autoconfiguration
           in IPv6). Takes a boolean or the special values
           <literal>prefer-public</literal> and
-          <literal>kernel</literal>. When true enables the privacy
+          <literal>kernel</literal>. When true, enables the privacy
           extensions and prefers temporary addresses over public
-          addresses. When <literal>prefer-public</literal> enables the
+          addresses. When <literal>prefer-public</literal>, enables the
           privacy extensions, but prefers public addresses over
           temporary addresses. When false, the privacy extensions
-          remain disabled. When <literal>kernel</literal> the kernel's
+          remain disabled. When <literal>kernel</literal>, the kernel's
           default setting will be left in place.  Defaults to
           <literal>no</literal>.</para></listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>IPv6AcceptRouterAdvertisements=</varname></term>
-          <listitem><para>Configures Accept Router Advertisements.
-          This is enabled if local forwarding is disabled.
-          Disabled if local forwarding is enabled.
-          Takes a boolean. Defaults to unset.
+          <listitem><para>Force the setting of the <filename>accept_ra</filename>
+          (router advertisements) setting for the interface.
+          When unset, the kernel default is used, and router
+          advertisements are accepted only when local forwarding
+          is disabled for that interface.
+          When router advertisements are accepted, they will
+          trigger the start of the DHCPv6 client if the relevant
+          flags are passed, or if no routers are found on the link.
+          Takes a boolean. If true, router advertisements are
+          accepted, when false, router advertisements are ignored,
+          independently of the local forwarding state.</para>
+
+          <para>See
+          <ulink url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink>
+          in the kernel documentation, but note that systemd's
+          setting of <constant>1</constant> corresponds to
+          kernel's setting of <constant>2</constant>.</para>
+        </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>IPv6DuplicateAddressDetection=</varname></term>
+          <listitem><para>Configures the amount of IPv6 Duplicate
+          Address Detection (DAD) probes to send. Defaults to unset.
+        </para></listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>IPv6HopLimit=</varname></term>
+          <listitem><para>Configures IPv6 Hop Limit. For each router that
+          forwards the packet, the hop limit is decremented by 1. When the
+          hop limit field reaches zero, the packet is discarded.
+          Defaults to unset.
         </para></listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Destination=</varname></term>
           <listitem>
             <para>The destination prefix of the route. Possibly
-            followed by a slash and the prefixlength. If omitted, a
+            followed by a slash and the prefix length. If omitted, a
             full-length host route is assumed.</para>
           </listitem>
         </varlistentry>
           <term><varname>Source=</varname></term>
           <listitem>
             <para>The source prefix of the route. Possibly followed by
-            a slash and the prefixlength. If omitted, a full-length
+            a slash and the prefix length. If omitted, a full-length
             host route is assumed.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Metric=</varname></term>
           <listitem>
-            <para>The metric of the route. An unsigned integer</para>
+            <para>The metric of the route (an unsigned integer).</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Scope=</varname></term>
           <listitem>
-            <para>The scope of the route. One of the values <literal>global</literal>,
+            <para>The scope of the route, which can be <literal>global</literal>,
             <literal>link</literal> or <literal>host</literal>. Defaults to
             <literal>global</literal>.</para>
           </listitem>
           <listitem>
             <para>When true (the default), the static routes will be
             requested from the DHCP server and added to the routing
-            table with metric of 1024.</para>
+            table with metric of 1024.</para>
           </listitem>
         </varlistentry>
 
         address. <varname>PoolOffset=</varname> takes the offset of the pool
         from the start of subnet, or zero to use the default value.
         <varname>PoolSize=</varname> takes the number of IP addresses in the
-        pool or zero to use the default value. By default the pool starts at
+        pool or zero to use the default value. By default, the pool starts at
         the first address after the subnet address and takes up the rest of
         the subnet, excluding the broadcast address. If the pool includes
         the server address (the default), this is reserved and not handed
         another common time unit, depending on the suffix. The default
         lease time is used for clients that did not ask for a specific
         lease time. If a client asks for a lease time longer than the
-        maximum lease time it is automatically shortened to the
+        maximum lease time, it is automatically shortened to the
         specified time. The default lease time defaults to 1h, the
         maximum lease time to 12h. Shorter lease times are beneficial
         if the configuration data in DHCP leases changes frequently
         pass to clients may be configured with the
         <varname>DNS=</varname> option, which takes a list of IPv4
         addresses. If the <varname>EmitDNS=</varname> option is
-        enabled but no servers configured the servers are
+        enabled but no servers configured, the servers are
         automatically propagated from an "uplink" interface that has
         appropriate servers set. The "uplink" interface is determined
         by the default route of the system with the highest
         into account that acquire DNS or NTP server information at a
         later point. DNS server propagation does not take
         <filename>/etc/resolv.conf</filename> into account. Also, note
-        that the leases are not refreshed if uplink network
+        that the leases are not refreshed if the uplink network
         configuration changes. To ensure clients regularly acquire the
-        most current uplink DNS server information it is thus
+        most current uplink DNS server information, it is thus
         advisable to shorten the DHCP lease time via
         <varname>MaxLeaseTimeSec=</varname> described
         above.</para></listitem>
         <term><varname>NTP=</varname></term>
 
         <listitem><para>Similar to the <varname>EmitDNS=</varname> and
-        <varname>DNS=</varname> settings described above these
+        <varname>DNS=</varname> settings described above, these
         settings configure whether and what NTP server information
         shall be emitted as part of the DHCP lease. The same syntax,
         propagation semantics and defaults apply as for
         <varname>Timezone=</varname> setting takes a timezone string
         (such as <literal>Europe/Berlin</literal> or
         <literal>UTC</literal>) to pass to clients. If no explicit
-        timezone is set the system timezone of the local host is
+        timezone is set, the system timezone of the local host is
         propagated, as determined by the
         <filename>/etc/localtime</filename> symlink.</para></listitem>
       </varlistentry>
           <term><varname>FastLeave=</varname></term>
           <listitem>
             <para>A boolean. This flag allows the bridge to immediately stop multicast
-            traffic on a port that receives IGMP Leave message. It is only used with
+            traffic on a port that receives an IGMP Leave message. It is only used with
             IGMP snooping if enabled on the bridge. Defaults to off.</para>
           </listitem>
         </varlistentry>
           <term><varname>Cost=</varname></term>
           <listitem>
             <para>Sets the "cost" of sending packets of this interface.
-            Each port in a bridge may have different speed and the cost
+            Each port in a bridge may have different speed and the cost
             is used to decide which link to use. Faster interfaces
             should have lower costs.</para>
           </listitem>
         <varlistentry>
           <term><varname>VLANId=</varname></term>
           <listitem>
-            <para>The VLAN Id for the new static MAC table entry. If
-            omitted, no VLAN Id info is appended to the new static MAC
+            <para>The VLAN ID for the new static MAC table entry. If
+            omitted, no VLAN ID info is appended to the new static MAC
             table entry.</para>
           </listitem>
         </varlistentry>
index 7bfafb424f57286dccfa6383df5a7014b0e59546..e952688331e67016515684acb89e7c62ef684e32 100644 (file)
     to specific containers. The syntax of these files is inspired by
     <filename>.desktop</filename> files following the <ulink
     url="http://standards.freedesktop.org/desktop-entry-spec/latest/">XDG
-    Desktop Entry Specification</ulink>, which are in turn inspired by
+    Desktop Entry Specification</ulink>, which in turn are inspired by
     Microsoft Windows <filename>.ini</filename> files.</para>
 
     <para>Boolean arguments used in these settings files can be
-    written in various formats. For positive settings the strings
+    written in various formats. For positive settings, the strings
     <option>1</option>, <option>yes</option>, <option>true</option>
     and <option>on</option> are equivalent. For negative settings, the
     strings <option>0</option>, <option>no</option>,
     directory or image file name. This file is first searched in
     <filename>/etc/systemd/nspawn/</filename> and
     <filename>/run/systemd/nspawn/</filename>. If found in these
-    directories its settings are read and all of them take full effect
+    directories, its settings are read and all of them take full effect
     (but are possibly overridden by corresponding command line
-    arguments). If not found the file will then be searched next to
+    arguments). If not found, the file will then be searched next to
     the image file or in the immediate parent of the root directory of
-    the container. If the file is found there only a subset of the
+    the container. If the file is found there, only a subset of the
     settings will take effect however. All settings that possibly
     elevate privileges or grant additional access to resources of the
     host (such as files or directories) are ignored. To which options
     this applies is documented below.</para>
 
-    <para>Persistent settings file created and maintained by the
+    <para>Persistent settings files created and maintained by the
     administrator (and thus trusted) should be placed in
     <filename>/etc/systemd/nspawn/</filename>, while automatically
     downloaded (and thus potentially untrusted) settings files are
     placed in <filename>/var/lib/machines/</filename> instead (next to
     the container images), where their security impact is limited. In
     order to add privileged settings to <filename>.nspawn</filename>
-    files acquired from the image vendor it is recommended to copy the
+    files acquired from the image vendor, it is recommended to copy the
     settings files into <filename>/etc/systemd/nspawn/</filename> and
     edit them there, so that the privileged options become
-    available. The precise algorithm how the files are searched and
+    available. The precise algorithm for how the files are searched and
     interpreted may be configured with
     <command>systemd-nspawn</command>'s <option>--settings=</option>
     switch, see
       <varlistentry>
         <term><varname>Boot=</varname></term>
 
-        <listitem><para>Takes a boolean argument, defaults to off. If
-        enabled <command>systemd-nspawn</command> will automatically
+        <listitem><para>Takes a boolean argument, which defaults to off. If
+        enabled, <command>systemd-nspawn</command> will automatically
         search for an <filename>init</filename> executable and invoke
-        it. In this case the specified parameters using
+        it. In this case, the specified parameters using
         <varname>Parameters=</varname> are passed as additional
         arguments to the <filename>init</filename> process. This
         setting corresponds to the <option>--boot</option> switch on
       <varlistentry>
         <term><varname>Parameters=</varname></term>
 
-        <listitem><para>Takes a space separated list of
+        <listitem><para>Takes a space-separated list of
         arguments. This is either a command line, beginning with the
         binary name to execute, or – if <varname>Boot=</varname> is
         enabled – the list of arguments to pass to the init
         <term><varname>Capability=</varname></term>
         <term><varname>DropCapability=</varname></term>
 
-        <listitem><para>Takes a space separated list of Linux process
+        <listitem><para>Takes a space-separated list of Linux process
         capabilities (see
         <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
         for details). The <varname>Capability=</varname> setting
         <filename>.nspawn</filename> files in
         <filename>/etc/systemd/nspawn/</filename> and
         <filename>/run/system/nspawn/</filename> (see above). On the
-        other hand <varname>DropCapability=</varname> takes effect in
+        other hand, <varname>DropCapability=</varname> takes effect in
         all cases.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>MachineID=</varname></term>
 
-        <listitem><para>Configures the 128bit machine ID (UUID) to pass to
+        <listitem><para>Configures the 128-bit machine ID (UUID) to pass to
         the container. This is equivalent to the
         <option>--uuid=</option> command line switch. This option is
         privileged (see above). </para></listitem>
       <varlistentry>
         <term><varname>ReadOnly=</varname></term>
 
-        <listitem><para>Takes a boolean argument, defaults to off. If
-        specified the container will be run with a read-only file
+        <listitem><para>Takes a boolean argument, which defaults to off. If
+        specified, the container will be run with a read-only file
         system. This setting corresponds to the
         <option>--read-only</option> command line
         switch.</para></listitem>
       <varlistentry>
         <term><varname>Private=</varname></term>
 
-        <listitem><para>Takes a boolean argument, defaults to off. If
-        enabled the container will run in its own network namespace
+        <listitem><para>Takes a boolean argument, which defaults to off. If
+        enabled, the container will run in its own network namespace
         and not share network interfaces and configuration with the
         host. This setting corresponds to the
         <option>--private-network</option> command line
         <term><varname>VirtualEthernet=</varname></term>
 
         <listitem><para>Takes a boolean argument. Configures whether
-        to create a virtual ethernet connection
+        to create a virtual Ethernet connection
         (<literal>veth</literal>) between host and the container. This
         setting implies <varname>Private=yes</varname>. This setting
         corresponds to the <option>--network-veth</option> command
         above).</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>VirtualEthernetExtra=</varname></term>
+
+        <listitem><para>Takes a colon-separated pair of interface
+        names. Configures an additional virtual Ethernet connection
+        (<literal>veth</literal>) between host and the container. The
+        first specified name is the interface name on the host, the
+        second the interface name in the container. The latter may be
+        omitted in which case it is set to the same name as the host
+        side interface. This setting implies
+        <varname>Private=yes</varname>. This setting corresponds to
+        the <option>--network-veth-extra=</option> command line
+        switch, and maybe be used multiple times. It is independent of
+        <varname>VirtualEthernet=</varname>. This option is privileged
+        (see above).</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>Interface=</varname></term>
 
-        <listitem><para>Takes a space separated list of interfaces to
+        <listitem><para>Takes a space-separated list of interfaces to
         add to the container. This option corresponds to the
         <option>--network-interface=</option> command line switch and
         implies <varname>Private=yes</varname>. This option is
         <term><varname>MACVLAN=</varname></term>
         <term><varname>IPVLAN=</varname></term>
 
-        <listitem><para>Takes a space separated list of interfaces to
+        <listitem><para>Takes a space-separated list of interfaces to
         add MACLVAN or IPVLAN interfaces to, which are then added to
         the container. These options correspond to the
         <option>--network-macvlan=</option> and
index d02bc92ae608c7b2ae0e3d3b239ce7ded9a22a2e..1bd65ce86d76ab78d21dfcdce89f12f7966c98ff 100644 (file)
     limitations as inotify, and for example cannot be used to monitor
     files or directories changed by other machines on remote NFS file
     systems.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>If a path unit is beneath another mount unit in the file
+    system hierarchy, both a requirement and an ordering dependency
+    between both units are created automatically.</para>
 
-    <para>If a path unit is beneath another mount point in the file
-    system hierarchy, a dependency between both units is created
-    automatically.</para>
+    <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
index 98f4d75ddb3e1dddbe9d2da694a460570d216397..0497f605460b10b0e150bd472487afc7bff3a273 100644 (file)
     use of resource control APIs from programs.</para>
   </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Units with the <varname>Slice=</varname> setting set get
+    automatic <varname>Requires=</varname> and
+    <varname>After=</varname> dependencies on the specified slice
+    unit.</para>
+  </refsect1>
+
   <refsect1>
     <title>Options</title>
 
           or T, the specified memory size is parsed as Kilobytes,
           Megabytes, Gigabytes, or Terabytes (with the base 1024),
           respectively. If assigned the special value
-          <literal>infinity</literal> no memory limit is applied. This
+          <literal>infinity</literal>, no memory limit is applied. This
           controls the <literal>memory.limit_in_bytes</literal>
           control group attribute. For details about this control
           group attribute, see <ulink
           created in the unit. This ensures that the number of tasks
           accounted for the unit (see above) stays below a specific
           limit. If assigned the special value
-          <literal>infinity</literal> no tasks limit is applied. This
+          <literal>infinity</literal>, no tasks limit is applied. This
           controls the <literal>pids.max</literal> control group
           attribute. For details about this control group attribute,
           see <ulink
         <term><varname>BlockIOAccounting=</varname></term>
 
         <listitem>
-          <para>Turn on Block IO accounting for this unit. Takes a
-          boolean argument. Note that turning on block IO accounting
+          <para>Turn on Block I/O accounting for this unit. Takes a
+          boolean argument. Note that turning on block I/O accounting
           for one unit will also implicitly turn it on for all units
           contained in the same slice and all for its parent slices
           and the units contained therein. The system default for this
         <term><varname>BlockIOWeight=<replaceable>weight</replaceable></varname></term>
         <term><varname>StartupBlockIOWeight=<replaceable>weight</replaceable></varname></term>
 
-        <listitem><para>Set the default overall block IO weight for
+        <listitem><para>Set the default overall block I/O weight for
         the executed processes. Takes a single weight value (between
-        10 and 1000) to set the default block IO weight. This controls
+        10 and 1000) to set the default block I/O weight. This controls
         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>.
-        The available IO bandwidth is split up among all units within
-        one slice relative to their block IO weight.</para>
+        The available I/O bandwidth is split up among all units within
+        one slice relative to their block I/O weight.</para>
 
         <para>While <varname>StartupBlockIOWeight=</varname> only
         applies to the startup phase of the system,
         <term><varname>BlockIODeviceWeight=<replaceable>device</replaceable> <replaceable>weight</replaceable></varname></term>
 
         <listitem>
-          <para>Set the per-device overall block IO weight for the
+          <para>Set the per-device overall block I/O weight for the
           executed processes. Takes a space-separated pair of a file
           path and a weight value to specify the device specific
           weight value, between 10 and 1000. (Example: "/dev/sda
         <term><varname>BlockIOWriteBandwidth=<replaceable>device</replaceable> <replaceable>bytes</replaceable></varname></term>
 
         <listitem>
-          <para>Set the per-device overall block IO bandwidth limit
+          <para>Set the per-device overall block I/O bandwidth limit
           for the executed processes. Takes a space-separated pair of
           a file path and a bandwidth value (in bytes per second) to
           specify the device specific bandwidth. The file path may be
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>NetClass=</varname></term>
+        <listitem><para>Configures a network class number to assign to the
+        unit. This value will be set to the
+        <literal>net_cls.class_id</literal> property of the
+        <literal>net_cls</literal> cgroup of the unit. The directive
+        accepts a numerical value (for fixed number assignment) and the keyword
+        <literal>auto</literal> (for dynamic allocation). Network traffic of
+        all processes inside the unit will have the network class ID assigned
+        by the kernel. Also see
+        the kernel docs for
+        <ulink url="https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt">net_cls controller</ulink>
+        and
+        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+        </para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>Slice=</varname></term>
 
           <para>Turns on delegation of further resource control
           partitioning to processes of the unit. For unprivileged
           services (i.e. those using the <varname>User=</varname>
-          setting) this allows processes to create a subhierarchy
+          setting), this allows processes to create a subhierarchy
           beneath its control group path. For privileged services and
-          scopes this ensures the processes will have all control
+          scopes, this ensures the processes will have all control
           group controllers enabled.</para>
         </listitem>
       </varlistentry>
index fd65a851e244f2324c7d5ec2f31210806b423a76..f69b2ef63554ae39d7d05fdc449c3f172d6cca8e 100644 (file)
     url="http://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New
     Control Group Interfaces</ulink> for an introduction on how to make
     use of scope units from programs.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
 
     <para>Unless <varname>DefaultDependencies=false</varname>
     is used, scope units will implicitly have dependencies of
     shutdown. Only scope units involved with early boot or
     late system shutdown should disable this option.
     </para>
+
+    <para>Additional implicit dependencies may be added as result of
+    resource control parameters as documented in
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
   </refsect1>
 
   <refsect1>
index 8afdbc513b98682810aa5e36bda33ddec83e4555..c6ed75d158dcf52cbcddfbc3018b03a9e8f70ebb 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
+<?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">
 
     which configure resource control settings for the processes of the
     service.</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>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>If a service is requested under a certain name but no unit
     configuration file is found, systemd looks for a SysV init script
     by the same name (with the <filename>.service</filename> suffix
     compatibility is quite comprehensive but not 100%. For details
     about the incompatibilities, see the <ulink
     url="http://www.freedesktop.org/wiki/Software/systemd/Incompatibilities">Incompatibilities
-    with SysV</ulink> document.
-    </para>
+    with SysV</ulink> document.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Services with <varname>Type=dbus</varname> set automatically
+    acquire dependencies of type <varname>Requires=</varname> and
+    <varname>After=</varname> on
+    <filename>dbus.socket</filename>.</para>
+
+    <para>Socket activated service are automatically ordered after
+    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>Additional implicit dependencies may be added as result of
+    execution and resource control parameters as documented in
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
   </refsect1>
 
   <refsect1>
         for, and its node will be bind-mounted over the default bus
         node location, so the service can only access the bus through
         its own endpoint. Note that custom bus endpoints default to a
-        'deny all' policy. Hence, if at least one
+        "deny all" policy. Hence, if at least one
         <varname>BusPolicy=</varname> directive is given, you have to
         make sure to add explicit rules for everything the service
         should be able to do.</para>
         <term><varname>ExecStart=</varname></term>
         <listitem><para>Commands with their arguments that are
         executed when this service is started. The value is split into
-        zero or more command lines is according to the rules described
+        zero or more command lines according to the rules described
         below (see section "Command Lines" below).
         </para>
 
 
         <para><varname>ExecStartPost=</varname> commands are only run after
         the service has started, as determined by <varname>Type=</varname>
-        (i.e. The process has been started for <varname>Type=simple</varname>
+        (i.e. the process has been started for <varname>Type=simple</varname>
         or <varname>Type=idle</varname>, the process exits successfully for
         <varname>Type=oneshot</varname>, the initial process exits successfully
         for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent
 
         <para>Note that it is usually not sufficient to specify a
         command for this setting that only asks the service to
-        terminate (for example by queuing some form of termination
+        terminate (for example, by queuing some form of termination
         signal for it), but does not wait for it to do so. Since the
         remaining processes of the services are killed using
         <constant>SIGKILL</constant> immediately after the command
-        exited this would not result in a clean stop. The specified
+        exited, this would not result in a clean stop. The specified
         command should hence be a synchronous operation, not an
         asynchronous one.</para></listitem>
       </varlistentry>
           </tgroup>
         </table>
 
-        <para>As exceptions to the setting above the service will not
+        <para>As exceptions to the setting above, the service will not
         be restarted if the exit code or signal is specified in
         <varname>RestartPreventExitStatus=</varname> (see below).
         Also, the services will always be restarted if the exit code
 
       <varlistentry>
         <term><varname>SuccessExitStatus=</varname></term>
-        <listitem><para>Takes a list of exit status definitions that
-        when returned by the main service process will be considered
+        <listitem><para>Takes a list of exit status definitions that,
+        when returned by the main service process, will be considered
         successful termination, in addition to the normal successful
         exit code 0 and the signals <constant>SIGHUP</constant>,
         <constant>SIGINT</constant>, <constant>SIGTERM</constant>, and
 
       <varlistentry>
         <term><varname>RestartPreventExitStatus=</varname></term>
-        <listitem><para>Takes a list of exit status definitions that
-        when returned by the main service process will prevent
+        <listitem><para>Takes a list of exit status definitions that,
+        when returned by the main service process, will prevent
         automatic service restarts, regardless of the restart setting
         configured with <varname>Restart=</varname>. Exit status
         definitions can either be numeric exit codes or termination
 
       <varlistentry>
         <term><varname>RestartForceExitStatus=</varname></term>
-        <listitem><para>Takes a list of exit status definitions that
-        when returned by the main service process will force automatic
+        <listitem><para>Takes a list of exit status definitions that,
+        when returned by the main service process, will force automatic
         service restarts, regardless of the restart setting configured
         with <varname>Restart=</varname>. The argument format is
         similar to
         <term><varname>Sockets=</varname></term>
         <listitem><para>Specifies the name of the socket units this
         service shall inherit socket file descriptors from when the
-        service is started. Normally it should not be necessary to use
-        this setting as all socket file descriptors whose unit shares
+        service is started. Normally, it should not be necessary to use
+        this setting, as all socket file descriptors whose unit shares
         the same name as the service (subject to the different unit
         name suffix of course) are passed to the spawned
         process.</para>
         to multiple processes simultaneously. Also note that a
         different service may be activated on incoming socket traffic
         than the one which is ultimately configured to inherit the
-        socket file descriptors. Or in other words: the
+        socket file descriptors. Or, in other words: the
         <varname>Service=</varname> setting of
         <filename>.socket</filename> units does not have to match the
         inverse of the <varname>Sockets=</varname> setting of the
         <option>reboot-immediate</option> causes immediate execution
         of the
         <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        system call, which might result in data loss. Similar,
+        system call, which might result in data loss. Similarly,
         <option>poweroff</option>, <option>poweroff-force</option>,
         <option>poweroff-immediate</option> have the effect of
         powering down the system with similar semantics. Defaults to
         <ulink
         url="https://www.kernel.org/doc/Documentation/usb/functionfs.txt">USB
         FunctionFS</ulink> descriptors, for implementation of USB
-        gadget functions. This is is used only in conjunction with a
+        gadget functions. This is used only in conjunction with a
         socket unit with <varname>ListenUSBFunction=</varname>
-        configured. The contents of this file is written to the
+        configured. The contents of this file are written to the
         <filename>ep0</filename> file after it is
         opened.</para></listitem>
       </varlistentry>
     contains, resulting in a single argument. Use
     <literal>$FOO</literal> as a separate word on the command line, in
     which case it will be replaced by the value of the environment
-    variable split at whitespace resulting in zero or more arguments.
+    variable split at whitespace, resulting in zero or more arguments.
     For this type of expansion, quotes are respected when splitting
     into words, and afterwards removed.</para>
 
@@ -1175,7 +1194,7 @@ WantedBy=multi-user.target</programlisting>
     <example>
       <title>Oneshot service</title>
 
-      <para>Sometimes units should just execute an action without
+      <para>Sometimes, units should just execute an action without
       keeping active processes, such as a filesystem check or a
       cleanup action on boot. For this,
       <varname>Type=</varname><option>oneshot</option> exists. Units
@@ -1194,10 +1213,10 @@ ExecStart=/usr/sbin/foo-cleanup
 WantedBy=multi-user.target</programlisting>
 
       <para>Note that systemd will consider the unit to be in the
-      state 'starting' until the program has terminated, so ordered
+      state "starting" until the program has terminated, so ordered
       dependencies will wait for the program to finish before starting
-      themselves. The unit will revert to the 'inactive' state after
-      the execution is done, never reaching the 'active' state. That
+      themselves. The unit will revert to the "inactive" state after
+      the execution is done, never reaching the "active" state. That
       means another request to start the unit will perform the action
       again.</para>
 
@@ -1214,9 +1233,9 @@ WantedBy=multi-user.target</programlisting>
       <para>Similarly to the oneshot services, there are sometimes
       units that need to execute a program to set up something and
       then execute another to shut it down, but no process remains
-      active while they are considered 'started'. Network
+      active while they are considered "started". Network
       configuration can sometimes fall into this category. Another use
-      case is if a oneshot service shall not be executed each time
+      case is if a oneshot service shall not be executed each time
       when they are pulled in as a dependency, but only the first
       time.</para>
 
@@ -1227,11 +1246,11 @@ WantedBy=multi-user.target</programlisting>
       types, but is most useful with
       <varname>Type=</varname><option>oneshot</option> and
       <varname>Type=</varname><option>simple</option>. With
-      <varname>Type=</varname><option>oneshot</option> systemd waits
+      <varname>Type=</varname><option>oneshot</option>, systemd waits
       until the start action has completed before it considers the
       unit to be active, so dependencies start only after the start
       action has succeeded. With
-      <varname>Type=</varname><option>simple</option> dependencies
+      <varname>Type=</varname><option>simple</option>, dependencies
       will start immediately after the start action has been
       dispatched. The following unit provides an example for a simple
       static firewall.</para>
@@ -1266,7 +1285,7 @@ WantedBy=multi-user.target</programlisting>
       <varname>RemainAfterExit=</varname><option>no</option>), the
       service is considered started.</para>
 
-      <para>Often a traditional daemon only consists of one process.
+      <para>Often, a traditional daemon only consists of one process.
       Therefore, if only one process is left after the original
       process terminates, systemd will consider that process the main
       process of the service. In that case, the
@@ -1281,7 +1300,7 @@ WantedBy=multi-user.target</programlisting>
       traditional PID file, systemd will be able to read the main PID
       from there. Please set <varname>PIDFile=</varname> accordingly.
       Note that the daemon should write that file before finishing
-      with its initialization, otherwise systemd might try to read the
+      with its initialization. Otherwise, systemd might try to read the
       file before it exists.</para>
 
       <para>The following example shows a simple daemon that forks and
@@ -1324,7 +1343,7 @@ ExecStart=/usr/sbin/simple-dbus-service
 [Install]
 WantedBy=multi-user.target</programlisting>
 
-      <para>For <emphasis>bus-activatable</emphasis> services, don't
+      <para>For <emphasis>bus-activatable</emphasis> services, do not
       include a <literal>[Install]</literal> section in the systemd
       service file, but use the <varname>SystemdService=</varname>
       option in the corresponding DBus service file, for example
@@ -1366,7 +1385,7 @@ ExecStart=/usr/sbin/simple-notifying-service
 WantedBy=multi-user.target</programlisting>
 
       <para>Note that the daemon has to support systemd's notification
-      protocol, else systemd will think the service hasn't started yet
+      protocol, else systemd will think the service has not started yet
       and kill it after a timeout. For an example of how to update
       daemons to support this protocol transparently, take a look at
       <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
index 87c2a3bce3aa6b45ebd49d6c0c600c2c5b12a0e4..5c87bf02608cd1477dbb551eaa6a0ebc1981d402 100644 (file)
     url="http://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New
     Control Group Interfaces</ulink> for an introduction on how to make
     use of slice units from programs.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Slice units automatically gain dependencies of type
+    <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
diff --git a/man/systemd.snapshot.xml b/man/systemd.snapshot.xml
deleted file mode 100644 (file)
index 96069c3..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?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 2010 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/>.
--->
-
-<refentry id="systemd.snapshot">
-  <refentryinfo>
-    <title>systemd.snapshot</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.snapshot</refentrytitle>
-    <manvolnum>5</manvolnum>
-  </refmeta>
-
-  <refnamediv>
-    <refname>systemd.snapshot</refname>
-    <refpurpose>Snapshot unit configuration</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <para><filename><replaceable>snapshot</replaceable>.snapshot</filename></para>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-
-    <para>Snapshot units are not configured via unit configuration
-    files. Nonetheless they are named similar to filenames. A unit
-    whose name ends in <literal>.snapshot</literal> refers to a
-    dynamic snapshot of the systemd runtime state.</para>
-
-    <para>Snapshots are not configured on disk but created dynamically
-    via <command>systemctl snapshot</command> (see
-    <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    for details) or an equivalent command. When created, they will
-    automatically get dependencies on the currently activated units.
-    They act as saved runtime state of the systemd manager. Later on,
-    the user may choose to return to the saved state via
-    <command>systemctl isolate</command>. They are useful to roll back
-    to a defined state after temporarily starting/stopping services or
-    similar.</para>
-  </refsect1>
-
-  <refsect1>
-      <title>See Also</title>
-      <para>
-        <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-      </para>
-  </refsect1>
-
-</refentry>
index 46a47b2d9527edc4c6d187b23b0e2f12fcc6e827..beac053bf0e61572d3b7d4e9d71814f3a2852dd7 100644 (file)
     service file).</para>
   </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Socket units automatically gain a <varname>Before=</varname>
+    dependency on the service units they activate.</para>
+
+    <para>Socket units referring to file system paths (such as AF_UNIX
+    sockets or FIFOs) implicitly gain <varname>Requires=</varname> and
+    <varname>After=</varname> dependencies on all mount units
+    necessary to access those paths.</para>
+
+    <para>Socket units using the <varname>BindToDevice=</varname>
+    setting automatically gain a <varname>BindsTo=</varname> and
+    <varname>After=</varname> dependency on the device unit
+    encapsulating the specified network interface.</para>
+
+    <para>If <varname>DefaultDependencies=yes</varname> is set (the
+    default), socket units automatically gain a
+    <varname>Before=</varname> dependency on
+    <filename>sockets.target</filename>. They also gain a pair of
+    <varname>After=</varname> and <varname>Requires=</varname>
+    dependency on <filename>sysinit.target</filename>, and a pair of
+    <varname>Before=</varname> and <varname>Conflicts=</varname>
+    dependencies on <filename>shutdown.target</filename>. These
+    dependencies ensure that the socket unit is started before normal
+    services at boot, and is stopped on shutdown.</para>
+
+    <para>Additional implicit dependencies may be added as result of
+    execution and resource control parameters as documented in
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+  </refsect1>
+
   <refsect1>
     <title>Options</title>
 
         refers to TCP sockets, <constant>SOCK_DGRAM</constant> (i.e.
         <varname>ListenDatagram=</varname>) to UDP.</para>
 
-        <para>These options may be specified more than once in which
+        <para>These options may be specified more than once, in which
         case incoming traffic on any of the sockets will trigger
         service activation, and all listed sockets will be passed to
         the service, regardless of whether there is incoming traffic
         implementation of USB gadget functions. This expects an
         absolute file system path as the argument. Behavior otherwise
         is very similar to the <varname>ListenFIFO=</varname>
-        directive above. Use this to open FunctionFS endpoint
+        directive above. Use this to open the FunctionFS endpoint
         <filename>ep0</filename>. When using this option, the
         activated service has to have the
         <varname>USBFunctionDescriptors=</varname> and
         <listitem><para>Specifies a network interface name to bind
         this socket to. If set, traffic will only be accepted from the
         specified network interfaces. This controls the
-        SO_BINDTODEVICE socket option (see
-        <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+        SO_BINDTODEVICE socket option (see <citerefentry
+        project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
         for details). If this option is used, an automatic dependency
         from this socket unit on the network interface device unit
         (<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        is created.</para></listitem>
+        is created. Note that setting this parameter might result in
+        additional dependencies to be added to the unit (see
+        above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         to work unmodified with systemd socket
         activation.</para>
 
-        <para>For IPv4 and IPv6 connections the <varname>REMOTE_ADDR</varname>
-        environment variable will contain the remote IP, and <varname>REMOTE_PORT</varname>
+        <para>For IPv4 and IPv6 connections, the <varname>REMOTE_ADDR</varname>
+        environment variable will contain the remote IP address, and <varname>REMOTE_PORT</varname>
         will contain the remote port. This is the same as the format used by CGI.
-        For SOCK_RAW the port is the IP protocol.</para></listitem>
+        For SOCK_RAW, the port is the IP protocol.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <listitem><para>Takes a boolean argument. May only be used in
         conjunction with <varname>ListenSpecial=</varname>. If true,
         the specified special file is opened in read-write mode, if
-        false in read-only mode. Defaults to false.</para></listitem>
+        false, in read-only mode. Defaults to false.</para></listitem>
       </varlistentry>
 
       <varlistentry>
 
       <varlistentry>
         <term><varname>KeepAliveTimeSec=</varname></term>
-        <listitem><para>Takes time (in seconds) as argument . The connection needs to remain
+        <listitem><para>Takes time (in seconds) as argument. The connection needs to remain
         idle before TCP starts sending keepalive probes. This controls the TCP_KEEPIDLE
         socket option (see
         <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
         <term><varname>KeepAliveIntervalSec=</varname></term>
         <listitem><para>Takes time (in seconds) as argument between
         individual keepalive probes, if the socket option SO_KEEPALIVE
-        has been set on this socket seconds as argument. This controls
+        has been set on this socket. This controls
         the TCP_KEEPINTVL socket option (see
         <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
         and the <ulink
 
       <varlistentry>
         <term><varname>KeepAliveProbes=</varname></term>
-        <listitem><para>Takes integer as argument. It's the number of
+        <listitem><para>Takes an integer as argument. It is the number of
         unacknowledged probes to send before considering the
         connection dead and notifying the application layer. This
         controls the TCP_KEEPCNT socket option (see
         with <varname>Accept=no</varname>. It defaults to the service
         that bears the same name as the socket (with the suffix
         replaced). In most cases, it should not be necessary to use
-        this option.</para></listitem>
+        this option. Note that setting this parameter might result in
+        additional dependencies to be added to the unit (see
+        above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>FileDescriptorName=</varname></term>
         <listitem><para>Assigns a name to all file descriptors this
         socket unit encapsulates. This is useful to help activated
-        services to identify specific file descriptors, if multiple
+        services identify specific file descriptors, if multiple fds
         are passed. Services may use the
         <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>
         call to acquire the names configured for the received file
         descriptors. Names may contain any ASCII character, but must
-        exclude control characters or <literal>:</literal>, and must
+        exclude control characters and <literal>:</literal>, and must
         be at most 255 characters in length. If this setting is not
-        used the file descriptor name defaults to the name of the
+        used, the file descriptor name defaults to the name of the
         socket unit, including its <filename>.socket</filename>
         suffix.</para></listitem>
       </varlistentry>
index 78bad4d814ef3e187290eed57623fee36fede215..54e7c49a9e4de676bece3ec9550ab9a3477b493c 100644 (file)
           for this target unit to all services (except for those with
           <varname>DefaultDependencies=no</varname>).</para>
 
-          <para>Usually this should pull-in all local mount points plus
+          <para>Usually, this should pull-in all local mount points plus
           <filename>/var</filename>, <filename>/tmp</filename> and
           <filename>/var/tmp</filename>, swap devices, sockets, timers,
           path units and other basic initialization necessary for general
         <term><filename>ctrl-alt-del.target</filename></term>
         <listitem>
           <para>systemd starts this target whenever Control+Alt+Del is
-          pressed on the console. Usually this should be aliased
+          pressed on the console. Usually, this should be aliased
           (symlinked) to <filename>reboot.target</filename>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><filename>default.target</filename></term>
         <listitem>
-          <para>The default unit systemd starts at bootup. Usually
+          <para>The default unit systemd starts at bootup. Usually,
           this should be aliased (symlinked) to
           <filename>multi-user.target</filename> or
           <filename>graphical.target</filename>.</para>
       <varlistentry>
         <term><filename>display-manager.service</filename></term>
         <listitem>
-          <para>The display manager service. Usually this should be
+          <para>The display manager service. Usually, this should be
           aliased (symlinked) to <filename>gdm.service</filename> or a
           similar display manager service.</para>
         </listitem>
           signal when running as user service daemon.</para>
 
           <para>Normally, this (indirectly) pulls in
-          <filename>shutdown.target</filename> which in turn should be
+          <filename>shutdown.target</filename>, which in turn should be
           conflicted by all units that want to be scheduled for
           shutdown when the service manager starts to exit.</para>
         </listitem>
index d9a39577d502e46bd425dc4e2308c08cac55fe13..c600405c87cf56cd90c60cdff4a7cdfc9cc95421 100644 (file)
 
     <para>Additional options are listed in
     <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-    which define the execution environment the
-    <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    binary is executed in, and in
+    which define the execution environment the <citerefentry
+    project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    binary is executed in, in
     <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-    which define the way the processes are terminated, and in
+    which define the way the these processes are
+    terminated, and in
     <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-    which configure resource control settings for the processes of the
-    service.</para>
+    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
     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>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
 
-    <para>All swap units automatically get the appropriate
-    dependencies on the devices or on the mount points of the files
+    <para>All swap units automatically get the
+    <varname>BindsTo=</varname> and <varname>After=</varname>
+    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 conflicting dependency to
+    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.</para>
+    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
+    <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
   </refsect1>
 
   <refsect1>
     <filename>/etc/fstab</filename> and a unit file, the configuration
     in the latter takes precedence.</para>
 
-    <para>When reading <filename>/etc/fstab</filename> a few special
+    <para>When reading <filename>/etc/fstab</filename>, a few special
     options are understood by systemd which influence how dependencies
     are created for swap units.</para>
 
         <term><option>noauto</option></term>
         <term><option>auto</option></term>
 
-        <listitem><para>With <option>noauto</option> the swap unit
+        <listitem><para>With <option>noauto</option>, the swap unit
         will not be added as a dependency for
         <filename>swap.target</filename>. This means that it will not
         be activated automatically during boot, unless it is pulled in
-        by some other unit. Option <option>auto</option> has the
+        by some other unit. The <option>auto</option> option has the
         opposite meaning and is the default.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><option>nofail</option></term>
 
-        <listitem><para>With <option>nofail</option> the swap unit
+        <listitem><para>With <option>nofail</option>, the swap unit
         will be only wanted, not required by
         <filename>swap.target</filename>. This means that the boot
         will continue even if this swap device is not activated
 
         <listitem><para>Swap priority to use when activating the swap
         device or file. This takes an integer. This setting is
-        optional and ignored when priority is set by <option>pri=</option> in the
-        <varname>Options=</varname> option.</para></listitem>
+        optional and ignored when the priority is set by <option>pri=</option> in the
+        <varname>Options=</varname> key.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index e790e9b77a91cd63caf011b85fb7a2d5057916db..bd4ab3903e7e94000ae42adf3c212a0bea224dbc 100644 (file)
     See
     <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     for details).</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
 
     <para>Unless <varname>DefaultDependencies=</varname> is set to
-    <option>false</option>, target units will implicitly complement
-    all configured dependencies of type <varname>Wants=</varname>,
-    <varname>Requires=</varname>,
-    <varname>RequiresOverridable=</varname> with dependencies of type
-    <varname>After=</varname> if the units in question also have
-    <varname>DefaultDependencies=true</varname>.
-    </para>
+    <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 64358351d5a764fcd7ef685201f35f0db63b982c..135eb35f1ba80604d77dd4d52a6412b0303a174f 100644 (file)
   <refsect1>
     <title>Parsing Timestamps</title>
 
-    <para>When parsing systemd will accept a similar timestamp syntax,
-    but excluding any timezone specification (this limitation might be
-    removed eventually). The weekday specification is optional, but
-    when the weekday is specified it must either be in the abbreviated
-    (<literal>Wed</literal>) or non-abbreviated
+    <para>When parsing, systemd will accept a similar syntax, but
+    expects no timezone specification, unless it is given as the
+    literal string "UTC". In this case, the time is considered in UTC,
+    otherwise in the local timezone. The weekday specification is
+    optional, but when the weekday is specified, it must either be in
+    the abbreviated (<literal>Wed</literal>) or non-abbreviated
     (<literal>Wednesday</literal>) English language form (case does
     not matter), and is not subject to the locale choice of the user.
     Either the date, or the time part may be omitted, in which case
     placeholders instead of timestamps: <literal>now</literal> may be
     used to refer to the current time (or of the invocation of the
     command that is currently executed). <literal>today</literal>,
-    <literal>yesterday</literal>, <literal>tomorrow</literal> refer to
-    00:00:00 of the current day, the day before or the next day,
+    <literal>yesterday</literal>, and <literal>tomorrow</literal> refer to
+    00:00:00 of the current day, the day before, or the next day,
     respectively.</para>
 
     <para>When parsing, systemd will also accept relative time
     00:00.</para>
 
     <para>Examples for valid timestamps and their normalized form
-    (assuming the current time was 2012-11-23 18:15:22):</para>
+    (assuming the current time was 2012-11-23 18:15:22 and the timezone
+    was UTC+8, for example TZ=Asia/Shanghai):</para>
 
     <programlisting>Fri 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13
     2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13
-       2012-11-23 → Fri 2012-11-23 00:00:00
-         12-11-23 → Fri 2012-11-23 00:00:00
-         11:12:13 → Fri 2012-11-23 11:12:13
-      11:12 → Fri 2012-11-23 11:12:00
-        now → Fri 2012-11-23 18:15:22
-      today → Fri 2012-11-23 00:00:00
-        yesterday → Fri 2012-11-22 00:00:00
-         tomorrow → Fri 2012-11-24 00:00:00
-         +3h30min → Fri 2012-11-23 21:45:22
-        -5s → Fri 2012-11-23 18:15:17
-        11min ago → Fri 2012-11-23 18:04:22
-      @1395716396 → Tue 2014-03-25 03:59:56</programlisting>
+2012-11-23 11:12:13 UTC → Fri 2012-11-23 19:12:13
+             2012-11-23 → Fri 2012-11-23 00:00:00
+               12-11-23 → Fri 2012-11-23 00:00:00
+               11:12:13 → Fri 2012-11-23 11:12:13
+       11:12:13.9900009 → Fri 2012-11-23 11:12:13
+                          format_timestamp_us: Fri 2012-11-23 11:12:13.990000
+                  11:12 → Fri 2012-11-23 11:12:00
+                    now → Fri 2012-11-23 18:15:22
+                  today → Fri 2012-11-23 00:00:00
+              today UTC → Fri 2012-11-23 16:00:00
+              yesterday → Fri 2012-11-22 00:00:00
+               tomorrow → Fri 2012-11-24 00:00:00
+               +3h30min → Fri 2012-11-23 21:45:22
+           +3h30min UTC → -EINVAL
+                    -5s → Fri 2012-11-23 18:15:17
+              11min ago → Fri 2012-11-23 18:04:22
+          11min ago UTC → -EINVAL
+            @1395716396 → Tue 2014-03-25 03:59:56</programlisting>
 
     <para>Note that timestamps printed by systemd will not be parsed
     correctly by systemd, as the timezone specification is not
     accepted, and printing timestamps is subject to locale settings
-    for the weekday while parsing only accepts English weekday
+    for the weekday, while parsing only accepts English weekday
     names.</para>
 
     <para>In some cases, systemd will display a relative timestamp
     second component is not specified, <literal>:00</literal> is
     assumed.</para>
 
-    <para>Timezone names may not be specified.</para>
+    <para>A timezone specification is not expected, unless it is given
+    as the literal string "UTC", similarly to timestamps.</para>
 
     <para>The special expressions
     <literal>minutely</literal>,
     <literal>*-*-01 00:00:00</literal>,
     <literal>Mon *-*-* 00:00:00</literal>,
     <literal>*-01-01 00:00:00</literal>,
-    <literal>*-01,04,07,10-01 00:00:0</literal> and
-    <literal>*-01,07-01 00:00:00</literal> respectively.
+    <literal>*-01,04,07,10-01 00:00:00</literal> and
+    <literal>*-01,07-01 00:00:00</literal>, respectively.
     </para>
 
     <para>Examples for valid timestamps and their
 
 <programlisting>   Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00
      Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00
-       Wed *-1 → Wed *-*-01 00:00:00
-     Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00
-    Wed, 17:48 → Wed *-*-* 17:48:00
+                   Wed *-1 → Wed *-*-01 00:00:00
+           Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00
+                Wed, 17:48 → Wed *-*-* 17:48:00
 Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
-         *-*-7 0:0:0 → *-*-07 00:00:00
-         10-15 → *-10-15 00:00:00
+               *-*-7 0:0:0 → *-*-07 00:00:00
+                     10-15 → *-10-15 00:00:00
        monday *-12-* 17:00 → Mon *-12-* 17:00:00
  Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45
       12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00
  mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45
-      03-05 08:05:40 → *-03-05 08:05:40
-      08:05:40 → *-*-* 08:05:40
-         05:40 → *-*-* 05:40:00
+            03-05 08:05:40 → *-03-05 08:05:40
+                  08:05:40 → *-*-* 08:05:40
+                     05:40 → *-*-* 05:40:00
     Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40
-    Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
-    2003-03-05 05:40 → 2003-03-05 05:40:00
-    2003-03-05 → 2003-03-05 00:00:00
-         03-05 → *-03-05 00:00:00
-        hourly → *-*-* *:00:00
-         daily → *-*-* 00:00:00
-       monthly → *-*-01 00:00:00
-        weekly → Mon *-*-* 00:00:00
-        yearly → *-01-01 00:00:00
-      annually → *-01-01 00:00:00
-         *:2/3 → *-*-* *:02/3:00</programlisting>
+          Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
+          2003-03-05 05:40 → 2003-03-05 05:40:00
+      2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC
+                2003-03-05 → 2003-03-05 00:00:00
+                     03-05 → *-03-05 00:00:00
+                    hourly → *-*-* *:00:00
+                     daily → *-*-* 00:00:00
+                 daily UTC → *-*-* 00:00:00 UTC
+                   monthly → *-*-01 00:00:00
+                    weekly → Mon *-*-* 00:00:00
+                    yearly → *-01-01 00:00:00
+                  annually → *-01-01 00:00:00
+                     *:2/3 → *-*-* *:02/3:00</programlisting>
 
       <para>Calendar events are used by timer units, see
       <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
index 20890f22700ab20165dd04a09bf8cb7454829162..8cf6c4683b3367606a9aca9f783cca2cf198bad4 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
+<?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">
 
     <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>
+  </refsect1>
+
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <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>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>
+    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>
         boot-up. The argument may also include time units. Example:
         "OnBootSec=5h 30min" means 5 hours and 30 minutes after
         boot-up. For details about the syntax of time spans, see
-        <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+        <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
 
         <para>If a timer configured with <varname>OnBootSec=</varname>
         or <varname>OnStartupSec=</varname> is already in the past
index 8985b6b94066f83180a1ec8a1f4292b87f8d8f1e..5b12378eda67b2891c33493acb7ddbce7feb3013 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
+<?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" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
@@ -60,7 +60,6 @@
     <filename><replaceable>target</replaceable>.target</filename>,
     <filename><replaceable>path</replaceable>.path</filename>,
     <filename><replaceable>timer</replaceable>.timer</filename>,
-    <filename><replaceable>snapshot</replaceable>.snapshot</filename>,
     <filename><replaceable>slice</replaceable>.slice</filename>,
     <filename><replaceable>scope</replaceable>.scope</filename></para>
 
@@ -90,7 +89,7 @@
     swap file or partition, a start-up target, a watched file system
     path, a timer controlled and supervised by
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-    a temporary system state snapshot, a resource management slice or
+    a resource management slice or
     a group of externally created processes. The syntax is inspired by
     <ulink
     url="http://standards.freedesktop.org/desktop-entry-spec/latest/">XDG
     <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-    <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-    <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+    <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
     <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
     </para>
 
     be parsed after the file itself is parsed. This is useful to alter
     or add configuration settings to a unit, without having to modify
     their unit files. Make sure that the file that is included has the
-    appropriate section headers before any directive. Note that for
-    instanced units this logic will first look for the instance
+    appropriate section headers before any directive. Note that, for
+    instanced units, this logic will first look for the instance
     <literal>.d/</literal> subdirectory and read its
     <literal>.conf</literal> files, followed by the template
     <literal>.d/</literal> subdirectory and reads its
          consider it mostly obsolete, and want people to
          use .d/ drop-ins instead. -->
 
-    <para>Note that while systemd offers a flexible dependency system
-    between units it is recommended to use this functionality only
-    sparingly and instead rely on techniques such as bus-based or
-    socket-based activation which make dependencies implicit,
-    resulting in a both simpler and more flexible system.</para>
-
     <para>Some unit names reflect paths existing in the file system
     namespace. Example: a device unit
     <filename>dev-sda.device</filename> refers to a device with the
     device node <filename noindex='true'>/dev/sda</filename> in the
     file system namespace. If this applies, a special way to escape
     the path name is used, so that the result is usable as part of a
-    filename. Basically, given a path, "/" is replaced by "-" and all
+    filename. Basically, given a path, "/" is replaced by "-", and all
     other characters which are not ASCII alphanumerics are replaced by
     C-style "\x2d" escapes (except that "_" is never replaced and "."
     is only replaced when it would be the first character in the
 
   </refsect1>
 
+  <refsect1>
+    <title>Automatic Dependencies</title>
+
+    <para>Note that while systemd offers a flexible dependency system
+    between units it is recommended to use this functionality only
+    sparingly and instead rely on techniques such as bus-based or
+    socket-based activation which make dependencies implicit,
+    resulting in a both simpler and more flexible system.</para>
+
+    <para>A number of unit dependencies are automatically established,
+    depending on unit configuration. On top of that, for units with
+    <varname>DefaultDependencies=yes</varname> (the default) a couple
+    of additional dependencies are added. The precise effect of
+    <varname>DefaultDependencies=yes</varname> depends on the unit
+    type (see below).</para>
+
+    <para>If <varname>DefaultDependencies=yes</varname> is set, units
+    that are referenced by other units of type
+    <filename>.target</filename> via a <varname>Wants=</varname> or
+    <varname>Requires=</varname> dependency might automatically gain
+    an <varname>Before=</varname> dependency too. See
+    <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+    for details.</para>
+  </refsect1>
+
   <refsect1>
     <title>Unit File Load Path</title>
 
     in directories listed earlier override files with the same name in
     directories lower in the list.</para>
 
-    <para>When systemd is running in user mode
-    (<option>--user</option>) and the variable
-    <varname>$SYSTEMD_UNIT_PATH</varname> is set, the contents of this
-    variable overrides the unit load path. If
+    <para>When the variable <varname>$SYSTEMD_UNIT_PATH</varname> is set,
+    the contents of this variable overrides the unit load path. If
     <varname>$SYSTEMD_UNIT_PATH</varname> ends with an empty component
     (<literal>:</literal>), the usual unit load path will be appended
     to the contents of the variable.</para>
   <refsect1>
     <title>[Unit] Section Options</title>
 
-    <para>Unit file may include a [Unit] section, which carries
+    <para>The unit file may include a [Unit] section, which carries
     generic information about the unit that is not dependent on the
     type of unit:</para>
 
         with <varname>After=</varname> or <varname>Before=</varname>,
         then both units will be started simultaneously and without any
         delay between them if <filename>foo.service</filename> is
-        activated. Often it is a better choice to use
+        activated. Often, it is a better choice to use
         <varname>Wants=</varname> instead of
         <varname>Requires=</varname> in order to achieve a system that
         is more robust when dealing with failing services.</para>
         <para>Note that dependencies of this type may also be
         configured outside of the unit configuration file by adding a
         symlink to a <filename>.requires/</filename> directory
-        accompanying the unit file. For details see
+        accompanying the unit file. For details, see
         above.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><varname>RequiresOverridable=</varname></term>
-
-        <listitem><para>Similar to <varname>Requires=</varname>.
-        Dependencies listed in <varname>RequiresOverridable=</varname>
-        which cannot be fulfilled or fail to start are ignored if the
-        startup was explicitly requested by the user. If the start-up
-        was pulled in indirectly by some dependency or automatic
-        start-up of units that is not requested by the user, this
-        dependency must be fulfilled and otherwise the transaction
-        fails. Hence, this option may be used to configure
-        dependencies that are normally honored unless the user
-        explicitly starts up the unit, in which case whether they
-        failed or not is irrelevant.</para></listitem>
-
-      </varlistentry>
       <varlistentry>
         <term><varname>Requisite=</varname></term>
-        <term><varname>RequisiteOverridable=</varname></term>
 
-        <listitem><para>Similar to <varname>Requires=</varname> and
-        <varname>RequiresOverridable=</varname>, respectively.
+        <listitem><para>Similar to <varname>Requires=</varname>.
         However, if the units listed here are not started already,
         they will not be started and the transaction will fail
         immediately. </para></listitem>
         <option>false</option>.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><varname>IgnoreOnSnapshot=</varname></term>
-
-        <listitem><para>Takes a boolean argument. If
-        <option>true</option>, this unit will not be included in
-        snapshots. Defaults to <option>true</option> for device and
-        snapshot units, <option>false</option> for the
-        others.</para></listitem>
-      </varlistentry>
-
       <varlistentry>
         <term><varname>StopWhenUnneeded=</varname></term>
 
         <listitem><para>Takes a boolean argument. If
         <option>true</option>, this unit will be stopped when it is no
-        longer used. Note that in order to minimize the work to be
+        longer used. Note that, in order to minimize the work to be
         executed, systemd will not stop units by default unless they
         are conflicting with other units, or the user explicitly
         requested their shut down. If this option is set, a unit will
         <term><varname>JobTimeoutAction=</varname></term>
         <term><varname>JobTimeoutRebootArgument=</varname></term>
 
-        <listitem><para>When a job for this unit is queued a time-out
+        <listitem><para>When a job for this unit is queued, a time-out
         may be configured. If this time limit is reached, the job will
         be cancelled, the unit however will not change state or even
         enter the <literal>failed</literal> mode. This value defaults
         <term><varname>ConditionFileNotEmpty=</varname></term>
         <term><varname>ConditionFileIsExecutable=</varname></term>
 
-        <!-- We don't document ConditionNull=
-             here as it is not particularly
+        <!-- We do not document ConditionNull=
+             here, as it is not particularly
              useful and probably just
              confusing. -->
 
         <varname>lxc</varname>,
         <varname>lxc-libvirt</varname>,
         <varname>systemd-nspawn</varname>,
-        <varname>docker</varname> to test
+        <varname>docker</varname>,
+        <varname>rkt</varname> to test
         against a specific implementation. See
         <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         for a full list of known virtualization technologies and their
 
         <para><varname>ConditionSecurity=</varname> may be used to
         check whether the given security module is enabled on the
-        system. Currently the recognized values values are
+        system. Currently, the recognized values values are
         <varname>selinux</varname>,
         <varname>apparmor</varname>,
         <varname>ima</varname>,
 
         <listitem><para>Similar to the
         <varname>ConditionArchitecture=</varname>,
-        <varname>ConditionVirtualization=</varname>, ... condition
-        settings described above these settings add assertion checks
+        <varname>ConditionVirtualization=</varname>, etc., condition
+        settings described above, these settings add assertion checks
         to the start-up of the unit. However, unlike the conditions
-        settings any assertion setting that is not met results in
+        settings, any assertion setting that is not met results in
         failure of the start job it was triggered
         by.</para></listitem>
       </varlistentry>
         units.</para></listitem>
       </varlistentry>
 
-      <varlistentry>
-        <term><varname>NetClass=</varname></term>
-        <listitem><para>Configures a network class number to assign to the
-        unit. This value will be set to the
-        <literal>net_cls.class_id</literal> property of the
-        <literal>net_cls</literal> cgroup of the unit. The directive
-        accepts a numerical value (for fixed number assignment) and the keyword
-        <literal>auto</literal> (for dynamic allocation). Network traffic of
-        all processes inside the unit will have the network class ID assigned
-        by the kernel. Also see
-        the kernel docs for
-        <ulink url="https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt">net_cls controller</ulink>
-        and
-        <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-        </para></listitem>
-      </varlistentry>
     </variablelist>
 
   </refsect1>
           <row>
       <entry><literal>%u</literal></entry>
       <entry>User name</entry>
-      <entry>This is the name of the configured user of the unit, or (if none is set) the user running the systemd instance.</entry>
+      <entry>This is the name of the user running the service manager instance. In case of the system manager this resolves to <literal>root</literal>.</entry>
           </row>
           <row>
       <entry><literal>%U</literal></entry>
       <entry>User UID</entry>
-      <entry>This is the numeric UID of the configured user of the unit, or (if none is set) the user running the systemd user instance. Note that this specifier is not available for units run by the systemd system instance (as opposed to those run by a systemd user instance), unless the user has been configured as a numeric UID in the first place or the configured user is the root user.</entry>
+      <entry>This is the numeric UID of the user running the service manager instance. In case of the system manager this resolves to <literal>0</literal>.</entry>
           </row>
           <row>
       <entry><literal>%h</literal></entry>
       <entry>User home directory</entry>
-      <entry>This is the home directory of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to <literal>%U</literal>, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user.</entry>
+      <entry>This is the home directory of the user running the service manager instance. In case of the system manager this resolves to <literal>/root</literal>.</entry>
           </row>
           <row>
       <entry><literal>%s</literal></entry>
       <entry>User shell</entry>
-      <entry>This is the shell of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to <literal>%U</literal>, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user.</entry>
+      <entry>This is the shell of the user running the service manager instance. In case of the system manager this resolves to <literal>/bin/sh</literal>.</entry>
           </row>
           <row>
       <entry><literal>%m</literal></entry>
@@ -1448,7 +1420,6 @@ PrivateTmp=yes</programlisting>
       <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
index 8d74ca49c3f5160de8cc0df9ba99141d780c52a8..6de18f8294c6db374a645ba90269bd0b8fcffcc9 100644 (file)
         run a system instance, even if the process ID is not 1, i.e.
         systemd is not run as init process. <option>--user</option>
         does the opposite, running a user instance even if the process
-        ID is 1. Normally it should not be necessary to pass these
+        ID is 1. Normally, it should not be necessary to pass these
         options, as systemd automatically detects the mode it is
         started in. These options are hence of little use except for
         debugging. Note that it is not supported booting and
         <term><option>--crash-vt=</option><replaceable>VT</replaceable></term>
 
         <listitem><para>Switch to a specific virtual console (VT) on
-        crash. Takes a positive integer in the range 1..63, or a
+        crash. Takes a positive integer in the range 163, or a
         boolean argument. If an integer is passed, selects which VT to
         switch to. If <constant>yes</constant>, the VT kernel messages
         are written to is selected. If <constant>no</constant>, no VT
 
     <orderedlist>
       <listitem><para>Service units, which start and control daemons
-      and the processes they consist of. For details see
+      and the processes they consist of. For details, see
       <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
 
       <listitem><para>Socket units, which encapsulate local IPC or
       network sockets in the system, useful for socket-based
-      activation. For details about socket units see
+      activation. For details about socket units, see
       <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
       for details on socket-based activation and other forms of
       activation, see
 
       <listitem><para>Device units expose kernel devices in systemd
       and may be used to implement device-based activation. For
-      details see
+      details, see
       <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
 
       <listitem><para>Mount units control mount points in the file
       boot-up. See
       <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
 
-      <listitem><para>Snapshot units can be used to temporarily save
-      the state of the set of systemd units, which later may be
-      restored by activating the saved snapshot unit. For more
-      information see
-      <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
-
       <listitem><para>Timer units are useful for triggering activation
       of other units based on timers. You may find details in
       <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
     <para>On boot systemd activates the target unit
     <filename>default.target</filename> whose job is to activate
     on-boot services and other on-boot units by pulling them in via
-    dependencies. Usually the unit name is just an alias (symlink) for
+    dependencies. Usually, the unit name is just an alias (symlink) for
     either <filename>graphical.target</filename> (for fully-featured
     boots into the UI) or <filename>multi-user.target</filename> (for
     limited console-only boots for use in embedded or server
 
     <para>Units may be generated dynamically at boot and system
     manager reload time, for example based on other configuration
-    files or parameters passed on the kernel command line. For details see
+    files or parameters passed on the kernel command line. For details, see
     <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
 
     <para>Systems which invoke systemd in a container or initrd
         <filename>ctrl-alt-del.target</filename> unit. This is mostly
         equivalent to <command>systemctl start
         ctl-alt-del.target</command>. If this signal is received more
-        often than 7 times per 2s an immediate reboot is triggered.
+        than 7 times per 2s, an immediate reboot is triggered.
         Note that pressing Ctrl-Alt-Del on the console will trigger
-        this signal. Hence, if a reboot is hanging pressing
+        this signal. Hence, if a reboot is hanging, pressing
         Ctrl-Alt-Del more than 7 times in 2s is a relatively safe way
         to trigger an immediate reboot.</para>
 
         <term><constant>SIGUSR2</constant></term>
 
         <listitem><para>When this signal is received the systemd
-        manager will log its complete state in human readable form.
+        manager will log its complete state in human-readable form.
         The data logged is the same as printed by
         <command>systemd-analyze dump</command>.</para></listitem>
       </varlistentry>
         <term><varname>systemd.crash_chvt=</varname></term>
 
         <listitem><para>Takes a positive integer, or a boolean
-        argument. If a positive integer (in the range 1..63) is
-        specified the system manager (PID 1) will activate the specified
+        argument. If a positive integer (in the range 163) is
+        specified, the system manager (PID 1) will activate the specified
         virtual terminal (VT) when it crashes. Defaults to
         <constant>no</constant>, meaning that no such switch is
-        attempted. If set to <constant>yes</constant> the VT the
+        attempted. If set to <constant>yes</constant>, the VT the
         kernel messages are written to is selected.</para></listitem>
       </varlistentry>
 
         like <option>false</option> until a service fails or there is
         a significant delay in boot.  Defaults to
         <option>yes</option>, unless <option>quiet</option> is passed
-        as kernel command line option in which case it defaults to
+        as kernel command line option, in which case it defaults to
         <constant>auto</constant>.</para></listitem>
       </varlistentry>
 
 
         <listitem><para>Set the system locale to use. This overrides
         the settings in <filename>/etc/locale.conf</filename>. For
-        more information see
+        more information, see
         <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         and
         <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
index 11cb83388ff86351b8ecd74d35599d9759e967af..42b53b2759de38f121b6e23aec883c0f6590e38a 100644 (file)
@@ -121,7 +121,7 @@ u root 0 "Superuser" /root</programlisting>
           <term><varname>r</varname></term>
           <listitem><para>Add a range of numeric UIDs/GIDs to the pool
           to allocate new UIDs and GIDs from. If no line of this type
-          is specified the range of UIDs/GIDs is set to some
+          is specified, the range of UIDs/GIDs is set to some
           compiled-in default. Note that both UIDs and GIDs are
           allocated from the same pool, in order to ensure that users
           and groups of the same name are likely to carry the same
@@ -143,32 +143,32 @@ u root 0 "Superuser" /root</programlisting>
       all system and group names with the underscore, and avoiding too
       generic names.</para>
 
-      <para>For <varname>m</varname> lines this field should contain
+      <para>For <varname>m</varname> lines, this field should contain
       the user name to add to a group.</para>
 
-      <para>For lines of type <varname>r</varname> this field should
+      <para>For lines of type <varname>r</varname>, this field should
       be set to <literal>-</literal>.</para>
     </refsect2>
 
     <refsect2>
       <title>ID</title>
 
-      <para>For <varname>u</varname> and <varname>g</varname> the
-      numeric 32bit UID or GID of the user/group. Do not use IDs 65535
+      <para>For <varname>u</varname> and <varname>g</varname>, the
+      numeric 32-bit UID or GID of the user/group. Do not use IDs 65535
       or 4294967295, as they have special placeholder meanings.
       Specify <literal>-</literal> for automatic UID/GID allocation
       for the user or group. Alternatively, specify an absolute path
-      in the file system. In this case the UID/GID is read from the
+      in the file system. In this case, the UID/GID is read from the
       path's owner/group. This is useful to create users whose UID/GID
       match the owners of pre-existing files (such as SUID or SGID
       binaries).</para>
 
-      <para>For <varname>m</varname> lines this field should contain
+      <para>For <varname>m</varname> lines, this field should contain
       the group name to add to a user to.</para>
 
-      <para>For lines of type <varname>r</varname> this field should
+      <para>For lines of type <varname>r</varname>, this field should
       be set to a UID/GID range in the format
-      <literal>FROM-TO</literal> where both values are formatted as
+      <literal>FROM-TO</literal>, where both values are formatted as
       decimal ASCII numbers. Alternatively, a single UID/GID may be
       specified formatted as decimal ASCII numbers.</para>
     </refsect2>
@@ -188,7 +188,7 @@ u root 0 "Superuser" /root</programlisting>
     <refsect2>
       <title>Home Directory</title>
 
-      <para>The home directory for a new system user. If omitted
+      <para>The home directory for a new system user. If omitted,
       defaults to the root directory. It is recommended to not
       unnecessarily specify home directories for system users, unless
       software strictly requires one to be set.</para>
@@ -207,7 +207,7 @@ u root 0 "Superuser" /root</programlisting>
 
     <para>Note that <command>systemd-sysusers</command> will do
     nothing if the specified users or groups already exist, so
-    normally there no reason to override
+    normally, there is no reason to override
     <filename>sysusers.d</filename> vendor configuration, except to
     block certain users or groups from being created.</para>
   </refsect1>
index c439bc56ede96669ca787130151db0ae7f0438f9..415e2c799a448a66941c43ddfa62fb42f4f4b8b2 100644 (file)
         on. Note that whether network time synchronization is on
         simply reflects whether the
         <filename>systemd-timesyncd.service</filename> unit is
-        enabled. Even if this command shows the status as off a
+        enabled. Even if this command shows the status as off, a
         different service might still synchronize the clock with the
         network.</para></listitem>
       </varlistentry>
 
         <para>Note that even if time synchronization is turned off
         with this command, another unrelated system service might
-        still synchronize the clock with the network. Also note that
-        strictly speaking
+        still synchronize the clock with the network. Also note that,
+        strictly speaking,
         <filename>systemd-timesyncd.service</filename> does more than
-        just network time synchronization as it ensures a monotonic
+        just network time synchronization, as it ensures a monotonic
         clock on systems without RTC even if no network is
         available. See
         <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
index c883685c97e0599d56687eb3f1146c31f26eaf48..10c2de89f6a36dcf65810b053f45853d0c5bc3c7 100644 (file)
@@ -72,7 +72,7 @@
 
       <varlistentry>
         <term><varname>NTP=</varname></term>
-        <listitem><para>A space separated list of NTP server host
+        <listitem><para>A space-separated list of NTP server host
         names or IP addresses. During runtime this list is combined
         with any per-interface NTP servers acquired from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
@@ -84,7 +84,7 @@
 
       <varlistentry>
         <term><varname>FallbackNTP=</varname></term>
-        <listitem><para>A space separated list of NTP server host
+        <listitem><para>A space-separated list of NTP server host
         names or IP addresses to be used as the fallback NTP servers.
         Any per-interface NTP servers obtained from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
index 8d3ed37ae3f628cba2ef25d513e7c777f1668b36..3f6128cb5b34f498e38545bd75877ec7a66e235c 100644 (file)
@@ -1,5 +1,4 @@
-<?xml version="1.0"?>
-<!--*-nxml-*-->
+<?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.
     prefix and suffix of each other, then the prefix is always
     processed first, the suffix later. Lines that take globs are
     applied after those accepting no globs. If multiple operations
-    shall be applied on the same file (such as ACL, xattr, file
-    attribute adjustments) these are always done in the same fixed
+    shall be applied on the same file, (such as ACL, xattr, file
+    attribute adjustments), these are always done in the same fixed
     order. Otherwise, the files/directories are processed in the order
     they are listed.</para>
 
           <term><varname>v</varname></term>
           <listitem><para>Create a subvolume if the path does not
           exist yet and the file system supports this
-          (btrfs). Otherwise create a normal directory, in the same
-          way as <varname>d</varname>.</para></listitem>
+          (btrfs). Otherwise, create a normal directory, in the same
+          way as <varname>d</varname>. A subvolume created with this
+          line type is not assigned to any higher-level quota
+          group. For that, use <varname>q</varname> or
+          <varname>Q</varname>, which allow creating simple quota group
+          hierarchies, see below.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>q</varname></term>
+          <listitem><para>Similar to <varname>v</varname>. However,
+          makes sure that the subvolume will be assigned to the same
+          higher-level quota groups as the subvolume it has been
+          created in. This ensures that higher-level limits and
+          accounting applied to the parent subvolume also include the
+          specified subvolume. On non-btrfs file systems, this line
+          type is identical to <varname>d</varname>. If the subvolume
+          already exists and is already assigned to one or more higher
+          level quota groups, no change to the quota hierarchy is
+          made. Also see <varname>Q</varname> below. See <citerefentry
+          project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+          for details about the btrfs quota group
+          concept.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>Q</varname></term>
+          <listitem><para>Similar to <varname>q</varname>. However,
+          instead of copying the higher-level quota group assignments
+          from the parent as-is, the lowest quota group of the parent
+          subvolume is determined that is not the leaf quota
+          group. Then, an "intermediary" quota group is inserted that
+          is one level below this level, and shares the same ID part
+          as the specified subvolume. If no higher-level quota group
+          exists for the parent subvolume, a new quota group at level
+          255 sharing the same ID as the specified subvolume is
+          inserted instead. This new intermediary quota group is then
+          assigned to the parent subvolume's higher-level quota
+          groups, and the specified subvolume's leaf quota group is
+          assigned to it.</para>
+
+          <para>Effectively, this has a similar effect as
+          <varname>q</varname>, however introduces a new higher-level
+          quota group for the specified subvolume that may be used to
+          enforce limits and accounting to the specified subvolume and
+          children subvolume created within it. Thus, by creating
+          subvolumes only via <varname>q</varname> and
+          <varname>Q</varname>, a concept of "subtree quotas" is
+          implemented. Each subvolume for which <varname>Q</varname>
+          is set will get a "subtree" quota group created, and all
+          child subvolumes created within it will be assigned to
+          it. Each subvolume for which <varname>q</varname> is set
+          will not get such a "subtree" quota group, but it is ensured
+          that they are added to the same "subtree" quota group as their
+          immediate parents.</para>
+
+          <para>It is recommended to use
+          <varname>Q</varname> for subvolumes that typically contain
+          further subvolumes, and where it is desirable to have
+          accounting and quota limits on all child subvolumes
+          together. Examples for <varname>Q</varname> are typically
+          <filename>/home</filename> or
+          <filename>/var/lib/machines</filename>. In contrast,
+          <varname>q</varname> should be used for subvolumes that
+          either usually do not include further subvolumes or where no
+          accounting and quota limits are needed that apply to all
+          child subvolumes together. Examples for <varname>q</varname>
+          are typically <filename>/var</filename> or
+          <filename>/var/tmp</filename>. As with <varname>Q</varname>,
+          <varname>q</varname> has no effect on the quota group
+          hierarchy if the subvolume exists and already has at least
+          one higher-level quota group assigned.</para></listitem>
         </varlistentry>
 
         <varlistentry>
           <varname>+</varname> (the default one) causes the
           attribute(s) to be added; <varname>-</varname> causes the
           attribute(s) to be removed; <varname>=</varname> causes the
-          attributes to set exactly as the following letters. The
+          attributes to be set exactly as the following letters. The
           letters <literal>aAcCdDeijsStTu</literal> select the new
           attributes for the files, see
-          <citerefentry><refentrytitle>chattr</refentrytitle>
+          <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle>
           <manvolnum>1</manvolnum></citerefentry> for further information.
           </para>
           <para>Passing only <varname>=</varname> as argument resets
           all the file attributes listed above. It has to be pointed
-          out that the <varname>=</varname> prefix, limits itself to
+          out that the <varname>=</varname> prefix limits itself to
           the attributes corresponding to the letters listed here. All
           other attributes will be left untouched. Does not follow
           symlinks.</para>
           <term><varname>a</varname></term>
           <term><varname>a+</varname></term>
           <listitem><para>Set POSIX ACLs (access control lists). If
-          suffixed with <varname>+</varname>, specified entries will
+          suffixed with <varname>+</varname>, the specified entries will
           be added to the existing set.
           <command>systemd-tmpfiles</command> will automatically add
           the required base entries for user and group based on the
       <para>The user and group to use for this file or directory. This
       may either be a numeric user/group ID or a user or group
       name. If omitted or when set to <literal>-</literal>, the
-      default 0 (root) is used. For <varname>z</varname>,
+      default 0 (root) is used. For <varname>z</varname> and
       <varname>Z</varname> lines, when omitted or when set to
       <literal>-</literal>, the file ownership will not be
       modified. These parameters are ignored for <varname>x</varname>,
       delete when cleaning. If a file or directory is older than the
       current time minus the age field, it is deleted. The field
       format is a series of integers each followed by one of the
-      following postfixes for the respective time units:
+      following suffixes for the respective time units:
       <constant>s</constant>,
       <constant>m</constant> or <constant>min</constant>,
       <constant>h</constant>,
       <constant>d</constant>,
       <constant>w</constant>,
-      <constant>ms</constant>,
+      <constant>ms</constant>, and
       <constant>us</constant>,
-      respectively meaning seconds, minutes, hours, days, weeks,
-      milliseconds, and microseconds. Full names of the time units can
+      meaning seconds, minutes, hours, days, weeks,
+      milliseconds, and microseconds, respectively. Full names of the time units can
       be used too.
       </para>
 
       <para>When the age is set to zero, the files are cleaned
       unconditionally.</para>
 
-      <para>The age field only applies to lines
-      starting with <varname>d</varname>,
-      <varname>D</varname>, and
-      <varname>x</varname>. If omitted or set to
-      <literal>-</literal>, no automatic clean-up is
-      done.</para>
+      <para>The age field only applies to lines starting with
+      <varname>d</varname>, <varname>D</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
+      <literal>-</literal>, no automatic clean-up is done.</para>
 
       <para>If the age field starts with a tilde character
       <literal>~</literal>, the clean-up is only applied to files and
       <title>Argument</title>
 
       <para>For <varname>L</varname> lines determines the destination
-      path of the symlink. For <varname>c</varname>,
-      <varname>b</varname> determines the major/minor of the device
+      path of the symlink. For <varname>c</varname> and
+      <varname>b</varname>, determines the major/minor of the device
       node, with major and minor formatted as integers, separated by
       <literal>:</literal>, e.g.  <literal>1:3</literal>. For
       <varname>f</varname>, <varname>F</varname>, and
-      <varname>w</varname> may be used to specify a short string that
+      <varname>w</varname>, the argument may be used to specify a short string that
       is written to the file, suffixed by a newline. For
       <varname>C</varname>, specifies the source file or
-      directory. For <varname>t</varname>, <varname>T</varname>
+      directory. For <varname>t</varname> and <varname>T</varname>,
       determines extended attributes to be set. For
-      <varname>a</varname>, <varname>A</varname> determines ACL
-      attributes to be set. For <varname>h</varname>,
-      <varname>H</varname> determines the file attributes to
+      <varname>a</varname> and <varname>A</varname>, determines ACL
+      attributes to be set. For <varname>h</varname> and
+      <varname>H</varname>, determines the file attributes to
       set. Ignored for all other lines.</para>
     </refsect2>
 
@@ -571,7 +640,9 @@ x /var/tmp/abrt/*</programlisting>
       <citerefentry project='man-pages'><refentrytitle>setfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>getfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry project='die-net'><refentrytitle>btrfs-subvolume</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 2e1655bf553137da4c5309f38e7de37a1b00c57c..dd5563605ca63cc704b7804e3074da8824993cf1 100644 (file)
                 <term><literal>program</literal></term>
                 <listitem>
                   <para>Execute an external program specified as the assigned
-                  value and if it returns successfully
+                  value and, if it returns successfully,
                   import its output, which must be in environment key
                   format. Path specification, command/argument separation,
                   and quoting work like in <varname>RUN</varname>.</para>
               <varlistentry>
                 <term><option>string_escape=<replaceable>none|replace</replaceable></option></term>
                 <listitem>
-                  <para>Usually control and other possibly unsafe characters are replaced
+                  <para>Usually, control and other possibly unsafe characters are replaced
                   in strings used for device naming. The mode of replacement can be specified
                   with this option.</para>
                 </listitem>
index b3062ae4a8432020cbaadc7197d7b4d6d243d307..ca9763fedf275d3f75cfadaba3f77357a6e1a6e6 100644 (file)
     <function>udev_device_get_parent_with_subsystem_devtype()</function>
     return a pointer to the parent device. No additional reference
     to this device is acquired, but the child device owns a reference
-    to such parent device. On failure, <constant>NULL</constant>
+    to such parent device. On failure, <constant>NULL</constant>
     is returned.</para>
 
     <para>On success, <function>udev_device_get_is_initialized()</function>
index 9c4ab7a1bf363368c5428f55d44beca17ee77907..11db1a0fab9f3af4dfa0677405bb351cb870f018 100644 (file)
     <function>udev_device_new_from_subsystem_sysname</function>, and
     <function>udev_device_new_from_device_id</function>
     create the device object based on information found in
-    <filename>/sys</filename> annotated with properties from the udev-internal
+    <filename>/sys</filename>, annotated with properties from the udev-internal
     device database. A syspath is any subdirectory of <filename>/sys</filename>,
     with the restriction that a subdirectory of <filename>/sys/devices</filename>
     (or a symlink to one) represents a real device and as such must contain
     and
     <citerefentry><refentrytitle>udev_device_get_sysname</refentrytitle><manvolnum>3</manvolnum></citerefentry>)
     and <function>udev_device_new_from_device_id</function> looks up devices based on the provided
-    device id which is a special string in one of the following four forms:
+    device ID, which is a special string in one of the following four forms:
     <table>
       <title>Device ID strings</title>
 
index 73566f50890490657191f5ed6b9dedd3c02df916..e0b6bfba32e5f3d9c156d334cb4330d59025d21c 100644 (file)
     <constant>NULL</constant> is returned.</para>
 
     <para><function>udev_enumerate_get_udev()</function> always
-    returns a pointer to the udev context that this enumerate
+    returns a pointer to the udev context that this enumerated
     object is associated with.</para>
   </refsect1>
 
index 6e033bdc813e1b639204e4f2454ea085b74e4800..a1b531d52a8162feb8882e5c7fe55677f3684f88 100644 (file)
     <function>udev_list_entry_get_name()</function> and
     <function>udev_list_entry_get_value()</function> return a
     pointer to a constant string representing the requested value.
-    The string is bound to the lifetime of the list-entry itself.
+    The string is bound to the lifetime of the list entry itself.
     On failure, <constant>NULL</constant> is returned.</para>
   </refsect1>
 
index 8ef9e23aa2a6cc940941b22bc9072a2ff56cc9e3..8c1abd2770cfaaf12164d69a2bcf58ea9bcb0193 100644 (file)
         </varlistentry>
       </variablelist>
 
-      <para>In addition an optional positional argument can be used
+      <para>In addition, an optional positional argument can be used
       to specify a device name or a sys path. It must start with
       <filename>/dev</filename> or <filename>/sys</filename>
       respectively.</para>
           <term><option>--name-match=<replaceable>NAME</replaceable></option></term>
           <listitem>
             <para>Trigger events for devices with a matching
-            device path. This options can be specified multiple
+            device path. This option can be specified multiple
             times.</para>
           </listitem>
         </varlistentry>
         </varlistentry>
       </variablelist>
 
-      <para>In addition optional positional arguments can be used
+      <para>In addition, optional positional arguments can be used
       to specify device names or sys paths. They must start with
       <filename>/dev</filename> or <filename>/sys</filename>
       respectively.</para>
index db05932efd9a584a507133d0c65385a2b35f028e..2774a3228f4341a67220e12df25804f6462889e1 100644 (file)
@@ -12,6 +12,7 @@ uk
 sv
 sr
 es
+zh_CN
 zh_TW
 be
 be@latin
index 51254ec5333f2394a9b099ab9cae34f23b569e9a..b56a9984c4ce655db1c8b4cceea48658c92358c8 100644 (file)
@@ -6,7 +6,6 @@ src/core/dbus-mount.c
 src/core/dbus-path.c
 src/core/dbus-service.c
 src/core/dbus-slice.c
-src/core/dbus-snapshot.c
 src/core/dbus-socket.c
 src/core/dbus-swap.c
 src/core/dbus-target.c
index 19bbb1eb78c773c5085e7ad10c1676218d35e1ca..a5be57940fced611a4b78bf1d6a3e0f3a2014683 100644 (file)
--- a/po/da.po
+++ b/po/da.po
-# Danish translation for systemd.\r
-# Copyright (C) 2014 systemd's COPYRIGHT HOLDER\r
-# This file is distributed under the same license as the systemd package.\r
-# Daniel Machon <dmachon.dev@gmail.com>, 2015.\r
-#\r
-msgid ""\r
-msgstr ""\r
-"Project-Id-Version: systemd master\n"\r
-"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"\r
-"POT-Creation-Date: 2015-10-07 19:30+0000\n"\r
-"PO-Revision-Date: 2015-10-07 19:30+0200\n"\r
-"Last-Translator: Daniel Machon <dmachon.dev@gmail.com>\n"\r
-"Language-Team: danish\n"\r
-"Language: da\n"\r
-"MIME-Version: 1.0\n"\r
-"Content-Type: text/plain; charset=UTF-8\n"\r
-"Content-Transfer-Encoding: 8bit\n"\r
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1\r
-msgid "Send passphrase back to system"\r
-msgstr "Send adgangssætning tilbage til systemet"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2\r
-msgid ""\r
-"Authentication is required to send the entered passphrase back to the system."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sende adgangssætning tilbage til systemet."\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3\r
-msgid "Manage system services or other units"\r
-msgstr "Håndtér system services eller andre enheder"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4\r
-msgid "Authentication is required to manage system services or other units."\r
-msgstr ""\r
-"Autentificering er nødvendig for at håndtere system services og andre enheder."\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5\r
-msgid "Manage system service or unit files"\r
-msgstr "Håndtér system services eller enhedsfiler"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6\r
-msgid "Authentication is required to manage system service or unit files."\r
-msgstr ""\r
-"Autentificering er nødvendig for at håndtere system service eller enhedsfiler."\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7\r
-msgid "Set or unset system and service manager environment variables"\r
-msgstr ""\r
-"Sæt eller fjern system- og service-forvalter miljøvariabler"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8\r
-msgid ""\r
-"Authentication is required to set or unset system and service manager "\r
-"environment variables."\r
-msgstr "Autentificering er nødvendig for at sætte eller fjerne system- "\r
-"og service-forvalter miljøvariabler."\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9\r
-msgid "Reload the systemd state"\r
-msgstr "Genindlæs systemd tilstand"\r
-\r
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10\r
-msgid "Authentication is required to reload the systemd state."\r
-msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden."\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1\r
-msgid "Set host name"\r
-msgstr "Sæt værtsnavn"\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2\r
-msgid "Authentication is required to set the local host name."\r
-msgstr "Autentificering er nødvendig for at sætte værtsnavn."\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3\r
-msgid "Set static host name"\r
-msgstr "Sæt statisk værstnavn"\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4\r
-msgid ""\r
-"Authentication is required to set the statically configured local host name, "\r
-"as well as the pretty host name."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte det statisk konfigurerede lokale "\r
-"værtsnavn, lige så vel som det pæne værtsnavn."\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5\r
-msgid "Set machine information"\r
-msgstr "Sæt maskininformation."\r
-\r
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6\r
-msgid "Authentication is required to set local machine information."\r
-msgstr "Autentificering er nødvendig for at sætte lokal maskininformation."\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:1\r
-msgid "Import a VM or container image"\r
-msgstr "Importér en VM eller container billede"\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:2\r
-msgid "Authentication is required to import a VM or container image"\r
-msgstr ""\r
-"Autentificering er nødvendig for at importére en VM eller "\r
-"container billeder."\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:3\r
-msgid "Export a VM or container image"\r
-msgstr "Exportér en VM eller container billede"\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:4\r
-msgid "Authentication is required to export a VM or container image"\r
-msgstr "Autentificering er nødvendig for at exportére en VM eller container billede"\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:5\r
-msgid "Download a VM or container image"\r
-msgstr "Hent en VM eller container billede"\r
-\r
-#: ../src/import/org.freedesktop.import1.policy.in.h:6\r
-msgid "Authentication is required to download a VM or container image"\r
-msgstr "Autentificering er nødvendig for at hente en VM eller container billede"\r
-\r
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:1\r
-msgid "Set system locale"\r
-msgstr "Sæt sprogindstillinger for systemet"\r
-\r
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:2\r
-msgid "Authentication is required to set the system locale."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte sprogindstillinger "\r
-"for systemet."\r
-\r
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:3\r
-msgid "Set system keyboard settings"\r
-msgstr "Sæt tastaturindstillinger for systemet."\r
-\r
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:4\r
-msgid "Authentication is required to set the system keyboard settings."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte tastaturindstillinger "\r
-"for systemet."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:1\r
-msgid "Allow applications to inhibit system shutdown"\r
-msgstr "Tillad applikationer at hæmme system nedlukning"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:2\r
-msgid ""\r
-"Authentication is required for an application to inhibit system shutdown."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme "\r
-"system nedlukning."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:3\r
-msgid "Allow applications to delay system shutdown"\r
-msgstr "Tillad applikationer at forsinke system nedlukning"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:4\r
-msgid "Authentication is required for an application to delay system shutdown."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan forsinke "\r
-"system nedlukning."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:5\r
-msgid "Allow applications to inhibit system sleep"\r
-msgstr "Tillad applikationer at hæmme system dvale"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:6\r
-msgid "Authentication is required for an application to inhibit system sleep"\r
-msgstr "Autentificering er nødvendig for at en applikation kan hæmme system dvale"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:7\r
-msgid "Allow applications to delay system sleep"\r
-msgstr "Tillad applikationer at forsinke system dvale"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:8\r
-msgid "Authentication is required for an application to delay system sleep."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan forsinke system "\r
-"dvale."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:9\r
-msgid "Allow applications to inhibit automatic system suspend"\r
-msgstr "Tillad applikationer at hæmme automatisk system standby"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:10\r
-msgid ""\r
-"Authentication is required for an application to inhibit automatic system "\r
-"suspend."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme automatisk "\r
-"system standby."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:11\r
-msgid "Allow applications to inhibit system handling of the power key"\r
-msgstr "Tillad applikationer at hæmme systemhåndtering af tænd/sluk-knappen"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:12\r
-msgid ""\r
-"Authentication is required for an application to inhibit system handling of "\r
-"the power key."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "\r
-"af tænd/sluk-knappen."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:13\r
-msgid "Allow applications to inhibit system handling of the suspend key"\r
-msgstr "Tillad applikationer at hæmme systemhåndtering af standby-knappen"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:14\r
-msgid ""\r
-"Authentication is required for an application to inhibit system handling of "\r
-"the suspend key."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "\r
-"af standby-knappen."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:15\r
-msgid "Allow applications to inhibit system handling of the hibernate key"\r
-msgstr "Tillad applikationer at hæmme systemhåndtering af dvale-knappen"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:16\r
-msgid ""\r
-"Authentication is required for an application to inhibit system handling of "\r
-"the hibernate key."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme "\r
-"systemhåndtering af dvale-knappen."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:17\r
-msgid "Allow applications to inhibit system handling of the lid switch"\r
-msgstr ""\r
-"Tillad applikationer at hæmme systemhåndtering af skærmlukning"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:18\r
-msgid ""\r
-"Authentication is required for an application to inhibit system handling of "\r
-"the lid switch."\r
-msgstr ""\r
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "\r
-"af skærmlukning."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:19\r
-msgid "Allow non-logged-in users to run programs"\r
-msgstr "Tillad brugere der ikke er logget ind, at køre programmer"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:20\r
-msgid "Authentication is required to run programs as a non-logged-in user."\r
-msgstr ""\r
-"Autentificering er nødvendig for at brugere, som ikke er logget ind, kan "\r
-"køre programmer."\r
-\r
-# www.freedesktop.org/wiki/Software/systemd/multiseat/\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:21\r
-msgid "Allow attaching devices to seats"\r
-msgstr "Tillad at montere af enheder til arbejdsstationer"\r
-\r
-# www.freedesktop.org/wiki/Software/systemd/multiseat/\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:22\r
-msgid "Authentication is required for attaching a device to a seat."\r
-msgstr ""\r
-"Autentificering er nødvendig for at montere en enhed til en "\r
-"arbejdsstation."\r
-\r
-# www.freedesktop.org/wiki/Software/systemd/multiseat/\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:23\r
-msgid "Flush device to seat attachments"\r
-msgstr "Nulstil enhed monteret til en arbejdsstation"\r
-\r
-# www.freedesktop.org/wiki/Software/systemd/multiseat/\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:24\r
-msgid ""\r
-"Authentication is required for resetting how devices are attached to seats."\r
-msgstr ""\r
-"Autentificering er nødvendig for at nulstille måden enheder er monteret "\r
-"arbejdsstationer."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:25\r
-msgid "Power off the system"\r
-msgstr "Sluk for systemet"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:26\r
-msgid "Authentication is required for powering off the system."\r
-msgstr "Autentificering er nødvendig for at slukke systemet"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:27\r
-msgid "Power off the system while other users are logged in"\r
-msgstr "Sluk systemet mens andre brugere er logget på"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:28\r
-msgid ""\r
-"Authentication is required for powering off the system while other users are "\r
-"logged in."\r
-msgstr ""\r
-"Autentificering er nødvendig for at slukke systemet mens andre brugere "\r
-"er logget på."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:29\r
-msgid "Power off the system while an application asked to inhibit it"\r
-msgstr ""\r
-"Sluk for systemet mens en applikation har forespurgt at hæmme det"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:30\r
-msgid ""\r
-"Authentication is required for powering off the system while an application "\r
-"asked to inhibit it."\r
-msgstr ""\r
-"Autentificering er nødvendig for at slukke systemet mens en applikation har "\r
-"forespurgt at hæmme det."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:31\r
-msgid "Reboot the system"\r
-msgstr "Genstart systemet"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:32\r
-msgid "Authentication is required for rebooting the system."\r
-msgstr "Autentificering er nødvendig for at genstarte systemet."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:33\r
-msgid "Reboot the system while other users are logged in"\r
-msgstr "Genstart systemet mens andre brugere er logget ind"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:34\r
-msgid ""\r
-"Authentication is required for rebooting the system while other users are "\r
-"logged in."\r
-msgstr ""\r
-"Autentificering er nødvendig for at genstarte systemet mens andre brugere "\r
-"er logget ind."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:35\r
-msgid "Reboot the system while an application asked to inhibit it"\r
-msgstr ""\r
-"Genstart systemet mens en applikation har forespurgt at hæmme det"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:36\r
-msgid ""\r
-"Authentication is required for rebooting the system while an application "\r
-"asked to inhibit it."\r
-msgstr ""\r
-"Autentificering er nødvendig for at genstarte systemet mens en applikation "\r
-"har forespurgt at hæmme det."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:37\r
-msgid "Suspend the system"\r
-msgstr "Sæt systemet på standby"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:38\r
-msgid "Authentication is required for suspending the system."\r
-msgstr "Autentificering er nødvendig for at sætte systemet på standby"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:39\r
-msgid "Suspend the system while other users are logged in"\r
-msgstr "Sæt systemet på standby mens andre brugere er logget på"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:40\r
-msgid ""\r
-"Authentication is required for suspending the system while other users are "\r
-"logged in."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte systemet på standby, mens andre "\r
-"brugere er logget på."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:41\r
-msgid "Suspend the system while an application asked to inhibit it"\r
-msgstr ""\r
-"Sæt systemet på standby mens en applikation har forespurgt at hæmme"  \r
-"det"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:42\r
-msgid ""\r
-"Authentication is required for suspending the system while an application "\r
-"asked to inhibit it."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte systemet på standby, mens en "\r
-"applikation har forespurgt at hæmme det."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:43\r
-msgid "Hibernate the system"\r
-msgstr "Sæt systemet i dvale"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:44\r
-msgid "Authentication is required for hibernating the system."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte systemet i dvale-tilstand."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:45\r
-msgid "Hibernate the system while other users are logged in"\r
-msgstr ""\r
-"Sæt systemet i dvale-tilstand mens andre brugere er logget på"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:46\r
-msgid ""\r
-"Authentication is required for hibernating the system while other users are "\r
-"logged in."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte systemet i dvale-tilstand, mens "\r
-"andre brugere er logget på."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:47\r
-msgid "Hibernate the system while an application asked to inhibit it"\r
-msgstr "Sæt systemet i dvale-tilstand mens en applikation har forespurgt at "\r
-"hæmme det"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:48\r
-msgid ""\r
-"Authentication is required for hibernating the system while an application "\r
-"asked to inhibit it."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte systemet i dvale tilstand, mens "\r
-"en applikation har forespurgt at hæmme det."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:49\r
-msgid "Manage active sessions, users and seats"\r
-msgstr "Håndtér aktive sessioner, brugere og arbejdsstationer"\r
-\r
-# www.freedesktop.org/wiki/Software/systemd/multiseat/\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:50\r
-msgid ""\r
-"Authentication is required for managing active sessions, users and seats."\r
-msgstr ""\r
-"Autentificering er nødvendig for at håndtere aktive sessioner, brugere "\r
-"og arbejdsstationer."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:51\r
-msgid "Lock or unlock active sessions"\r
-msgstr "Lås eller oplås aktive sessioner"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:52\r
-msgid "Authentication is required to lock or unlock active sessions."\r
-msgstr ""\r
-"Autentificering er nødvendig for at låse eller oplåse aktive sessioner."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:53\r
-msgid "Allow indication to the firmware to boot to setup interface"\r
-msgstr "Tillad meddelelse til firmwaren om at starte op i opsætningsgrænseflade"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:54\r
-msgid ""\r
-"Authentication is required to indicate to the firmware to boot to setup "\r
-"interface."\r
-msgstr "Autentificering er nødvendig for at meddele firmwaren om at starte "\r
-"op i opsætningsgrænseflade."\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:55\r
-msgid "Set a wall message"\r
-msgstr "Sæt broadcast-besked"\r
-\r
-#: ../src/login/org.freedesktop.login1.policy.in.h:56\r
-msgid "Authentication is required to set a wall message"\r
-msgstr "Autentificering er nødvendig for at sætte en broadcast-besked"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:1\r
-msgid "Log into a local container"\r
-msgstr "Log på en lokal container"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:2\r
-msgid "Authentication is required to log into a local container."\r
-msgstr "Autentificering er nødvendig for at logge på en lokal container."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:3\r
-msgid "Log into the local host"\r
-msgstr "Log på den lokale vært"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:4\r
-msgid "Authentication is required to log into the local host."\r
-msgstr "Auitentificering er nødvendig for at logge på den lokale vært."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:5\r
-msgid "Acquire a shell in a local container"\r
-msgstr "Anskaf en shell i en lokal container"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:6\r
-msgid "Authentication is required to acquire a shell in a local container."\r
-msgstr ""\r
-"Autentificering er nødvendig for at anskaffe en shell i en lokal "\r
-"container."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:7\r
-msgid "Acquire a shell on the local host"\r
-msgstr "Anskaf en shell på den lokale vært"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:8\r
-msgid "Authentication is required to acquire a shell on the local host."\r
-msgstr ""\r
-"Autentificering er nødvendig for at anskaffe en shell på den lokale vært."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:9\r
-msgid "Acquire a pseudo TTY in a local container"\r
-msgstr "Anskaf en pseudo-TTY i en lokal container"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:10\r
-msgid ""\r
-"Authentication is required to acquire a pseudo TTY in a local container."\r
-msgstr ""\r
-"Autentificering er nødvendig for at anskaffe en pseudo-TTY i en lokal "\r
-"container."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:11\r
-msgid "Acquire a pseudo TTY on the local host"\r
-msgstr "Anskaf en pseudo-TTY på den lokale vært"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:12\r
-msgid "Authentication is required to acquire a pseudo TTY on the local host."\r
-msgstr ""\r
-"Autentificering er nødvendig for at anskaffe en pseudo-TTY på den "\r
-"lokale vært."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:13\r
-msgid "Manage local virtual machines and containers"\r
-msgstr "Håndtér lokale virtuelle maskiner og containere"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:14\r
-msgid ""\r
-"Authentication is required to manage local virtual machines and containers."\r
-msgstr ""\r
-"Autentificering er nødvendig for at håndtere lokale virtuelle maskiner og "\r
-"containere."\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:15\r
-msgid "Manage local virtual machine and container images"\r
-msgstr "Håndtér lokal virtuel maskine- og container billeder"\r
-\r
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:16\r
-msgid ""\r
-"Authentication is required to manage local virtual machine and container "\r
-"images."\r
-msgstr ""\r
-"Autentificering er nødvendig for at håndtere lokal virtuel maskine- og "\r
-"container billeder."\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1\r
-msgid "Set system time"\r
-msgstr "Sæt tiden for systemet"\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2\r
-msgid "Authentication is required to set the system time."\r
-msgstr "Autentificering er nødvendig for at sætte tiden for systemet."\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3\r
-msgid "Set system timezone"\r
-msgstr "Sæt tidszone for systemet"\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4\r
-msgid "Authentication is required to set the system timezone."\r
-msgstr "Autentificering er nødvendig for at sætte tidszonen for systemet."\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5\r
-msgid "Set RTC to local timezone or UTC"\r
-msgstr "Sæt RTC til lokal tidszone eller UTC"\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6\r
-msgid ""\r
-"Authentication is required to control whether the RTC stores the local or "\r
-"UTC time."\r
-msgstr ""\r
-"Autentificering er nødvendig for at kontrollere hvorvidt RTC'en gemmer "\r
-"den lokale tid eller UTC tid."\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7\r
-msgid "Turn network time synchronization on or off"\r
-msgstr "Slå synkronisering af netværkstid til eller fra"\r
-\r
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8\r
-msgid ""\r
-"Authentication is required to control whether network time synchronization "\r
-"shall be enabled."\r
-msgstr ""\r
-"Autentificering er nødvendig for at kontrollere hvorvidt synkronisering af "\r
-"netværkstid skal aktiveres"\r
-\r
-#: ../src/core/dbus-unit.c:428\r
-msgid "Authentication is required to start '$(unit)'."\r
-msgstr "Autentificering er nødvendig for at starte '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:429\r
-msgid "Authentication is required to stop '$(unit)'."\r
-msgstr "Autentificering er nødvendig for at stoppe '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:430\r
-msgid "Authentication is required to reload '$(unit)'."\r
-msgstr "Autentificering er nødvendig for at genindlæse '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432\r
-msgid "Authentication is required to restart '$(unit)'."\r
-msgstr "Autentificering at nødvendig for at genstarte '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:535\r
-msgid "Authentication is required to kill '$(unit)'."\r
-msgstr "Autentificering er nødvendig for at eliminere '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:565\r
-msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."\r
-msgstr ""\r
-"Autentificering er nødvendig for at nulstille \"fejl\" tilstanden på '$(unit)'."\r
-\r
-#: ../src/core/dbus-unit.c:597\r
-msgid "Authentication is required to set properties on '$(unit)'."\r
-msgstr ""\r
-"Autentificering er nødvendig for at sætte egenskaber på '$(unit)'."\r
-\r
-#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"\r
-#~ msgstr ""\r
-#~ "Tryk Ctrl-C for at annulere alle igangværende kontrolleringer af "\r
-#~ "filsystemet"\r
-\r
-#~ msgid "Checking in progress on %d disk (%3.1f%% complete)"\r
-#~ msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"\r
-#~ msgstr[0] "Igangværende kontrollering på %d disk (%3.1f%% færdig)"\r
-#~ msgstr[1] "Igangværende kontrollering på %d diske (%3.1f%% færdig)"\r
+# Danish translation for systemd.
+# Copyright (C) 2014 systemd's COPYRIGHT HOLDER
+# This file is distributed under the same license as the systemd package.
+# Daniel Machon <dmachon.dev@gmail.com>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: systemd master\n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
+"POT-Creation-Date: 2015-10-07 19:30+0000\n"
+"PO-Revision-Date: 2015-10-07 19:30+0200\n"
+"Last-Translator: Daniel Machon <dmachon.dev@gmail.com>\n"
+"Language-Team: danish\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Send adgangssætning tilbage til systemet"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr ""
+"Autentificering er nødvendig for at sende adgangssætning tilbage til systemet."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Håndtér system services eller andre enheder"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr ""
+"Autentificering er nødvendig for at håndtere system services og andre enheder."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Håndtér system services eller enhedsfiler"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr ""
+"Autentificering er nødvendig for at håndtere system service eller enhedsfiler."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr ""
+"Sæt eller fjern system- og service-forvalter miljøvariabler"
+
+#: ../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 "Autentificering er nødvendig for at sætte eller fjerne system- "
+"og service-forvalter miljøvariabler."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "Genindlæs systemd tilstand"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+msgid "Set host name"
+msgstr "Sæt værtsnavn"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+msgid "Authentication is required to set the local host name."
+msgstr "Autentificering er nødvendig for at sætte værtsnavn."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+msgid "Set static host name"
+msgstr "Sæt statisk værstnavn"
+
+#: ../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 ""
+"Autentificering er nødvendig for at sætte det statisk konfigurerede lokale "
+"værtsnavn, lige så vel som det pæne værtsnavn."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+msgid "Set machine information"
+msgstr "Sæt maskininformation."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+msgid "Authentication is required to set local machine information."
+msgstr "Autentificering er nødvendig for at sætte lokal maskininformation."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Importér en VM eller container billede"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr ""
+"Autentificering er nødvendig for at importére en VM eller "
+"container billeder."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Exportér en VM eller container billede"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr "Autentificering er nødvendig for at exportére en VM eller container billede"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "Hent en VM eller container billede"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr "Autentificering er nødvendig for at hente en VM eller container billede"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+msgid "Set system locale"
+msgstr "Sæt sprogindstillinger for systemet"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+msgid "Authentication is required to set the system locale."
+msgstr ""
+"Autentificering er nødvendig for at sætte sprogindstillinger "
+"for systemet."
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+msgid "Set system keyboard settings"
+msgstr "Sæt tastaturindstillinger for systemet."
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+msgid "Authentication is required to set the system keyboard settings."
+msgstr ""
+"Autentificering er nødvendig for at sætte tastaturindstillinger "
+"for systemet."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:1
+msgid "Allow applications to inhibit system shutdown"
+msgstr "Tillad applikationer at hæmme system nedlukning"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:2
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
+msgstr ""
+"Autentificering er nødvendig for at en applikation kan hæmme "
+"system nedlukning."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:3
+msgid "Allow applications to delay system shutdown"
+msgstr "Tillad applikationer at forsinke system nedlukning"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:4
+msgid "Authentication is required for an application to delay system shutdown."
+msgstr ""
+"Autentificering er nødvendig for at en applikation kan forsinke "
+"system nedlukning."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:5
+msgid "Allow applications to inhibit system sleep"
+msgstr "Tillad applikationer at hæmme system dvale"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:6
+msgid "Authentication is required for an application to inhibit system sleep"
+msgstr "Autentificering er nødvendig for at en applikation kan hæmme system dvale"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:7
+msgid "Allow applications to delay system sleep"
+msgstr "Tillad applikationer at forsinke system dvale"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:8
+msgid "Authentication is required for an application to delay system sleep."
+msgstr ""
+"Autentificering er nødvendig for at en applikation kan forsinke system "
+"dvale."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:9
+msgid "Allow applications to inhibit automatic system suspend"
+msgstr "Tillad applikationer at hæmme automatisk system standby"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:10
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr ""
+"Autentificering er nødvendig for at en applikation kan hæmme automatisk "
+"system standby."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:11
+msgid "Allow applications to inhibit system handling of the power key"
+msgstr "Tillad applikationer at hæmme systemhåndtering af tænd/sluk-knappen"
+
+#: ../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 ""
+"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
+"af tænd/sluk-knappen."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:13
+msgid "Allow applications to inhibit system handling of the suspend key"
+msgstr "Tillad applikationer at hæmme systemhåndtering af standby-knappen"
+
+#: ../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 ""
+"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
+"af standby-knappen."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:15
+msgid "Allow applications to inhibit system handling of the hibernate key"
+msgstr "Tillad applikationer at hæmme systemhåndtering af dvale-knappen"
+
+#: ../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 ""
+"Autentificering er nødvendig for at en applikation kan hæmme "
+"systemhåndtering af dvale-knappen."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:17
+msgid "Allow applications to inhibit system handling of the lid switch"
+msgstr ""
+"Tillad applikationer at hæmme systemhåndtering af skærmlukning"
+
+#: ../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 ""
+"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
+"af skærmlukning."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in users to run programs"
+msgstr "Tillad brugere der ikke er logget ind, at køre programmer"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Authentication is required to run programs as a non-logged-in user."
+msgstr ""
+"Autentificering er nødvendig for at brugere, som ikke er logget ind, kan "
+"køre programmer."
+
+# www.freedesktop.org/wiki/Software/systemd/multiseat/
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow attaching devices to seats"
+msgstr "Tillad at montere af enheder til arbejdsstationer"
+
+# www.freedesktop.org/wiki/Software/systemd/multiseat/
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
+msgid "Authentication is required for attaching a device to a seat."
+msgstr ""
+"Autentificering er nødvendig for at montere en enhed til en "
+"arbejdsstation."
+
+# www.freedesktop.org/wiki/Software/systemd/multiseat/
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
+msgid "Flush device to seat attachments"
+msgstr "Nulstil enhed monteret til en arbejdsstation"
+
+# www.freedesktop.org/wiki/Software/systemd/multiseat/
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr ""
+"Autentificering er nødvendig for at nulstille måden enheder er monteret "
+"arbejdsstationer."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
+msgid "Power off the system"
+msgstr "Sluk for systemet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
+msgid "Authentication is required for powering off the system."
+msgstr "Autentificering er nødvendig for at slukke systemet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
+msgid "Power off the system while other users are logged in"
+msgstr "Sluk systemet mens andre brugere er logget på"
+
+#: ../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 ""
+"Autentificering er nødvendig for at slukke systemet mens andre brugere "
+"er logget på."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
+msgid "Power off the system while an application asked to inhibit it"
+msgstr ""
+"Sluk for systemet mens en applikation har forespurgt at hæmme det"
+
+#: ../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 ""
+"Autentificering er nødvendig for at slukke systemet mens en applikation har "
+"forespurgt at hæmme det."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
+msgid "Reboot the system"
+msgstr "Genstart systemet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
+msgid "Authentication is required for rebooting the system."
+msgstr "Autentificering er nødvendig for at genstarte systemet."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
+msgid "Reboot the system while other users are logged in"
+msgstr "Genstart systemet mens andre brugere er logget ind"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr ""
+"Autentificering er nødvendig for at genstarte systemet mens andre brugere "
+"er logget ind."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
+msgid "Reboot the system while an application asked to inhibit it"
+msgstr ""
+"Genstart systemet mens en applikation har forespurgt at hæmme det"
+
+#: ../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 ""
+"Autentificering er nødvendig for at genstarte systemet mens en applikation "
+"har forespurgt at hæmme det."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
+msgid "Suspend the system"
+msgstr "Sæt systemet på standby"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
+msgid "Authentication is required for suspending the system."
+msgstr "Autentificering er nødvendig for at sætte systemet på standby"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
+msgid "Suspend the system while other users are logged in"
+msgstr "Sæt systemet på standby mens andre brugere er logget på"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr ""
+"Autentificering er nødvendig for at sætte systemet på standby, mens andre "
+"brugere er logget på."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
+msgid "Suspend the system while an application asked to inhibit it"
+msgstr ""
+"Sæt systemet på standby mens en applikation har forespurgt at hæmme"
+"det"
+
+#: ../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 ""
+"Autentificering er nødvendig for at sætte systemet på standby, mens en "
+"applikation har forespurgt at hæmme det."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
+msgid "Hibernate the system"
+msgstr "Sæt systemet i dvale"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
+msgid "Authentication is required for hibernating the system."
+msgstr ""
+"Autentificering er nødvendig for at sætte systemet i dvale-tilstand."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
+msgid "Hibernate the system while other users are logged in"
+msgstr ""
+"Sæt systemet i dvale-tilstand mens andre brugere er logget på"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr ""
+"Autentificering er nødvendig for at sætte systemet i dvale-tilstand, mens "
+"andre brugere er logget på."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
+msgid "Hibernate the system while an application asked to inhibit it"
+msgstr "Sæt systemet i dvale-tilstand mens en applikation har forespurgt at "
+"hæmme det"
+
+#: ../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 ""
+"Autentificering er nødvendig for at sætte systemet i dvale tilstand, mens "
+"en applikation har forespurgt at hæmme det."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Håndtér aktive sessioner, brugere og arbejdsstationer"
+
+# www.freedesktop.org/wiki/Software/systemd/multiseat/
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Autentificering er nødvendig for at håndtere aktive sessioner, brugere "
+"og arbejdsstationer."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Lås eller oplås aktive sessioner"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr ""
+"Autentificering er nødvendig for at låse eller oplåse aktive sessioner."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr "Tillad meddelelse til firmwaren om at starte op i opsætningsgrænseflade"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr "Autentificering er nødvendig for at meddele firmwaren om at starte "
+"op i opsætningsgrænseflade."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
+msgid "Set a wall message"
+msgstr "Sæt broadcast-besked"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
+msgid "Authentication is required to set a wall message"
+msgstr "Autentificering er nødvendig for at sætte en broadcast-besked"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+msgid "Log into a local container"
+msgstr "Log på en lokal container"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+msgid "Authentication is required to log into a local container."
+msgstr "Autentificering er nødvendig for at logge på en lokal container."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Log into the local host"
+msgstr "Log på den lokale vært"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid "Authentication is required to log into the local host."
+msgstr "Auitentificering er nødvendig for at logge på den lokale vært."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Acquire a shell in a local container"
+msgstr "Anskaf en shell i en lokal container"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to acquire a shell in a local container."
+msgstr ""
+"Autentificering er nødvendig for at anskaffe en shell i en lokal "
+"container."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+msgid "Acquire a shell on the local host"
+msgstr "Anskaf en shell på den lokale vært"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+msgid "Authentication is required to acquire a shell on the local host."
+msgstr ""
+"Autentificering er nødvendig for at anskaffe en shell på den lokale vært."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+msgid "Acquire a pseudo TTY in a local container"
+msgstr "Anskaf en pseudo-TTY i en lokal container"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
+msgstr ""
+"Autentificering er nødvendig for at anskaffe en pseudo-TTY i en lokal "
+"container."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+msgid "Acquire a pseudo TTY on the local host"
+msgstr "Anskaf en pseudo-TTY på den lokale vært"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+msgid "Authentication is required to acquire a pseudo TTY on the local host."
+msgstr ""
+"Autentificering er nødvendig for at anskaffe en pseudo-TTY på den "
+"lokale vært."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+msgid "Manage local virtual machines and containers"
+msgstr "Håndtér lokale virtuelle maskiner og containere"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Autentificering er nødvendig for at håndtere lokale virtuelle maskiner og "
+"containere."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
+msgid "Manage local virtual machine and container images"
+msgstr "Håndtér lokal virtuel maskine- og container billeder"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Autentificering er nødvendig for at håndtere lokal virtuel maskine- og "
+"container billeder."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+msgid "Set system time"
+msgstr "Sæt tiden for systemet"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+msgid "Authentication is required to set the system time."
+msgstr "Autentificering er nødvendig for at sætte tiden for systemet."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+msgid "Set system timezone"
+msgstr "Sæt tidszone for systemet"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+msgid "Authentication is required to set the system timezone."
+msgstr "Autentificering er nødvendig for at sætte tidszonen for systemet."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+msgid "Set RTC to local timezone or UTC"
+msgstr "Sæt RTC til lokal tidszone eller 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 ""
+"Autentificering er nødvendig for at kontrollere hvorvidt RTC'en gemmer "
+"den lokale tid eller UTC tid."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+msgid "Turn network time synchronization on or off"
+msgstr "Slå synkronisering af netværkstid til eller fra"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+msgid ""
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
+msgstr ""
+"Autentificering er nødvendig for at kontrollere hvorvidt synkronisering af "
+"netværkstid skal aktiveres"
+
+#: ../src/core/dbus-unit.c:428
+msgid "Authentication is required to start '$(unit)'."
+msgstr "Autentificering er nødvendig for at starte '$(unit)'."
+
+#: ../src/core/dbus-unit.c:429
+msgid "Authentication is required to stop '$(unit)'."
+msgstr "Autentificering er nødvendig for at stoppe '$(unit)'."
+
+#: ../src/core/dbus-unit.c:430
+msgid "Authentication is required to reload '$(unit)'."
+msgstr "Autentificering er nødvendig for at genindlæse '$(unit)'."
+
+#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+msgid "Authentication is required to restart '$(unit)'."
+msgstr "Autentificering at nødvendig for at genstarte '$(unit)'."
+
+#: ../src/core/dbus-unit.c:535
+msgid "Authentication is required to kill '$(unit)'."
+msgstr "Autentificering er nødvendig for at eliminere '$(unit)'."
+
+#: ../src/core/dbus-unit.c:565
+msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
+msgstr ""
+"Autentificering er nødvendig for at nulstille \"fejl\" tilstanden på '$(unit)'."
+
+#: ../src/core/dbus-unit.c:597
+msgid "Authentication is required to set properties on '$(unit)'."
+msgstr ""
+"Autentificering er nødvendig for at sætte egenskaber på '$(unit)'."
+
+#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
+#~ msgstr ""
+#~ "Tryk Ctrl-C for at annulere alle igangværende kontrolleringer af "
+#~ "filsystemet"
+
+#~ msgid "Checking in progress on %d disk (%3.1f%% complete)"
+#~ msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
+#~ msgstr[0] "Igangværende kontrollering på %d disk (%3.1f%% færdig)"
+#~ msgstr[1] "Igangværende kontrollering på %d diske (%3.1f%% færdig)"
index 382c011cd01cf56d79e132e5b61c536f90653b36..e78ad2ef870c72acb905175609779bef32146da2 100644 (file)
--- a/po/ko.po
+++ b/po/ko.po
@@ -2,19 +2,20 @@
 # Copyright (C) 2015 systemd author and translators.
 # This file is distributed under the same license as the systemd package.
 # Seong-ho Cho <shcho@gnome.org>, 2015.
+# Dongsu Park <dongsu@endocode.com>, 2015.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
 "POT-Creation-Date: 2015-09-25 22:52+0900\n"
-"PO-Revision-Date: 2015-09-25 23:50+0900\n"
-"Last-Translator: Seong-ho Cho <shcho@gnome.org>\n"
+"PO-Revision-Date: 2015-11-03 13:19+0100\n"
+"Last-Translator: Dongsu Park <dongsu@endocode.com>\n"
 "Language-Team: GNOME Korea <gnome-kr@googlegroups.com>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.5.5\n"
+"X-Generator: Gtranslator 2.91.7\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Language: ko\n"
 "X-Poedit-SourceCharset: UTF-8\n"
@@ -242,7 +243,7 @@ msgstr "시트에 장치 부착을 허용하려면 인증이 필요합니다."
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:23
 msgid "Flush device to seat attachments"
-msgstr "ì\8b\9cí\8a¸ë¡\9cë¶\80í\84° ì\9e¥ì¹\98 í\83\88ê±° 허용"
+msgstr "ì\8b\9cí\8a¸ë¡\9cë¶\80í\84° ì\9e¥ì¹\98 í\95´ì \9c 허용"
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:24
 msgid ""
@@ -393,13 +394,13 @@ msgstr "활성화 세션을 잠금 또는 잠금 해제하려면 인증이 필
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:53
 msgid "Allow indication to the firmware to boot to setup interface"
-msgstr "ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤ë¥¼ ì\84¤ì \95í\95\98ë\8f\84ë¡\9d í\8e\8cì\9b¨ì\96´ ë¶\80í\8c\85 지시 허용"
+msgstr "ì\84¤ì \95 í\99\94ë©´ì\9c¼ë¡\9c ë¶\80í\8c\85í\95\98ë\8f\84ë¡\9d í\8e\8cì\9b¨ì\96´ì\97\90ê²\8c 지시 허용"
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:54
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
-msgstr "ì\9d¸í\84°í\8e\98ì\9d´ì\8a¤ë¥¼ ì\84¤ì \95í\95\98ë\8f\84ë¡\9d í\8e\8cì\9b¨ì\96´ ë¶\80í\8c\85ì\9d\84 지시하려면 인증이 필요합니다."
+msgstr "ì\84¤ì \95 í\99\94ë©´ì\9c¼ë¡\9c ë¶\80í\8c\85í\95\98ë\8f\84ë¡\9d í\8e\8cì\9b¨ì\96´ì\97\90ê²\8c 지시하려면 인증이 필요합니다."
 
 #: ../src/login/org.freedesktop.login1.policy.in.h:55
 msgid "Set a wall message"
@@ -452,7 +453,7 @@ msgstr "로컬 컨테이너에서 의사 TTY를 획득하려면 인증이 필요
 
 #: ../src/machine/org.freedesktop.machine1.policy.in.h:11
 msgid "Acquire a pseudo TTY on the local host"
-msgstr "ë¡\9c컬 í\98¸ì\8a¤í\8a¸ì\97\90ì\84\9c ì\9d\98사 TTY 획득"
+msgstr "ë¡\9c컬 í\98¸ì\8a¤í\8a¸ì\97\90ì\84\9c ì\9c 사 TTY 획득"
 
 #: ../src/machine/org.freedesktop.machine1.policy.in.h:12
 msgid "Authentication is required to acquire a pseudo TTY on the local host."
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644 (file)
index 0000000..6763962
--- /dev/null
@@ -0,0 +1,527 @@
+# Simplified Chinese translation for systemd.
+# Copyright (C) 2015 systemd's COPYRIGHT HOLDER
+# This file is distributed under the same license as the systemd package.
+#
+# Frank Hill <hxf.prc@gmail.com>, 2014.
+# Boyuan Yang <073plan@gmail.com>, 2015.
+msgid ""
+msgstr ""
+"Project-Id-Version: systemd\n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
+"POT-Creation-Date: 2015-10-27 02:24+0000\n"
+"PO-Revision-Date: 2015-10-28 15:00+0800\n"
+"Last-Translator: Boyuan Yang <073plan@gmail.com>\n"
+"Language-Team: Chinese <i18n-zh@googlegroups.com>\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 2.0\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "将密码发回系统"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr "将输入的密码发回系统需要验证。"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "管理系统服务或其它单元"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr "管理系统服务或其它单元需要验证。"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "管理系统服务或单元文件"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr "管理系统服务或单元文件需要验证。"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "设置或清除系统及服务管理器的环境变量"
+
+#: ../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 "设置或清除系统及服务管理器的环境变量需要验证。"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "重新载入 systemd 状态"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "重新载入 systemd 状态需要验证。"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+msgid "Set host name"
+msgstr "设置主机名"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+msgid "Authentication is required to set the local host name."
+msgstr "设置本地主机名需要验证。"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+msgid "Set static host name"
+msgstr "设置静态主机名"
+
+# For pretty hostname, the zh_CN/zh_TW translation should be discussed again.
+#
+# There were some discussions, like https://lists.fedoraprojects.org/pipermail/trans-zh_cn/2012-December/001347.html
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
+#, fuzzy
+msgid ""
+"Authentication is required to set the statically configured local host name, "
+"as well as the pretty host name."
+msgstr "设置静态本地主机名或漂亮的主机名需要验证。"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+msgid "Set machine information"
+msgstr "设置机器信息"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+msgid "Authentication is required to set local machine information."
+msgstr "设置本地机器信息需要验证。"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "导入虚拟机或容器镜像"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr "导入虚拟机或容器镜像需要验证"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "导出虚拟机或容器镜像"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr "导出虚拟机或容器镜像需要验证"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "下载虚拟机或容器镜像"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr "下载虚拟机或容器镜像需要验证。"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+msgid "Set system locale"
+msgstr "设置系统区域和语言"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+msgid "Authentication is required to set the system locale."
+msgstr "设置系统区域和语言需要验证。"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+msgid "Set system keyboard settings"
+msgstr "设置系统键盘"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+msgid "Authentication is required to set the system keyboard settings."
+msgstr "设置系统键盘需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:1
+msgid "Allow applications to inhibit system shutdown"
+msgstr "允许应用程序阻止系统关机"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:2
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
+msgstr "要允许应用程序阻止系统关机需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:3
+msgid "Allow applications to delay system shutdown"
+msgstr "允许应用程序延迟系统关机"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:4
+msgid "Authentication is required for an application to delay system shutdown."
+msgstr "要允许应用程序延迟系统关机需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:5
+msgid "Allow applications to inhibit system sleep"
+msgstr "允许应用程序阻止系统睡眠"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:6
+msgid "Authentication is required for an application to inhibit system sleep."
+msgstr "要允许应用程序阻止系统睡眠需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:7
+msgid "Allow applications to delay system sleep"
+msgstr "允许应用程序延迟系统睡眠"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:8
+msgid "Authentication is required for an application to delay system sleep."
+msgstr "要允许应用程序延迟系统睡眠需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:9
+msgid "Allow applications to inhibit automatic system suspend"
+msgstr "允许应用程序阻止系统自动挂起"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:10
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr "要允许应用程序阻止系统自动挂起需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:11
+msgid "Allow applications to inhibit system handling of the power key"
+msgstr "允许应用程序阻止系统响应电源键"
+
+#: ../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 "要允许应用程序阻止系统响应电源键需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:13
+msgid "Allow applications to inhibit system handling of the suspend key"
+msgstr "允许应用程序阻止系统响应挂起键"
+
+#: ../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 "要允许应用程序阻止系统响应挂起键需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:15
+msgid "Allow applications to inhibit system handling of the hibernate key"
+msgstr "允许应用程序阻止系统响应挂起键"
+
+#: ../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 "要允许应用程序阻止系统响应挂起键需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:17
+#, fuzzy
+msgid "Allow applications to inhibit system handling of the lid switch"
+msgstr "允许应用程序阻止系统响应笔记本上盖开关事件"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:18
+#, fuzzy
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the lid switch."
+msgstr "要允许应用程序阻止系统响应笔记本上盖开关事件需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in users to run programs"
+msgstr "允许未登录用户运行程序"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Authentication is required to run programs as a non-logged-in user."
+msgstr "要允许未登录用户运行程序需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow attaching devices to seats"
+msgstr "允许将设备附加至会话座位"
+
+# Pay attention to the concept of "seat".
+#
+# To fully understand the meaning, please refer to session management in old ConsoleKit and new systemd-logind.
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
+msgid "Authentication is required for attaching a device to a seat."
+msgstr "要允许将设备附加至某个会话座位需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
+msgid "Flush device to seat attachments"
+msgstr "刷新设备至会话座位间的连接"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr "重新设定设备的会话座位接入方式时需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
+msgid "Power off the system"
+msgstr "关闭系统"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
+msgid "Authentication is required for powering off the system."
+msgstr "关闭系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
+msgid "Power off the system while other users are logged in"
+msgstr "存在其他已登录用户时仍然关机"
+
+#: ../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 "存在其他已登录用户时关闭系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
+msgid "Power off the system while an application asked to inhibit it"
+msgstr "有其它应用程序阻止时仍然关机"
+
+#: ../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 "要在其它应用程序阻止关机时关闭系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
+msgid "Reboot the system"
+msgstr "重启系统"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
+msgid "Authentication is required for rebooting the system."
+msgstr "重启系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
+msgid "Reboot the system while other users are logged in"
+msgstr "存在其他已登录用户时仍然重启"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr "存在其他已登录用户时重启系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
+msgid "Reboot the system while an application asked to inhibit it"
+msgstr "有其它应用程序阻止时仍然重启"
+
+#: ../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 "要在其它应用程序阻止重启时重启系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
+msgid "Suspend the system"
+msgstr "挂起系统"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
+msgid "Authentication is required for suspending the system."
+msgstr "挂起系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
+msgid "Suspend the system while other users are logged in"
+msgstr "存在其他已登录用户时仍然挂起系统"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr "存在其他已登录用户时挂起系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
+msgid "Suspend the system while an application asked to inhibit it"
+msgstr "有其它应用程序阻止时仍然挂起系统"
+
+#: ../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 "要在其它应用程序阻止挂起时挂起系统需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
+msgid "Hibernate the system"
+msgstr "休眠"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
+msgid "Authentication is required for hibernating the system."
+msgstr "休眠需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
+msgid "Hibernate the system while other users are logged in"
+msgstr "存在其他已登录用户时仍然休眠"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr "存在其他已登录用户时进行休眠需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
+msgid "Hibernate the system while an application asked to inhibit it"
+msgstr "有其它应用程序阻止时仍然休眠"
+
+#: ../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 "要在其它应用程序阻止休眠时进行休眠需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "管理活动会话、用户与会话座位"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr "要管理活动会话、用户与会话座位需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "活动会话锁定与解锁"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr "要对活动会话进行锁定或解锁需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr "允许向固件发出指示以启动至固件设置界面"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr "要允许向固件发出启动时进入设置界面的指令需要验证。"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
+msgid "Set a wall message"
+msgstr ""
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
+#, fuzzy
+msgid "Authentication is required to set a wall message"
+msgstr ""
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+msgid "Log into a local container"
+msgstr "登入一个本地容器"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+msgid "Authentication is required to log into a local container."
+msgstr "要登入一个本地容器需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Log into the local host"
+msgstr "登入本地主机"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid "Authentication is required to log into the local host."
+msgstr "要登入本地主机需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Acquire a shell in a local container"
+msgstr "在本地容器中获取一个 shell"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to acquire a shell in a local container."
+msgstr "要在本地容器中获取 shell 需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+msgid "Acquire a shell on the local host"
+msgstr "在本地主机中获取一个 shell"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+msgid "Authentication is required to acquire a shell on the local host."
+msgstr "要在本地主机中获取 shell 需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+msgid "Acquire a pseudo TTY in a local container"
+msgstr "在本地容器中获取一个假 TTY"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
+msgstr "要在本地容器中获取假 TTY 需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+msgid "Acquire a pseudo TTY on the local host"
+msgstr "在本地主机中获取一个假 TTY"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+msgid "Authentication is required to acquire a pseudo TTY on the local host."
+msgstr "要在本地主机中获取假 TTY 需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+msgid "Manage local virtual machines and containers"
+msgstr "管理本地虚拟机和容器"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr "要管理本地虚拟机和容器需要验证。"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
+msgid "Manage local virtual machine and container images"
+msgstr "管理本地虚拟机和容器的镜像"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr "要管理本地的虚拟机和容器镜像需要验证。"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+msgid "Set system time"
+msgstr "设置系统时间"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+msgid "Authentication is required to set the system time."
+msgstr "设置系统时间需要验证。"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+msgid "Set system timezone"
+msgstr "设置系统时区"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+msgid "Authentication is required to set the system timezone."
+msgstr "设置系统时区需要验证。"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+msgid "Set RTC to local timezone or UTC"
+msgstr "设置硬件时钟使用本地时间或 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 "设置硬件时钟使用本地时间或 UTC 需要验证。"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+msgid "Turn network time synchronization on or off"
+msgstr "打开或关闭网络时间同步"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+msgid ""
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
+msgstr "设置是否启用网络时间同步需要验证。"
+
+#: ../src/core/dbus-unit.c:430
+msgid "Authentication is required to start '$(unit)'."
+msgstr "启动“$(unit)”需要验证。"
+
+#: ../src/core/dbus-unit.c:431
+msgid "Authentication is required to stop '$(unit)'."
+msgstr "停止“$(unit)”需要验证。"
+
+#: ../src/core/dbus-unit.c:432
+msgid "Authentication is required to reload '$(unit)'."
+msgstr "重新载入“$(unit)”需要验证。"
+
+#: ../src/core/dbus-unit.c:433 ../src/core/dbus-unit.c:434
+msgid "Authentication is required to restart '$(unit)'."
+msgstr "重新启动“$(unit)”需要验证。"
+
+#: ../src/core/dbus-unit.c:537
+msgid "Authentication is required to kill '$(unit)'."
+msgstr "杀死“$(unit)”需要验证。"
+
+#: ../src/core/dbus-unit.c:567
+msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
+msgstr "重置“$(unit)”的失败(\"failed\")状态需要验证。"
+
+#: ../src/core/dbus-unit.c:599
+msgid "Authentication is required to set properties on '$(unit)'."
+msgstr "设置“$(unit)”的属性需要验证。"
+
index 9ad52e03b481c56f6cbbe8d230093347b0ca08f4..6a252188ea09b8aa8b20650489d26e794fe3ffaa 100644 (file)
@@ -38,7 +38,7 @@ _hostnamectl() {
         local -A VERBS=(
                 [STANDALONE]='status'
                      [ICONS]='set-icon-name'
-                      [NAME]='set-hostname set-deployment'
+                      [NAME]='set-hostname set-deployment set-location'
                    [CHASSIS]='set-chassis'
         )
 
index 056cdbce703546c76cf207222b7b80b9d927b49f..4a7e0da1abf54e7d3b5eb64d29d986bed0e8750a 100644 (file)
@@ -51,7 +51,7 @@ _journalctl() {
                        [ARG]='-b --boot --this-boot -D --directory --file -F --field
                               -o --output -u --unit --user-unit -p --priority
                               --vacuum-size --vacuum-time'
-                [ARGUNKNOWN]='-c --cursor --interval -n --lines --since --until
+                [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until
                               --after-cursor --verify-key -t --identifier
                               --root -M --machine'
         )
index 29bb41c436da28093c46b39c79a33a28d79fe761..d80d8f02a810479bf736c39646690270eefd3038 100644 (file)
@@ -106,6 +106,8 @@ _systemctl () {
 
         if __contains_word "--user" ${COMP_WORDS[*]}; then
             mode=--user
+        elif __contains_word "--global" ${COMP_WORDS[*]}; then
+            mode=--user
         else
             mode=--system
         fi
@@ -159,7 +161,7 @@ _systemctl () {
         fi
 
         local -A VERBS=(
-                [ALL_UNITS]='is-active is-failed is-enabled status show cat mask preset help list-dependencies edit'
+                [ALL_UNITS]='is-active is-failed is-enabled status show cat mask preset help list-dependencies edit set-property'
             [ENABLED_UNITS]='disable'
            [DISABLED_UNITS]='enable'
         [REENABLABLE_UNITS]='reenable'
@@ -172,14 +174,12 @@ _systemctl () {
          [TARGET_AND_UNITS]='add-wants add-requires'
              [MASKED_UNITS]='unmask'
                      [JOBS]='cancel'
-                [SNAPSHOTS]='delete'
                      [ENVS]='set-environment unset-environment'
                [STANDALONE]='daemon-reexec daemon-reload default
                              emergency exit halt hibernate hybrid-sleep kexec list-jobs
                              list-sockets list-timers list-units list-unit-files poweroff
                              reboot rescue show-environment suspend get-default
                              is-system-running'
-                     [NAME]='snapshot'
                      [FILE]='link switch-root'
                   [TARGETS]='set-default'
         )
@@ -257,16 +257,12 @@ _systemctl () {
                 fi
                 compopt -o filenames
 
-        elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then
+        elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
                 comps=''
 
         elif __contains_word "$verb" ${VERBS[JOBS]}; then
                 comps=$( __systemctl $mode list-jobs | { while read -r a b; do echo " $a"; done; } )
 
-        elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then
-                comps=$( __systemctl $mode list-units --type snapshot --full --all \
-                        | { while read -r a b; do echo " $a"; done; } )
-
         elif __contains_word "$verb" ${VERBS[ENVS]}; then
                 comps=$( __systemctl $mode show-environment \
                     | while read -r line; do echo " ${line%%=*}=";done )
index b1387a28b634a9eddde25d9ac593e4c5350b0cbb..8152b021e779d8c0f1f882ed0f3d7cf5af9242ca 100644 (file)
@@ -83,7 +83,10 @@ _systemd_run() {
                          LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE=
                          LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=
                          PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory=
-                         TTYPath= SyslogIdentifier= SyslogLevelPrefix='
+                         TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel=
+                         SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories=
+                         ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile=
+                         ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment='
 
             COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
             return 0
index 863348e05015cda24e693c0718a84a8c834eb965..b50f0cafc98f66f943a97f76e34efc2bff6d5455 100644 (file)
@@ -69,6 +69,7 @@ _arguments -s \
     {-u+,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \
     '--user-unit=[Show data only from the specified user session unit]:units:_journal_fields USER_UNIT' \
     {-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journal_fields PRIORITY' \
+    {-t+,--identifier=}'[Show only messages with the specified syslog identifier]:identifier:_journal_fields SYSLOG_IDENTIFIER' \
     {-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journal_fields __CURSORS' \
     '--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journal_fields __CURSORS' \
     '--since=[Start showing entries on or newer than the specified date]:YYYY-MM-DD HH\:MM\:SS' \
index 4778a0420d0d270823b65fa3ee2a6db452ace9a1..3e7a4ee803db5ccddedcaea7d67e95f01d84f837 100644 (file)
@@ -5,5 +5,5 @@ _sd_unit_files() {
     files=( '*:files:->files' )
 
     _description files expl 'unit file'
-    _files "$expl[@]" -g '*.(automount|busname|device|mount|path|service|snapshot|socket|swap|target|timer)'
+    _files "$expl[@]" -g '*.(automount|busname|device|mount|path|service|socket|swap|target|timer)'
 }
index 96f51a0ee0c0e5316e5846d2e83bfa818444b755..58c88c9d982dd28c3c31c6f13b86d181b7edba94 100644 (file)
@@ -43,8 +43,6 @@
     "is-enabled:Check whether unit files are enabled"
     "list-jobs:List jobs"
     "cancel:Cancel all, one, or more jobs"
-    "snapshot:Create a snapshot"
-    "delete:Remove one or more snapshots"
     "show-environment:Dump environment"
     "set-environment:Set one or more environment variables"
     "unset-environment:Unset one or more environment variables"
@@ -268,14 +266,6 @@ done
       _message "no jobs found"
 }
 
-# Completion functions for SNAPSHOTS
-(( $+functions[_systemctl_delete] )) || _systemctl_delete()
-{
-  _wanted systemd-snapshots expl snapshot \
-    compadd "$@" - ${${(f)"$(__systemctl list-units --type snapshot --all)"}%% *} ||
-      _message "no snapshots found"
-}
-
 # Completion functions for TARGETS
 (( $+functions[_systemctl_set-default] )) || _systemctl_set-default()
 {
@@ -310,7 +300,6 @@ done
 #    [STANDALONE]='daemon-reexec daemon-reload default
 #                  emergency exit halt kexec list-jobs list-units
 #                  list-unit-files poweroff reboot rescue show-environment'
-#         [NAME]='snapshot'
 
 _systemctl_caching_policy()
 {
index 8d6957fa9bf7258bd18cdf6d96fcdabb609c45f5..c425085cd801c855981875cd935cb4c3bb1e9f40 100644 (file)
@@ -26,7 +26,21 @@ _arguments \
         {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \
         '--scope[Run this as scope rather than service]' \
         '--unit=[Run under the specified unit name]:unit name' \
-        {-p+,--property=}'[Set unit property]:NAME=VALUE' \
+        {-p+,--property=}'[Set unit property]:NAME=VALUE:(( \
+                CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP= \
+                SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \
+                DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \
+                BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \
+                KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= \
+                LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \
+                LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \
+                LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \
+                PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \
+                TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= \
+                SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= \
+                ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= \
+                ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \
+                ))' \
         '--description=[Description for unit]:description' \
         '--slice=[Run in the specified slice]:slices:__slices' \
         {-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \
index 4ece1367c11e9651da10e5b429b726028bf79f4a..b7e6255f4905f6c0190a60cf753680712e4d2b1b 100644 (file)
 
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "log.h"
 #include "macro.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "string-util.h"
 #include "strv.h"
 
 static char** arg_listen = NULL;
index f4255f979efd24e75b1630f59fe589e3027380bb..deb102c22c35e373fe7f9bba2f9633bc1f370742 100644 (file)
 
 #include <stdlib.h>
 
-#include "manager.h"
+#include "alloc-util.h"
+#include "analyze-verify.h"
+#include "bus-error.h"
 #include "bus-util.h"
 #include "log.h"
-#include "strv.h"
+#include "manager.h"
 #include "pager.h"
-#include "analyze-verify.h"
+#include "path-util.h"
+#include "strv.h"
 
 static int generate_path(char **var, char **filenames) {
         char **filename;
@@ -162,7 +165,6 @@ static int verify_documentation(Unit *u, bool check_man) {
 
 static int verify_unit(Unit *u, bool check_man) {
         _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL;
-        Job *j;
         int r, k;
 
         assert(u);
@@ -171,11 +173,9 @@ static int verify_unit(Unit *u, bool check_man) {
                 unit_dump(u, stdout, "\t");
 
         log_unit_debug(u, "Creating %s/start job", u->id);
-        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j);
-        if (sd_bus_error_is_set(&err))
-                log_unit_error(u, "Error: %s: %s", err.name, err.message);
+        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
         if (r < 0)
-                log_unit_error_errno(u, r, "Failed to create %s/start: %m", u->id);
+                log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
 
         k = verify_socket(u);
         if (k < 0 && r == 0)
index 4bf83eb3293546e27a2926b41fd74439643928ea..e922d6fb32d30bdcf9c4300d87c3328937243c42 100644 (file)
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "analyze-verify.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "glob-util.h"
 #include "hashmap.h"
+#include "locale-util.h"
 #include "log.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "special.h"
 #include "strv.h"
 #include "strxcpyx.h"
@@ -1062,20 +1066,17 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro
         assert(bus);
         assert(u);
 
-        if (arg_dot == DEP_ORDER ||arg_dot == DEP_ALL) {
+        if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) {
                 r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns);
                 if (r < 0)
                         return r;
         }
 
-        if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) {
+        if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) {
                 r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns);
                 if (r < 0)
                         return r;
-                r = graph_one_property(bus, u, "RequiresOverridable", "black", patterns, from_patterns, to_patterns);
-                if (r < 0)
-                        return r;
-                r = graph_one_property(bus, u, "RequisiteOverridable", "darkblue", patterns, from_patterns, to_patterns);
+                r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns);
                 if (r < 0)
                         return r;
                 r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns);
@@ -1084,9 +1085,6 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro
                 r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns);
                 if (r < 0)
                         return r;
-                r = graph_one_property(bus, u, "ConflictedBy", "red", patterns, from_patterns, to_patterns);
-                if (r < 0)
-                        return r;
         }
 
         return 0;
index 1a69d15908534b516907dc070ad82478bbf854e3..a5448660003e23c3d2c83473ef5b94946ab6a534 100644 (file)
@@ -144,7 +144,7 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 int main(int argc, char *argv[]) {
-        _cleanup_strv_free_ char **l = NULL;
+        _cleanup_strv_free_erase_ char **l = NULL;
         usec_t timeout;
         char **p;
         int r;
index c8961de946857c498eb3d6098bc9bb31e0a2a561..b0fa079fec2b560b0979d43704a1c4e8de1ce39b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "mkdir.h"
-#include "fileio.h"
 #include "libudev.h"
-#include "udev-util.h"
+
+#include "alloc-util.h"
 #include "def.h"
+#include "escape.h"
+#include "fileio.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
+#include "udev-util.h"
+#include "util.h"
 
 static struct udev_device *find_pci_or_platform_parent(struct udev_device *device) {
         struct udev_device *parent;
@@ -375,7 +381,7 @@ int main(int argc, char *argv[]) {
                 _cleanup_free_ char *value = NULL;
                 const char *clamp;
 
-                if (!shall_restore_state())
+                if (shall_restore_state() == 0)
                         return EXIT_SUCCESS;
 
                 if (!validate_device(udev, device))
diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c
new file mode 100644 (file)
index 0000000..48183e3
--- /dev/null
@@ -0,0 +1,81 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "util.h"
+
+void* memdup(const void *p, size_t l) {
+        void *r;
+
+        assert(p);
+
+        r = malloc(l);
+        if (!r)
+                return NULL;
+
+        memcpy(r, p, l);
+        return r;
+}
+
+void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
+        size_t a, newalloc;
+        void *q;
+
+        assert(p);
+        assert(allocated);
+
+        if (*allocated >= need)
+                return *p;
+
+        newalloc = MAX(need * 2, 64u / size);
+        a = newalloc * size;
+
+        /* check for overflows */
+        if (a < size * need)
+                return NULL;
+
+        q = realloc(*p, a);
+        if (!q)
+                return NULL;
+
+        *p = q;
+        *allocated = newalloc;
+        return q;
+}
+
+void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
+        size_t prev;
+        uint8_t *q;
+
+        assert(p);
+        assert(allocated);
+
+        prev = *allocated;
+
+        q = greedy_realloc(p, allocated, need, size);
+        if (!q)
+                return NULL;
+
+        if (*allocated > prev)
+                memzero(q + prev * size, (*allocated - prev) * size);
+
+        return q;
+}
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
new file mode 100644 (file)
index 0000000..12b602e
--- /dev/null
@@ -0,0 +1,108 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macro.h"
+
+#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
+
+#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+
+#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
+
+#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
+
+#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
+
+#define malloc0(n) (calloc(1, (n)))
+
+static inline void *mfree(void *memory) {
+        free(memory);
+        return NULL;
+}
+
+void* memdup(const void *p, size_t l) _alloc_(2);
+
+static inline void freep(void *p) {
+        free(*(void**) p);
+}
+
+#define _cleanup_free_ _cleanup_(freep)
+
+_malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
+        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+                return NULL;
+
+        return malloc(a * b);
+}
+
+_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
+        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+                return NULL;
+
+        return realloc(p, a * b);
+}
+
+_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
+        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+                return NULL;
+
+        return memdup(p, a * b);
+}
+
+void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
+void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
+
+#define GREEDY_REALLOC(array, allocated, need)                          \
+        greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
+
+#define GREEDY_REALLOC0(array, allocated, need)                         \
+        greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
+
+#define alloca0(n)                                      \
+        ({                                              \
+                char *_new_;                            \
+                size_t _len_ = n;                       \
+                _new_ = alloca(_len_);                  \
+                (void *) memset(_new_, 0, _len_);       \
+        })
+
+/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
+#define alloca_align(size, align)                                       \
+        ({                                                              \
+                void *_ptr_;                                            \
+                size_t _mask_ = (align) - 1;                            \
+                _ptr_ = alloca((size) + _mask_);                        \
+                (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
+        })
+
+#define alloca0_align(size, align)                                      \
+        ({                                                              \
+                void *_new_;                                            \
+                size_t _size_ = (size);                                 \
+                _new_ = alloca_align(_size_, (align));                  \
+                (void*)memset(_new_, 0, _size_);                        \
+        })
index 7725e6d7d363e7ee17821214863525dd062e4c18..c3135f0efe2c8abdaca148e5209e6a7b294671bc 100644 (file)
@@ -23,6 +23,7 @@
 #include <unistd.h>
 
 #include "async.h"
+#include "fd-util.h"
 #include "log.h"
 #include "util.h"
 
similarity index 95%
rename from src/basic/audit.c
rename to src/basic/audit-util.c
index 1f593aa813571673b448873ce6bad9ad35f60cc5..4612297334156aa325b62894603120c30e45be50 100644 (file)
 #include <errno.h>
 #include <stdio.h>
 
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "macro.h"
-#include "audit.h"
-#include "util.h"
+#include "parse-util.h"
 #include "process-util.h"
-#include "fileio.h"
+#include "user-util.h"
+#include "util.h"
 
 int audit_session_from_pid(pid_t pid, uint32_t *id) {
         _cleanup_free_ char *s = NULL;
similarity index 100%
rename from src/basic/audit.h
rename to src/basic/audit-util.h
index 436ba9598910a861b59312effa26622f7cdee1c8..2d55bab4abb39c5c9fca8dbaa47b6de284973e3e 100644 (file)
@@ -30,6 +30,7 @@
 #include <unistd.h>
 
 #include "barrier.h"
+#include "fd-util.h"
 #include "macro.h"
 #include "util.h"
 
index 2eabf3e1c1bbaf5d140c2fc1214bd74e80e2cad9..1449e2ea852504b682ac54fb4ea0a1775ae9c8ce 100644 (file)
@@ -19,9 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-
+#include "alloc-util.h"
 #include "bitmap.h"
+#include "util.h"
 
 struct Bitmap {
         uint64_t *bitmaps;
index 074deeccdaa2154138b808dba138fbec574d51dd..290fabdeffef111a62ffd39aed13cec1fecbdad7 100644 (file)
 ***/
 
 #include <stdlib.h>
-#include <sys/vfs.h>
 #include <sys/stat.h>
-
+#include <sys/vfs.h>
 #ifdef HAVE_LINUX_BTRFS_H
 #include <linux/btrfs.h>
 #endif
 
+#include "alloc-util.h"
+#include "btrfs-ctree.h"
+#include "btrfs-util.h"
+#include "copy.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "macro.h"
 #include "missing.h"
-#include "util.h"
 #include "path-util.h"
-#include "macro.h"
-#include "copy.h"
 #include "selinux-util.h"
 #include "smack-util.h"
-#include "fileio.h"
-#include "btrfs-ctree.h"
-#include "btrfs-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
 
 /* WARNING: Be careful with file system ioctls! When we get an fd, we
  * need to make sure it either refers to only a regular file or
@@ -59,13 +62,13 @@ static int validate_subvolume_name(const char *name) {
 
 static int open_parent(const char *path, int flags) {
         _cleanup_free_ char *parent = NULL;
-        int r, fd;
+        int fd;
 
         assert(path);
 
-        r = path_get_parent(path, &parent);
-        if (r < 0)
-                return r;
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
 
         fd = open(parent, flags);
         if (fd < 0)
@@ -436,7 +439,7 @@ static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
 #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh)                              \
         ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
 
-int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
+int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
         struct btrfs_ioctl_search_args args = {
                 /* Tree of tree roots */
                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
@@ -453,16 +456,23 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
                 .key.max_transid = (uint64_t) -1,
         };
 
-        uint64_t subvol_id;
         bool found = false;
         int r;
 
         assert(fd >= 0);
         assert(ret);
 
-        r = btrfs_subvol_get_id_fd(fd, &subvol_id);
-        if (r < 0)
-                return r;
+        if (subvol_id == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+                if (r < 0)
+                        return r;
+        } else {
+                r = btrfs_is_filesystem(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+        }
 
         args.key.min_objectid = args.key.max_objectid = subvol_id;
 
@@ -521,7 +531,7 @@ finish:
         return 0;
 }
 
-int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
+int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
 
         struct btrfs_ioctl_search_args args = {
                 /* Tree of quota items */
@@ -540,26 +550,37 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
                 .key.max_transid = (uint64_t) -1,
         };
 
-        uint64_t subvol_id;
         bool found_info = false, found_limit = false;
         int r;
 
         assert(fd >= 0);
         assert(ret);
 
-        r = btrfs_subvol_get_id_fd(fd, &subvol_id);
-        if (r < 0)
-                return r;
+        if (qgroupid == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+                if (r < 0)
+                        return r;
+        } else {
+                r = btrfs_is_filesystem(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+        }
 
-        args.key.min_offset = args.key.max_offset = subvol_id;
+        args.key.min_offset = args.key.max_offset = qgroupid;
 
         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
                 const struct btrfs_ioctl_search_header *sh;
                 unsigned i;
 
                 args.key.nr_items = 256;
-                if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+                if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
+                        if (errno == ENOENT) /* quota tree is missing: quota disabled */
+                                break;
+
                         return -errno;
+                }
 
                 if (args.key.nr_items <= 0)
                         break;
@@ -571,7 +592,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
 
                         if (sh->objectid != 0)
                                 continue;
-                        if (sh->offset != subvol_id)
+                        if (sh->offset != qgroupid)
                                 continue;
 
                         if (sh->type == BTRFS_QGROUP_INFO_KEY) {
@@ -585,12 +606,14 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
                         } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
                                 const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
 
-                                ret->referenced_max = le64toh(qli->max_rfer);
-                                ret->exclusive_max = le64toh(qli->max_excl);
-
-                                if (ret->referenced_max == 0)
+                                if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER)
+                                        ret->referenced_max = le64toh(qli->max_rfer);
+                                else
                                         ret->referenced_max = (uint64_t) -1;
-                                if (ret->exclusive_max == 0)
+
+                                if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL)
+                                        ret->exclusive_max = le64toh(qli->max_excl);
+                                else
                                         ret->exclusive_max = (uint64_t) -1;
 
                                 found_limit = true;
@@ -622,6 +645,109 @@ finish:
         return 0;
 }
 
+int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
+}
+
+int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) {
+        uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0;
+        _cleanup_free_ uint64_t *qgroups = NULL;
+        int r, n, i;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        /* This finds the "subtree" qgroup for a specific
+         * subvolume. This only works for subvolumes that have been
+         * prepared with btrfs_subvol_auto_qgroup_fd() with
+         * insert_intermediary_qgroup=true (or equivalent). For others
+         * it will return the leaf qgroup instead. The two cases may
+         * be distuingished via the return value, which is 1 in case
+         * an appropriate "subtree" qgroup was found, and 0
+         * otherwise. */
+
+        if (subvol_id == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+                if (r < 0)
+                        return r;
+        }
+
+        r = btrfs_qgroupid_split(subvol_id, &level, NULL);
+        if (r < 0)
+                return r;
+        if (level != 0) /* Input must be a leaf qgroup */
+                return -EINVAL;
+
+        n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
+        if (n < 0)
+                return n;
+
+        for (i = 0; i < n; i++) {
+                uint64_t id;
+
+                r = btrfs_qgroupid_split(qgroups[i], &level, &id);
+                if (r < 0)
+                        return r;
+
+                if (id != subvol_id)
+                        continue;
+
+                if (lowest == (uint64_t) -1 || level < lowest) {
+                        lowest_qgroupid = qgroups[i];
+                        lowest = level;
+                }
+        }
+
+        if (lowest == (uint64_t) -1) {
+                /* No suitable higher-level qgroup found, let's return
+                 * the leaf qgroup instead, and indicate that with the
+                 * return value. */
+
+                *ret = subvol_id;
+                return 0;
+        }
+
+        *ret = lowest_qgroupid;
+        return 1;
+}
+
+int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
+        uint64_t qgroupid;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        /* This determines the quota data of the qgroup with the
+         * lowest level, that shares the id part with the specified
+         * subvolume. This is useful for determining the quota data
+         * for entire subvolume subtrees, as long as the subtrees have
+         * been set up with btrfs_qgroup_subvol_auto_fd() or in a
+         * compatible way */
+
+        r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
+        if (r < 0)
+                return r;
+
+        return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
+}
+
+int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
+}
+
 int btrfs_defrag_fd(int fd) {
         struct stat st;
 
@@ -679,37 +805,79 @@ int btrfs_quota_enable(const char *path, bool b) {
         return btrfs_quota_enable_fd(fd, b);
 }
 
-int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) {
+int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) {
+
         struct btrfs_ioctl_qgroup_limit_args args = {
-                .lim.max_rfer =
-                        referenced_max == (uint64_t) -1 ? 0 :
-                        referenced_max == 0 ? 1 : referenced_max,
+                .lim.max_rfer = referenced_max,
                 .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
         };
+        unsigned c;
         int r;
 
         assert(fd >= 0);
 
-        r = btrfs_is_filesystem(fd);
-        if (r < 0)
-                return r;
-        if (!r)
-                return -ENOTTY;
+        if (qgroupid == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+                if (r < 0)
+                        return r;
+        } else {
+                r = btrfs_is_filesystem(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+        }
 
-        if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
-                return -errno;
+        args.qgroupid = qgroupid;
+
+        for (c = 0;; c++) {
+                if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) {
+
+                        if (errno == EBUSY && c < 10) {
+                                (void) btrfs_quota_scan_wait(fd);
+                                continue;
+                        }
+
+                        return -errno;
+                }
+
+                break;
+        }
 
         return 0;
 }
 
-int btrfs_quota_limit(const char *path, uint64_t referenced_max) {
+int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
+}
+
+int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) {
+        uint64_t qgroupid;
+        int r;
+
+        assert(fd >= 0);
+
+        r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
+        if (r < 0)
+                return r;
+
+        return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
+}
+
+int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) {
         _cleanup_close_ int fd = -1;
 
         fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
         if (fd < 0)
                 return -errno;
 
-        return btrfs_quota_limit_fd(fd, referenced_max);
+        return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max);
 }
 
 int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
@@ -799,7 +967,192 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
         return btrfs_resize_loopback_fd(fd, new_size, grow_only);
 }
 
-static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
+int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) {
+        assert(ret);
+
+        if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT)))
+                return -EINVAL;
+
+        if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT))
+                return -EINVAL;
+
+        *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
+        return 0;
+}
+
+int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) {
+        assert(level || id);
+
+        if (level)
+                *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT;
+
+        if (id)
+                *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1);
+
+        return 0;
+}
+
+static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) {
+
+        struct btrfs_ioctl_qgroup_create_args args = {
+                .create = b,
+                .qgroupid = qgroupid,
+        };
+        unsigned c;
+        int r;
+
+        r = btrfs_is_filesystem(fd);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -ENOTTY;
+
+        for (c = 0;; c++) {
+                if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
+
+                        /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */
+                        if (errno == EINVAL)
+                                return -ENOPROTOOPT;
+
+                        if (errno == EBUSY && c < 10) {
+                                (void) btrfs_quota_scan_wait(fd);
+                                continue;
+                        }
+
+                        return -errno;
+                }
+
+                break;
+        }
+
+        return 0;
+}
+
+int btrfs_qgroup_create(int fd, uint64_t qgroupid) {
+        return qgroup_create_or_destroy(fd, true, qgroupid);
+}
+
+int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) {
+        return qgroup_create_or_destroy(fd, false, qgroupid);
+}
+
+int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) {
+        _cleanup_free_ uint64_t *qgroups = NULL;
+        uint64_t subvol_id;
+        int i, n, r;
+
+        /* Destroys the specified qgroup, but unassigns it from all
+         * its parents first. Also, it recursively destroys all
+         * qgroups it is assgined to that have the same id part of the
+         * qgroupid as the specified group. */
+
+        r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id);
+        if (r < 0)
+                return r;
+
+        n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups);
+        if (n < 0)
+                return n;
+
+        for (i = 0; i < n; i++) {
+                uint64_t id;
+
+                r = btrfs_qgroupid_split(qgroups[i], NULL, &id);
+                if (r < 0)
+                        return r;
+
+                r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]);
+                if (r < 0)
+                        return r;
+
+                if (id != subvol_id)
+                        continue;
+
+                /* The parent qgroupid shares the same id part with
+                 * us? If so, destroy it too. */
+
+                (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]);
+        }
+
+        return btrfs_qgroup_destroy(fd, qgroupid);
+}
+
+int btrfs_quota_scan_start(int fd) {
+        struct btrfs_ioctl_quota_rescan_args args = {};
+
+        assert(fd >= 0);
+
+        if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int btrfs_quota_scan_wait(int fd) {
+        assert(fd >= 0);
+
+        if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int btrfs_quota_scan_ongoing(int fd) {
+        struct btrfs_ioctl_quota_rescan_args args = {};
+
+        assert(fd >= 0);
+
+        if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0)
+                return -errno;
+
+        return !!args.flags;
+}
+
+static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) {
+        struct btrfs_ioctl_qgroup_assign_args args = {
+                .assign = b,
+                .src = child,
+                .dst = parent,
+        };
+        unsigned c;
+        int r;
+
+        r = btrfs_is_filesystem(fd);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -ENOTTY;
+
+        for (c = 0;; c++) {
+                r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
+                if (r < 0) {
+                        if (errno == EBUSY && c < 10) {
+                                (void) btrfs_quota_scan_wait(fd);
+                                continue;
+                        }
+
+                        return -errno;
+                }
+
+                if (r == 0)
+                        return 0;
+
+                /* If the return value is > 0, we need to request a rescan */
+
+                (void) btrfs_quota_scan_start(fd);
+                return 1;
+        }
+}
+
+int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) {
+        return qgroup_assign_or_unassign(fd, true, child, parent);
+}
+
+int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) {
+        return qgroup_assign_or_unassign(fd, false, child, parent);
+}
+
+static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) {
         struct btrfs_ioctl_search_args args = {
                 .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
 
@@ -828,16 +1181,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
         if (!S_ISDIR(st.st_mode))
                 return -EINVAL;
 
-        /* First, try to remove the subvolume. If it happens to be
-         * already empty, this will just work. */
-        strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
-        if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
-                return 0;
-        if (!recursive || errno != ENOTEMPTY)
-                return -errno;
-
-        /* OK, the subvolume is not empty, let's look for child
-         * subvolumes, and remove them, first */
         subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
         if (subvol_fd < 0)
                 return -errno;
@@ -848,7 +1191,20 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
                         return r;
         }
 
-        args.key.min_offset = args.key.max_offset = subvol_id;
+        /* First, try to remove the subvolume. If it happens to be
+         * already empty, this will just work. */
+        strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+        if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
+                (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
+                return 0;
+        }
+        if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY)
+                return -errno;
+
+        /* OK, the subvolume is not empty, let's look for child
+         * subvolumes, and remove them, first */
+
+        args.key.min_offset = args.key.max_offset = subvol_id;
 
         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
                 const struct btrfs_ioctl_search_header *sh;
@@ -897,7 +1253,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
                         if (isempty(ino_args.name))
                                 /* Subvolume is in the top-level
                                  * directory of the subvolume. */
-                                r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive);
+                                r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
                         else {
                                 _cleanup_close_ int child_fd = -1;
 
@@ -909,7 +1265,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
                                 if (child_fd < 0)
                                         return -errno;
 
-                                r = subvol_remove_children(child_fd, p, sh->objectid, recursive);
+                                r = subvol_remove_children(child_fd, p, sh->objectid, flags);
                         }
                         if (r < 0)
                                 return r;
@@ -925,10 +1281,11 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
         if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
                 return -errno;
 
+        (void) btrfs_qgroup_destroy_recursive(fd, subvol_id);
         return 0;
 }
 
-int btrfs_subvol_remove(const char *path, bool recursive) {
+int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
         _cleanup_close_ int fd = -1;
         const char *subvolume;
         int r;
@@ -943,11 +1300,198 @@ int btrfs_subvol_remove(const char *path, bool recursive) {
         if (fd < 0)
                 return fd;
 
-        return subvol_remove_children(fd, subvolume, 0, recursive);
+        return subvol_remove_children(fd, subvolume, 0, flags);
+}
+
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
+        return subvol_remove_children(fd, subvolume, 0, flags);
+}
+
+int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) {
+
+        struct btrfs_ioctl_search_args args = {
+                /* Tree of quota items */
+                .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+
+                /* The object ID is always 0 */
+                .key.min_objectid = 0,
+                .key.max_objectid = 0,
+
+                /* Look precisely for the quota items */
+                .key.min_type = BTRFS_QGROUP_LIMIT_KEY,
+                .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
+
+                /* For our qgroup */
+                .key.min_offset = old_qgroupid,
+                .key.max_offset = old_qgroupid,
+
+                /* No restrictions on the other components */
+                .key.min_transid = 0,
+                .key.max_transid = (uint64_t) -1,
+        };
+
+        int r;
+
+        r = btrfs_is_filesystem(fd);
+        if (r < 0)
+                return r;
+        if (!r)
+                return -ENOTTY;
+
+        while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+                const struct btrfs_ioctl_search_header *sh;
+                unsigned i;
+
+                args.key.nr_items = 256;
+                if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
+                        if (errno == ENOENT) /* quota tree missing: quota is not enabled, hence nothing to copy */
+                                break;
+
+                        return -errno;
+                }
+
+                if (args.key.nr_items <= 0)
+                        break;
+
+                FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+                        const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+                        struct btrfs_ioctl_qgroup_limit_args qargs;
+                        unsigned c;
+
+                        /* Make sure we start the next search at least from this entry */
+                        btrfs_ioctl_search_args_set(&args, sh);
+
+                        if (sh->objectid != 0)
+                                continue;
+                        if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
+                                continue;
+                        if (sh->offset != old_qgroupid)
+                                continue;
+
+                        /* We found the entry, now copy things over. */
+
+                        qargs = (struct btrfs_ioctl_qgroup_limit_args) {
+                                .qgroupid = new_qgroupid,
+
+                                .lim.max_rfer = le64toh(qli->max_rfer),
+                                .lim.max_excl = le64toh(qli->max_excl),
+                                .lim.rsv_rfer = le64toh(qli->rsv_rfer),
+                                .lim.rsv_excl = le64toh(qli->rsv_excl),
+
+                                .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER|
+                                                                    BTRFS_QGROUP_LIMIT_MAX_EXCL|
+                                                                    BTRFS_QGROUP_LIMIT_RSV_RFER|
+                                                                    BTRFS_QGROUP_LIMIT_RSV_EXCL),
+                        };
+
+                        for (c = 0;; c++) {
+                                if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) {
+                                        if (errno == EBUSY && c < 10) {
+                                                (void) btrfs_quota_scan_wait(fd);
+                                                continue;
+                                        }
+                                        return -errno;
+                                }
+
+                                break;
+                        }
+
+                        return 1;
+                }
+
+                /* Increase search key by one, to read the next item, if we can. */
+                if (!btrfs_ioctl_search_args_inc(&args))
+                        break;
+        }
+
+        return 0;
 }
 
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) {
-        return subvol_remove_children(fd, subvolume, 0, recursive);
+static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) {
+        _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL;
+        bool copy_from_parent = false, insert_intermediary_qgroup = false;
+        int n_old_qgroups, n_old_parent_qgroups, r, i;
+        uint64_t old_parent_id;
+
+        assert(fd >= 0);
+
+        /* Copies a reduced form of quota information from the old to
+         * the new subvolume. */
+
+        n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups);
+        if (n_old_qgroups <= 0) /* Nothing to copy */
+                return n_old_qgroups;
+
+        r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
+        if (r < 0)
+                return r;
+
+        n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
+        if (n_old_parent_qgroups < 0)
+                return n_old_parent_qgroups;
+
+        for (i = 0; i < n_old_qgroups; i++) {
+                uint64_t id;
+                int j;
+
+                r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id);
+                if (r < 0)
+                        return r;
+
+                if (id == old_subvol_id) {
+                        /* The old subvolume was member of a qgroup
+                         * that had the same id, but a different level
+                         * as it self. Let's set up something similar
+                         * in the destination. */
+                        insert_intermediary_qgroup = true;
+                        break;
+                }
+
+                for (j = 0; j < n_old_parent_qgroups; j++)
+                        if (old_parent_qgroups[j] == old_qgroups[i]) {
+                                /* The old subvolume shared a common
+                                 * parent qgroup with its parent
+                                 * subvolume. Let's set up something
+                                 * similar in the destination. */
+                                copy_from_parent = true;
+                        }
+        }
+
+        if (!insert_intermediary_qgroup && !copy_from_parent)
+                return 0;
+
+        return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup);
+}
+
+static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) {
+        uint64_t old_subtree_qgroup, new_subtree_qgroup;
+        bool changed;
+        int r;
+
+        /* First copy the leaf limits */
+        r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol);
+        if (r < 0)
+                return r;
+        changed = r > 0;
+
+        /* Then, try to copy the subtree limits, if there are any. */
+        r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return changed;
+
+        r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return changed;
+
+        r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup);
+        if (r != 0)
+                return r;
+
+        return changed;
 }
 
 static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
@@ -978,12 +1522,12 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
         assert(subvolume);
 
         strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
-        vol_args.fd = old_fd;
 
         if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
                 return -errno;
 
-        if (!(flags & BTRFS_SNAPSHOT_RECURSIVE))
+        if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
+            !(flags & BTRFS_SNAPSHOT_QUOTA))
                 return 0;
 
         if (old_subvol_id == 0) {
@@ -996,6 +1540,17 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
         if (r < 0)
                 return r;
 
+        if (flags & BTRFS_SNAPSHOT_QUOTA)
+                (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id);
+
+        if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) {
+
+                if (flags & BTRFS_SNAPSHOT_QUOTA)
+                        (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
+
+                return 0;
+        }
+
         args.key.min_offset = args.key.max_offset = old_subvol_id;
 
         while (btrfs_ioctl_search_args_compare(&args) <= 0) {
@@ -1113,6 +1668,9 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
                         break;
         }
 
+        if (flags & BTRFS_SNAPSHOT_QUOTA)
+                (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
+
         return 0;
 }
 
@@ -1137,14 +1695,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
 
                 r = copy_directory_fd(old_fd, new_path, true);
                 if (r < 0) {
-                        btrfs_subvol_remove(new_path, false);
+                        (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
                         return r;
                 }
 
                 if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
                         r = btrfs_subvol_set_read_only(new_path, true);
                         if (r < 0) {
-                                btrfs_subvol_remove(new_path, false);
+                                (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
                                 return r;
                         }
                 }
@@ -1175,3 +1733,306 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnaps
 
         return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
 }
+
+int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
+
+        struct btrfs_ioctl_search_args args = {
+                /* Tree of quota items */
+                .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+
+                /* Look precisely for the quota relation items */
+                .key.min_type = BTRFS_QGROUP_RELATION_KEY,
+                .key.max_type = BTRFS_QGROUP_RELATION_KEY,
+
+                /* No restrictions on the other components */
+                .key.min_offset = 0,
+                .key.max_offset = (uint64_t) -1,
+
+                .key.min_transid = 0,
+                .key.max_transid = (uint64_t) -1,
+        };
+
+        _cleanup_free_ uint64_t *items = NULL;
+        size_t n_items = 0, n_allocated = 0;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        if (qgroupid == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+                if (r < 0)
+                        return r;
+        } else {
+                r = btrfs_is_filesystem(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+        }
+
+        args.key.min_objectid = args.key.max_objectid = qgroupid;
+
+        while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+                const struct btrfs_ioctl_search_header *sh;
+                unsigned i;
+
+                args.key.nr_items = 256;
+                if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) {
+                        if (errno == ENOENT) /* quota tree missing: quota is disabled */
+                                break;
+
+                        return -errno;
+                }
+
+                if (args.key.nr_items <= 0)
+                        break;
+
+                FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+
+                        /* Make sure we start the next search at least from this entry */
+                        btrfs_ioctl_search_args_set(&args, sh);
+
+                        if (sh->type != BTRFS_QGROUP_RELATION_KEY)
+                                continue;
+                        if (sh->offset < sh->objectid)
+                                continue;
+                        if (sh->objectid != qgroupid)
+                                continue;
+
+                        if (!GREEDY_REALLOC(items, n_allocated, n_items+1))
+                                return -ENOMEM;
+
+                        items[n_items++] = sh->offset;
+                }
+
+                /* Increase search key by one, to read the next item, if we can. */
+                if (!btrfs_ioctl_search_args_inc(&args))
+                        break;
+        }
+
+        if (n_items <= 0) {
+                *ret = NULL;
+                return 0;
+        }
+
+        *ret = items;
+        items = NULL;
+
+        return (int) n_items;
+}
+
+int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
+        _cleanup_free_ uint64_t *qgroups = NULL;
+        uint64_t parent_subvol;
+        bool changed = false;
+        int n = 0, r;
+
+        assert(fd >= 0);
+
+        /*
+         * Sets up the specified subvolume's qgroup automatically in
+         * one of two ways:
+         *
+         * If insert_intermediary_qgroup is false, the subvolume's
+         * leaf qgroup will be assigned to the same parent qgroups as
+         * the subvolume's parent subvolume.
+         *
+         * If insert_intermediary_qgroup is true a new intermediary
+         * higher-level qgroup is created, with a higher level number,
+         * but reusing the id of the subvolume. The level number is
+         * picked as one smaller than the lowest level qgroup the
+         * parent subvolume is a member of. If the parent subvolume's
+         * leaf qgroup is assigned to no higher-level qgroup a new
+         * qgroup of level 255 is created instead. Either way, the new
+         * qgroup is then assigned to the parent's higher-level
+         * qgroup, and the subvolume itself is assigned to it.
+         *
+         * If the subvolume is already assigned to a higher level
+         * qgroup, no operation is executed.
+         *
+         * Effectively this means: regardless if
+         * insert_intermediary_qgroup is true or not, after this
+         * function is invoked the subvolume will be accounted within
+         * the same qgroups as the parent. However, if it is true, it
+         * will also get its own higher-level qgroup, which may in
+         * turn be used by subvolumes created beneath this subvolume
+         * later on.
+         *
+         * This hence defines a simple default qgroup setup for
+         * subvolumes, as long as this function is invoked on each
+         * created subvolume: each subvolume is always accounting
+         * together with its immediate parents. Optionally, if
+         * insert_intermediary_qgroup is true, it will also get a
+         * qgroup that then includes all its own child subvolumes.
+         */
+
+        if (subvol_id == 0) {
+                r = btrfs_is_subvol(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+
+                r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+                if (r < 0)
+                        return r;
+        }
+
+        n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
+        if (n < 0)
+                return n;
+        if (n > 0) /* already parent qgroups set up, let's bail */
+                return 0;
+
+        r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
+        if (r < 0)
+                return r;
+
+        qgroups = mfree(qgroups);
+        n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
+        if (n < 0)
+                return n;
+
+        if (insert_intermediary_qgroup) {
+                uint64_t lowest = 256, new_qgroupid;
+                bool created = false;
+                int i;
+
+                /* Determine the lowest qgroup that the parent
+                 * subvolume is assigned to. */
+
+                for (i = 0; i < n; i++) {
+                        uint64_t level;
+
+                        r = btrfs_qgroupid_split(qgroups[i], &level, NULL);
+                        if (r < 0)
+                                return r;
+
+                        if (level < lowest)
+                                lowest = level;
+                }
+
+                if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */
+                        return -EBUSY;
+
+                r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid);
+                if (r < 0)
+                        return r;
+
+                /* Create the new intermediary group, unless it already exists */
+                r = btrfs_qgroup_create(fd, new_qgroupid);
+                if (r < 0 && r != -EEXIST)
+                        return r;
+                if (r >= 0)
+                        changed = created = true;
+
+                for (i = 0; i < n; i++) {
+                        r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]);
+                        if (r < 0 && r != -EEXIST) {
+                                if (created)
+                                        (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
+
+                                return r;
+                        }
+                        if (r >= 0)
+                                changed = true;
+                }
+
+                r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid);
+                if (r < 0 && r != -EEXIST) {
+                        if (created)
+                                (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
+                        return r;
+                }
+                if (r >= 0)
+                        changed = true;
+
+        } else {
+                int i;
+
+                /* Assign our subvolume to all the same qgroups as the parent */
+
+                for (i = 0; i < n; i++) {
+                        r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]);
+                        if (r < 0 && r != -EEXIST)
+                                return r;
+                        if (r >= 0)
+                                changed = true;
+                }
+        }
+
+        return changed;
+}
+
+int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+        if (fd < 0)
+                return -errno;
+
+        return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
+}
+
+int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
+
+        struct btrfs_ioctl_search_args args = {
+                /* Tree of tree roots */
+                .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
+
+                /* Look precisely for the subvolume items */
+                .key.min_type = BTRFS_ROOT_BACKREF_KEY,
+                .key.max_type = BTRFS_ROOT_BACKREF_KEY,
+
+                /* No restrictions on the other components */
+                .key.min_offset = 0,
+                .key.max_offset = (uint64_t) -1,
+
+                .key.min_transid = 0,
+                .key.max_transid = (uint64_t) -1,
+        };
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        if (subvol_id == 0) {
+                r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+                if (r < 0)
+                        return r;
+        } else {
+                r = btrfs_is_filesystem(fd);
+                if (r < 0)
+                        return r;
+                if (!r)
+                        return -ENOTTY;
+        }
+
+        args.key.min_objectid = args.key.max_objectid = subvol_id;
+
+        while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+                const struct btrfs_ioctl_search_header *sh;
+                unsigned i;
+
+                args.key.nr_items = 256;
+                if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+                        return -errno;
+
+                if (args.key.nr_items <= 0)
+                        break;
+
+                FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+
+                        if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+                                continue;
+                        if (sh->objectid != subvol_id)
+                                continue;
+
+                        *ret = sh->offset;
+                        return 0;
+                }
+        }
+
+        return -ENXIO;
+}
index 8632c3638c227f0dad1eead3ffadcfdc673aba47..fc9efd72d5268805d526b3a591b8bbe1d964fc93 100644 (file)
@@ -47,42 +47,82 @@ typedef enum BtrfsSnapshotFlags {
         BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
         BTRFS_SNAPSHOT_READ_ONLY = 2,
         BTRFS_SNAPSHOT_RECURSIVE = 4,
+        BTRFS_SNAPSHOT_QUOTA = 8,
 } BtrfsSnapshotFlags;
 
+typedef enum BtrfsRemoveFlags {
+        BTRFS_REMOVE_RECURSIVE = 1,
+        BTRFS_REMOVE_QUOTA = 2,
+} BtrfsRemoveFlags;
+
 int btrfs_is_filesystem(int fd);
 int btrfs_is_subvol(int fd);
 
+int btrfs_reflink(int infd, int outfd);
+int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
+
+int btrfs_get_block_device_fd(int fd, dev_t *dev);
+int btrfs_get_block_device(const char *path, dev_t *dev);
+
+int btrfs_defrag_fd(int fd);
+int btrfs_defrag(const char *p);
+
+int btrfs_quota_enable_fd(int fd, bool b);
+int btrfs_quota_enable(const char *path, bool b);
+
+int btrfs_quota_scan_start(int fd);
+int btrfs_quota_scan_wait(int fd);
+int btrfs_quota_scan_ongoing(int fd);
+
+int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
+int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+
 int btrfs_subvol_make(const char *path);
 int btrfs_subvol_make_label(const char *path);
 
 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
 
+int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
+
 int btrfs_subvol_set_read_only_fd(int fd, bool b);
 int btrfs_subvol_set_read_only(const char *path, bool b);
 int btrfs_subvol_get_read_only_fd(int fd);
+
 int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
 int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
-int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info);
-int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota);
+int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret);
 
-int btrfs_reflink(int infd, int outfd);
-int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
+int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info);
 
-int btrfs_get_block_device_fd(int fd, dev_t *dev);
-int btrfs_get_block_device(const char *path, dev_t *dev);
+int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret);
 
-int btrfs_defrag_fd(int fd);
-int btrfs_defrag(const char *p);
+int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota);
+int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota);
 
-int btrfs_quota_enable_fd(int fd, bool b);
-int btrfs_quota_enable(const char *path, bool b);
+int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max);
+int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max);
 
-int btrfs_quota_limit_fd(int fd, uint64_t referenced_max);
-int btrfs_quota_limit(const char *path, uint64_t referenced_max);
+int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup);
+int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup);
 
-int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
-int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret);
+int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id);
+
+int btrfs_qgroup_create(int fd, uint64_t qgroupid);
+int btrfs_qgroup_destroy(int fd, uint64_t qgroupid);
+int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid);
+
+int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max);
+int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max);
+
+int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid);
+
+int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent);
+int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent);
+
+int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret);
 
-int btrfs_subvol_remove(const char *path, bool recursive);
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
+int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota);
+int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota);
index ccc9f2bf8e58df7c6047bafc13b22c127e77b0bb..c1534657ac921124ca8939d62b3e7301ad269c4e 100644 (file)
 
 #include <stdlib.h>
 
-#include "util.h"
-#include "macro.h"
-
+#include "alloc-util.h"
 #include "bus-label.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "util.h"
 
 char *bus_label_escape(const char *s) {
         char *r, *t;
index 2dcc9c55751acd4d81b8dd8b42247fc2599f87bc..7151fc3d0c6fe8a4999696caee26c016e0fc51de 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include "alloc-util.h"
+#include "string-util.h"
 #include "calendarspec.h"
+#include "fileio.h"
 
 #define BITS_WEEKDAYS   127
 
@@ -279,6 +282,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
         fputc(':', f);
         format_chain(f, 2, c->second);
 
+        if (c->utc)
+                fputs(" UTC", f);
+
         r = fflush_and_check(f);
         if (r < 0) {
                 free(buf);
@@ -556,7 +562,7 @@ static int parse_date(const char **p, CalendarSpec *c) {
         return -EINVAL;
 }
 
-static int parse_time(const char **p, CalendarSpec *c) {
+static int parse_calendar_time(const char **p, CalendarSpec *c) {
         CalendarComponent *h = NULL, *m = NULL, *s = NULL;
         const char *t;
         int r;
@@ -646,6 +652,7 @@ fail:
 int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
         CalendarSpec *c;
         int r;
+        const char *utc;
 
         assert(p);
         assert(spec);
@@ -657,6 +664,12 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
         if (!c)
                 return -ENOMEM;
 
+        utc = endswith_no_case(p, " UTC");
+        if (utc) {
+                c->utc = true;
+                p = strndupa(p, utc - p);
+        }
+
         if (strcaseeq(p, "minutely")) {
                 r = const_chain(0, &c->second);
                 if (r < 0)
@@ -789,7 +802,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
                 if (r < 0)
                         goto fail;
 
-                r = parse_time(&p, c);
+                r = parse_calendar_time(&p, c);
                 if (r < 0)
                         goto fail;
 
@@ -859,13 +872,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) {
         return r;
 }
 
-static bool tm_out_of_bounds(const struct tm *tm) {
+static bool tm_out_of_bounds(const struct tm *tm, bool utc) {
         struct tm t;
         assert(tm);
 
         t = *tm;
 
-        if (mktime(&t) == (time_t) -1)
+        if (mktime_or_timegm(&t, utc) == (time_t) -1)
                 return true;
 
         /* Did any normalization take place? If so, it was out of bounds before */
@@ -878,7 +891,7 @@ static bool tm_out_of_bounds(const struct tm *tm) {
                 t.tm_sec != tm->tm_sec;
 }
 
-static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
+static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
         struct tm t;
         int k;
 
@@ -886,7 +899,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
                 return true;
 
         t = *tm;
-        if (mktime(&t) == (time_t) -1)
+        if (mktime_or_timegm(&t, utc) == (time_t) -1)
                 return false;
 
         k = t.tm_wday == 0 ? 6 : t.tm_wday - 1;
@@ -904,7 +917,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
 
         for (;;) {
                 /* Normalize the current date */
-                mktime(&c);
+                mktime_or_timegm(&c, spec->utc);
                 c.tm_isdst = -1;
 
                 c.tm_year += 1900;
@@ -916,7 +929,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                 }
-                if (r < 0 || tm_out_of_bounds(&c))
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc))
                         return r;
 
                 c.tm_mon += 1;
@@ -927,7 +940,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                 }
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_year ++;
                         c.tm_mon = 0;
                         c.tm_mday = 1;
@@ -938,14 +951,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->day, &c.tm_mday);
                 if (r > 0)
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_mon ++;
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
                 }
 
-                if (!matches_weekday(spec->weekdays_bits, &c)) {
+                if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
                         c.tm_mday++;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
@@ -954,7 +967,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->hour, &c.tm_hour);
                 if (r > 0)
                         c.tm_min = c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_mday ++;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
@@ -963,14 +976,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->minute, &c.tm_min);
                 if (r > 0)
                         c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_hour ++;
                         c.tm_min = c.tm_sec = 0;
                         continue;
                 }
 
                 r = find_matching_component(spec->second, &c.tm_sec);
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_min ++;
                         c.tm_sec = 0;
                         continue;
@@ -991,13 +1004,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
         assert(next);
 
         t = (time_t) (usec / USEC_PER_SEC) + 1;
-        assert_se(localtime_r(&t, &tm));
+        assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
 
         r = find_next(spec, &tm);
         if (r < 0)
                 return r;
 
-        t = mktime(&tm);
+        t = mktime_or_timegm(&tm, spec->utc);
         if (t == (time_t) -1)
                 return -EINVAL;
 
index 7baf318249bb5c64bc509404bf68d99bad33a017..56dc02f391bc12cd8cc00d73a66d80ed915d6089 100644 (file)
@@ -36,6 +36,7 @@ typedef struct CalendarComponent {
 
 typedef struct CalendarSpec {
         int weekdays_bits;
+        bool utc;
 
         CalendarComponent *year;
         CalendarComponent *month;
index bd5bffbfa519479a207a4a2ef5744aab80c75e3a..4d391510bc8a254333d9ff5fc67a02a3fc92f274 100644 (file)
 
 #include <string.h>
 
-#include "util.h"
 #include "cap-list.h"
 #include "missing.h"
+#include "parse-util.h"
+#include "util.h"
 
 static const struct capability_name* lookup_capability(register const char *str, register unsigned int len);
 
similarity index 97%
rename from src/basic/capability.c
rename to src/basic/capability-util.c
index 8dbe4da5bbbe1280518e81bca9af166549f06bf1..0eb5c03d65601f6f457675f30564c084b0c5c80f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <errno.h>
+#include <grp.h>
 #include <stdio.h>
 #include <sys/capability.h>
 #include <sys/prctl.h>
-#include "grp.h"
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "capability-util.h"
+#include "fileio.h"
+#include "log.h"
 #include "macro.h"
+#include "parse-util.h"
 #include "util.h"
-#include "log.h"
-#include "fileio.h"
-#include "capability.h"
 
 int have_effective_cap(int value) {
         _cleanup_cap_free_ cap_t cap;
@@ -276,10 +278,8 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
                 assert(keep_capabilities & (1ULL << (i - 1)));
 
                 if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
-                    cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) {
-                        log_error_errno(errno, "Failed to enable capabilities bits: %m");
-                        return -errno;
-                }
+                    cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
+                        return log_error_errno(errno, "Failed to enable capabilities bits: %m");
 
                 if (cap_set_proc(d) < 0)
                         return log_error_errno(errno, "Failed to increase capabilities: %m");
index 95fc2b9e5d76ef9ae861aebaeca7c8e67dcc08f4..f7fc2c2c975d05dd0919a3b62ba69a74a37bbd4f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <dirent.h>
 #include <errno.h>
-#include <unistd.h>
+#include <ftw.h>
 #include <signal.h>
-#include <string.h>
 #include <stdlib.h>
-#include <dirent.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <ftw.h>
+#include <unistd.h>
 
-#include "set.h"
-#include "macro.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "dirent-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
-#include "process-util.h"
+#include "fs-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "unit-name.h"
-#include "fileio.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "set.h"
 #include "special.h"
-#include "mkdir.h"
-#include "login-util.h"
-#include "cgroup-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
 
 int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
         _cleanup_free_ char *fs = NULL;
diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c
new file mode 100644 (file)
index 0000000..d49ca05
--- /dev/null
@@ -0,0 +1,107 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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/ioctl.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+
+#include "chattr-util.h"
+#include "fd-util.h"
+#include "util.h"
+
+int chattr_fd(int fd, unsigned value, unsigned mask) {
+        unsigned old_attr, new_attr;
+        struct stat st;
+
+        assert(fd >= 0);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        /* Explicitly check whether this is a regular file or
+         * directory. If it is anything else (such as a device node or
+         * fifo), then the ioctl will not hit the file systems but
+         * possibly drivers, where the ioctl might have different
+         * effects. Notably, DRM is using the same ioctl() number. */
+
+        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+                return -ENOTTY;
+
+        if (mask == 0)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+                return -errno;
+
+        new_attr = (old_attr & ~mask) | (value & mask);
+        if (new_attr == old_attr)
+                return 0;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+                return -errno;
+
+        return 1;
+}
+
+int chattr_path(const char *p, unsigned value, unsigned mask) {
+        _cleanup_close_ int fd = -1;
+
+        assert(p);
+
+        if (mask == 0)
+                return 0;
+
+        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return chattr_fd(fd, value, mask);
+}
+
+int read_attr_fd(int fd, unsigned *ret) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+                return -ENOTTY;
+
+        if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int read_attr_path(const char *p, unsigned *ret) {
+        _cleanup_close_ int fd = -1;
+
+        assert(p);
+        assert(ret);
+
+        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+        if (fd < 0)
+                return -errno;
+
+        return read_attr_fd(fd, ret);
+}
diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h
new file mode 100644 (file)
index 0000000..ba6b8eb
--- /dev/null
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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/>.
+***/
+
+int chattr_fd(int fd, unsigned value, unsigned mask);
+int chattr_path(const char *p, unsigned value, unsigned mask);
+
+int read_attr_fd(int fd, unsigned *ret);
+int read_attr_path(const char *p, unsigned *ret);
index e4e03df1e47d196f1457e8c2ea00689de0780afb..00ee4c2796df7391876de0abf07e052f28f1c9b6 100644 (file)
 ***/
 
 #include <errno.h>
-#include <stdio.h>
 #include <fcntl.h>
+#include <linux/rtc.h>
+#include <stdio.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
-#include <linux/rtc.h>
 
+#include "clock-util.h"
+#include "fd-util.h"
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
-#include "clock-util.h"
 
 int clock_get_hwclock(struct tm *tm) {
         _cleanup_close_ int fd = -1;
index 8c2d2354302fc7771bf3e4f71d124f415db84325..fef2d471a6f37f45c83d13cb7bbc1b56f8e257f5 100644 (file)
@@ -21,6 +21,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <time.h>
 
 int clock_is_localtime(void);
 int clock_set_timezone(int *min);
index da8745b284d7462d9a3a03297b0784aff9bf09ce..be9972fffffe6fc054ec12f6ab790166cf10bf07 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
+#include <dirent.h>
 #include <errno.h>
-#include <stdlib.h>
 #include <stdio.h>
-#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include "conf-files.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "hashmap.h"
+#include "log.h"
 #include "macro.h"
-#include "util.h"
 #include "missing.h"
-#include "log.h"
-#include "strv.h"
 #include "path-util.h"
-#include "hashmap.h"
-#include "conf-files.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
         _cleanup_closedir_ DIR *dir = NULL;
index b20c178727357e33747760911e742ccd285d1491..a187ae08fe6dd542168ffe57eb67b37f0d17fc0a 100644 (file)
 #include <sys/sendfile.h>
 #include <sys/xattr.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "strv.h"
+#include "chattr-util.h"
 #include "copy.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "util.h"
+#include "xattr-util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
 
index 519583c167a0760b3a4f025473b069157925aa18..e2ec4ca83f06e1e9fb69cf65d3437f1f8c41b0ff 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
 #include "cpu-set-util.h"
+#include "extract-word.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
 
 cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         cpu_set_t *c;
@@ -69,14 +73,12 @@ int parse_cpu_set_and_warn(
 
         for (;;) {
                 _cleanup_free_ char *word = NULL;
-                unsigned cpu;
+                unsigned cpu, cpu_lower, cpu_upper;
                 int r;
 
-                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
-                        return r;
-                }
+                r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES);
+                if (r < 0)
+                        return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
                 if (r == 0)
                         break;
 
@@ -86,13 +88,17 @@ int parse_cpu_set_and_warn(
                                 return log_oom();
                 }
 
-                r = safe_atou(word, &cpu);
-                if (r < 0 || cpu >= ncpus) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", rvalue);
-                        return -EINVAL;
-                }
-
-                CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+                r = parse_range(word, &cpu_lower, &cpu_upper);
+                if (r < 0)
+                        return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word);
+                if (cpu_lower >= ncpus || cpu_upper >= ncpus)
+                        return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus);
+
+                if (cpu_lower > cpu_upper)
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper);
+                else
+                        for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
+                                CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
         }
 
         /* On success, sets *cpu_set and returns ncpus for the system. */
index 7c4161eb7277f2a651ad3f4d56287818ebb5a9d0..0657ac736724930a2267c2fd65d39dababca1c1e 100644 (file)
  * the watchdog pings will keep the loop busy. */
 #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
 
+/* The default value for the net.unix.max_dgram_qlen sysctl */
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL
+
 #define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
 
 #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
 #define SIGNALS_IGNORE SIGPIPE
 
-#define DIGITS            "0123456789"
-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
-#define ALPHANUMERICAL LETTERS DIGITS
-
 #define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
 
 #ifdef HAVE_SPLIT_USR
 
 #define NOTIFY_FD_MAX 768
 #define NOTIFY_BUFFER_MAX PIPE_BUF
+
+#ifdef HAVE_SPLIT_USR
+#define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0"
+#else
+#define _CONF_PATHS_SPLIT_USR(n)
+#endif
+
+/* Return a nulstr for a standard cascade of configuration paths,
+ * suitable to pass to conf_files_list_nulstr() or config_parse_many()
+ * to implement drop-in directories for extending configuration
+ * files. */
+#define CONF_PATHS_NULSTR(n) \
+        "/etc/" n "\0" \
+        "/run/" n "\0" \
+        "/usr/local/lib/" n "\0" \
+        "/usr/lib/" n "\0" \
+        _CONF_PATHS_SPLIT_USR(n)
index 04ba4897e5f908617d2062d15c5af9a8cdaa73f3..7db81f3d52e4e1110c5274fec8bdc196c9671ee1 100644 (file)
@@ -21,5 +21,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <sys/types.h>
+
 int encode_devnode_name(const char *str, char *str_enc, size_t len);
 int whitelisted_char_for_devnode(char c, const char *additional);
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
new file mode 100644 (file)
index 0000000..c433d58
--- /dev/null
@@ -0,0 +1,81 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010-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 <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "dirent-util.h"
+#include "string-util.h"
+
+int dirent_ensure_type(DIR *d, struct dirent *de) {
+        struct stat st;
+
+        assert(d);
+        assert(de);
+
+        if (de->d_type != DT_UNKNOWN)
+                return 0;
+
+        if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+                return -errno;
+
+        de->d_type =
+                S_ISREG(st.st_mode)  ? DT_REG  :
+                S_ISDIR(st.st_mode)  ? DT_DIR  :
+                S_ISLNK(st.st_mode)  ? DT_LNK  :
+                S_ISFIFO(st.st_mode) ? DT_FIFO :
+                S_ISSOCK(st.st_mode) ? DT_SOCK :
+                S_ISCHR(st.st_mode)  ? DT_CHR  :
+                S_ISBLK(st.st_mode)  ? DT_BLK  :
+                                       DT_UNKNOWN;
+
+        return 0;
+}
+
+bool dirent_is_file(const struct dirent *de) {
+        assert(de);
+
+        if (hidden_file(de->d_name))
+                return false;
+
+        if (de->d_type != DT_REG &&
+            de->d_type != DT_LNK &&
+            de->d_type != DT_UNKNOWN)
+                return false;
+
+        return true;
+}
+
+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)
+                return false;
+
+        if (hidden_file_allow_backup(de->d_name))
+                return false;
+
+        return endswith(de->d_name, suffix);
+}
diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h
new file mode 100644 (file)
index 0000000..5866a75
--- /dev/null
@@ -0,0 +1,51 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <dirent.h>
+
+#include "path-util.h"
+
+int dirent_ensure_type(DIR *d, struct dirent *de);
+
+bool dirent_is_file(const struct dirent *de) _pure_;
+bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
+
+#define FOREACH_DIRENT(de, d, on_error)                                 \
+        for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d))   \
+                if (!de) {                                              \
+                        if (errno > 0) {                                \
+                                on_error;                               \
+                        }                                               \
+                        break;                                          \
+                } else if (hidden_file((de)->d_name))                   \
+                        continue;                                       \
+                else
+
+#define FOREACH_DIRENT_ALL(de, d, on_error)                             \
+        for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d))   \
+                if (!de) {                                              \
+                        if (errno > 0) {                                \
+                                on_error;                               \
+                        }                                               \
+                        break;                                          \
+                } else
index ecb2192c4d79ea5b8b877a689421241bc1ea9058..441169db311eb3118be49ff36267d26ebd168a83 100644 (file)
 #include <limits.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "def.h"
+#include "env-util.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
 #include "util.h"
-#include "env-util.h"
-#include "def.h"
 
 #define VALID_CHARS_ENV_NAME                    \
         DIGITS LETTERS                          \
@@ -135,6 +138,21 @@ bool strv_env_is_valid(char **e) {
         return true;
 }
 
+bool strv_env_name_is_valid(char **l) {
+        char **p, **q;
+
+        STRV_FOREACH(p, l) {
+                if (!env_name_is_valid(*p))
+                        return false;
+
+                STRV_FOREACH(q, p + 1)
+                        if (streq(*p, *q))
+                                return false;
+        }
+
+        return true;
+}
+
 bool strv_env_name_or_assignment_is_valid(char **l) {
         char **p, **q;
 
@@ -592,3 +610,13 @@ char **replace_env_argv(char **argv, char **env) {
         ret[k] = NULL;
         return ret;
 }
+
+int getenv_bool(const char *p) {
+        const char *e;
+
+        e = getenv(p);
+        if (!e)
+                return -ENXIO;
+
+        return parse_boolean(e);
+}
index 803aa61cad7def354ea11335cf6ba50094ebddcb..5efffa3dc72483952f2a44bc2f853a1e294dd1b8 100644 (file)
@@ -36,6 +36,7 @@ bool strv_env_is_valid(char **e);
 #define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
 char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
 
+bool strv_env_name_is_valid(char **l);
 bool strv_env_name_or_assignment_is_valid(char **l);
 
 char **strv_env_merge(unsigned n_lists, ...);
@@ -47,3 +48,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_;
 
 char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
 char *strv_env_get(char **x, const char *n) _pure_;
+
+int getenv_bool(const char *p);
diff --git a/src/basic/escape.c b/src/basic/escape.c
new file mode 100644 (file)
index 0000000..4815161
--- /dev/null
@@ -0,0 +1,482 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "escape.h"
+#include "hexdecoct.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+size_t cescape_char(char c, char *buf) {
+        char * buf_old = buf;
+
+        switch (c) {
+
+                case '\a':
+                        *(buf++) = '\\';
+                        *(buf++) = 'a';
+                        break;
+                case '\b':
+                        *(buf++) = '\\';
+                        *(buf++) = 'b';
+                        break;
+                case '\f':
+                        *(buf++) = '\\';
+                        *(buf++) = 'f';
+                        break;
+                case '\n':
+                        *(buf++) = '\\';
+                        *(buf++) = 'n';
+                        break;
+                case '\r':
+                        *(buf++) = '\\';
+                        *(buf++) = 'r';
+                        break;
+                case '\t':
+                        *(buf++) = '\\';
+                        *(buf++) = 't';
+                        break;
+                case '\v':
+                        *(buf++) = '\\';
+                        *(buf++) = 'v';
+                        break;
+                case '\\':
+                        *(buf++) = '\\';
+                        *(buf++) = '\\';
+                        break;
+                case '"':
+                        *(buf++) = '\\';
+                        *(buf++) = '"';
+                        break;
+                case '\'':
+                        *(buf++) = '\\';
+                        *(buf++) = '\'';
+                        break;
+
+                default:
+                        /* For special chars we prefer octal over
+                         * hexadecimal encoding, simply because glib's
+                         * g_strescape() does the same */
+                        if ((c < ' ') || (c >= 127)) {
+                                *(buf++) = '\\';
+                                *(buf++) = octchar((unsigned char) c >> 6);
+                                *(buf++) = octchar((unsigned char) c >> 3);
+                                *(buf++) = octchar((unsigned char) c);
+                        } else
+                                *(buf++) = c;
+                        break;
+        }
+
+        return buf - buf_old;
+}
+
+char *cescape(const char *s) {
+        char *r, *t;
+        const char *f;
+
+        assert(s);
+
+        /* Does C style string escaping. May be reversed with
+         * cunescape(). */
+
+        r = new(char, strlen(s)*4 + 1);
+        if (!r)
+                return NULL;
+
+        for (f = s, t = r; *f; f++)
+                t += cescape_char(*f, t);
+
+        *t = 0;
+
+        return r;
+}
+
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
+        int r = 1;
+
+        assert(p);
+        assert(*p);
+        assert(ret);
+
+        /* Unescapes C style. Returns the unescaped character in ret,
+         * unless we encountered a \u sequence in which case the full
+         * unicode character is returned in ret_unicode, instead. */
+
+        if (length != (size_t) -1 && length < 1)
+                return -EINVAL;
+
+        switch (p[0]) {
+
+        case 'a':
+                *ret = '\a';
+                break;
+        case 'b':
+                *ret = '\b';
+                break;
+        case 'f':
+                *ret = '\f';
+                break;
+        case 'n':
+                *ret = '\n';
+                break;
+        case 'r':
+                *ret = '\r';
+                break;
+        case 't':
+                *ret = '\t';
+                break;
+        case 'v':
+                *ret = '\v';
+                break;
+        case '\\':
+                *ret = '\\';
+                break;
+        case '"':
+                *ret = '"';
+                break;
+        case '\'':
+                *ret = '\'';
+                break;
+
+        case 's':
+                /* This is an extension of the XDG syntax files */
+                *ret = ' ';
+                break;
+
+        case 'x': {
+                /* hexadecimal encoding */
+                int a, b;
+
+                if (length != (size_t) -1 && length < 3)
+                        return -EINVAL;
+
+                a = unhexchar(p[1]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unhexchar(p[2]);
+                if (b < 0)
+                        return -EINVAL;
+
+                /* Don't allow NUL bytes */
+                if (a == 0 && b == 0)
+                        return -EINVAL;
+
+                *ret = (char) ((a << 4U) | b);
+                r = 3;
+                break;
+        }
+
+        case 'u': {
+                /* C++11 style 16bit unicode */
+
+                int a[4];
+                unsigned i;
+                uint32_t c;
+
+                if (length != (size_t) -1 && length < 5)
+                        return -EINVAL;
+
+                for (i = 0; i < 4; i++) {
+                        a[i] = unhexchar(p[1 + i]);
+                        if (a[i] < 0)
+                                return a[i];
+                }
+
+                c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
+
+                /* Don't allow 0 chars */
+                if (c == 0)
+                        return -EINVAL;
+
+                if (c < 128)
+                        *ret = c;
+                else {
+                        if (!ret_unicode)
+                                return -EINVAL;
+
+                        *ret = 0;
+                        *ret_unicode = c;
+                }
+
+                r = 5;
+                break;
+        }
+
+        case 'U': {
+                /* C++11 style 32bit unicode */
+
+                int a[8];
+                unsigned i;
+                uint32_t c;
+
+                if (length != (size_t) -1 && length < 9)
+                        return -EINVAL;
+
+                for (i = 0; i < 8; i++) {
+                        a[i] = unhexchar(p[1 + i]);
+                        if (a[i] < 0)
+                                return a[i];
+                }
+
+                c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
+                    ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] <<  8U) | ((uint32_t) a[6] <<  4U) |  (uint32_t) a[7];
+
+                /* Don't allow 0 chars */
+                if (c == 0)
+                        return -EINVAL;
+
+                /* Don't allow invalid code points */
+                if (!unichar_is_valid(c))
+                        return -EINVAL;
+
+                if (c < 128)
+                        *ret = c;
+                else {
+                        if (!ret_unicode)
+                                return -EINVAL;
+
+                        *ret = 0;
+                        *ret_unicode = c;
+                }
+
+                r = 9;
+                break;
+        }
+
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7': {
+                /* octal encoding */
+                int a, b, c;
+                uint32_t m;
+
+                if (length != (size_t) -1 && length < 3)
+                        return -EINVAL;
+
+                a = unoctchar(p[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unoctchar(p[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unoctchar(p[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                /* don't allow NUL bytes */
+                if (a == 0 && b == 0 && c == 0)
+                        return -EINVAL;
+
+                /* Don't allow bytes above 255 */
+                m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
+                if (m > 255)
+                        return -EINVAL;
+
+                *ret = m;
+                r = 3;
+                break;
+        }
+
+        default:
+                return -EINVAL;
+        }
+
+        return r;
+}
+
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
+        char *r, *t;
+        const char *f;
+        size_t pl;
+
+        assert(s);
+        assert(ret);
+
+        /* Undoes C style string escaping, and optionally prefixes it. */
+
+        pl = prefix ? strlen(prefix) : 0;
+
+        r = new(char, pl+length+1);
+        if (!r)
+                return -ENOMEM;
+
+        if (prefix)
+                memcpy(r, prefix, pl);
+
+        for (f = s, t = r + pl; f < s + length; f++) {
+                size_t remaining;
+                uint32_t u;
+                char c;
+                int k;
+
+                remaining = s + length - f;
+                assert(remaining > 0);
+
+                if (*f != '\\') {
+                        /* A literal literal, copy verbatim */
+                        *(t++) = *f;
+                        continue;
+                }
+
+                if (remaining == 1) {
+                        if (flags & UNESCAPE_RELAX) {
+                                /* A trailing backslash, copy verbatim */
+                                *(t++) = *f;
+                                continue;
+                        }
+
+                        free(r);
+                        return -EINVAL;
+                }
+
+                k = cunescape_one(f + 1, remaining - 1, &c, &u);
+                if (k < 0) {
+                        if (flags & UNESCAPE_RELAX) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                                continue;
+                        }
+
+                        free(r);
+                        return k;
+                }
+
+                if (c != 0)
+                        /* Non-Unicode? Let's encode this directly */
+                        *(t++) = c;
+                else
+                        /* Unicode? Then let's encode this in UTF-8 */
+                        t += utf8_encode_unichar(t, u);
+
+                f += k;
+        }
+
+        *t = 0;
+
+        *ret = r;
+        return t - r;
+}
+
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+        return cunescape_length_with_prefix(s, length, NULL, flags, ret);
+}
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+        return cunescape_length(s, strlen(s), flags, ret);
+}
+
+char *xescape(const char *s, const char *bad) {
+        char *r, *t;
+        const char *f;
+
+        /* Escapes all chars in bad, in addition to \ and all special
+         * chars, in \xFF style escaping. May be reversed with
+         * cunescape(). */
+
+        r = new(char, strlen(s) * 4 + 1);
+        if (!r)
+                return NULL;
+
+        for (f = s, t = r; *f; f++) {
+
+                if ((*f < ' ') || (*f >= 127) ||
+                    (*f == '\\') || strchr(bad, *f)) {
+                        *(t++) = '\\';
+                        *(t++) = 'x';
+                        *(t++) = hexchar(*f >> 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
+        assert(bad);
+
+        for (; *s; s++) {
+                if (*s == '\\' || strchr(bad, *s))
+                        *(t++) = '\\';
+
+                *(t++) = *s;
+        }
+
+        return t;
+}
+
+char *shell_escape(const char *s, const char *bad) {
+        char *r, *t;
+
+        r = new(char, strlen(s)*2+1);
+        if (!r)
+                return NULL;
+
+        t = strcpy_backslash_escaped(r, s, bad);
+        *t = 0;
+
+        return r;
+}
+
+char *shell_maybe_quote(const char *s) {
+        const char *p;
+        char *r, *t;
+
+        assert(s);
+
+        /* Encloses a string in double quotes if necessary to make it
+         * OK as shell string. */
+
+        for (p = s; *p; p++)
+                if (*p <= ' ' ||
+                    *p >= 127 ||
+                    strchr(SHELL_NEED_QUOTES, *p))
+                        break;
+
+        if (!*p)
+                return strdup(s);
+
+        r = new(char, 1+strlen(s)*2+1+1);
+        if (!r)
+                return NULL;
+
+        t = r;
+        *(t++) = '"';
+        t = mempcpy(t, s, p - s);
+
+        t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
+
+        *(t++)= '"';
+        *t = 0;
+
+        return r;
+}
diff --git a/src/basic/escape.h b/src/basic/escape.h
new file mode 100644 (file)
index 0000000..85ba909
--- /dev/null
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <inttypes.h>
+
+/* What characters are special in the shell? */
+/* must be escaped outside and inside double-quotes */
+#define SHELL_NEED_ESCAPE "\"\\`$"
+/* can be escaped or double-quoted */
+#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
+
+typedef enum UnescapeFlags {
+        UNESCAPE_RELAX = 1,
+} UnescapeFlags;
+
+char *cescape(const char *s);
+size_t cescape_char(char c, char *buf);
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode);
+
+char *xescape(const char *s, const char *bad);
+
+char *shell_escape(const char *s, const char *bad);
+char *shell_maybe_quote(const char *s);
diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c
new file mode 100644 (file)
index 0000000..2bf3bfe
--- /dev/null
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 Tom Gundersen
+
+  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 <stdio.h>
+
+#include "ether-addr-util.h"
+#include "macro.h"
+
+char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
+        assert(addr);
+        assert(buffer);
+
+        /* Like ether_ntoa() but uses %02x instead of %x to print
+         * ethernet addresses, which makes them look less funny. Also,
+         * doesn't use a static buffer. */
+
+        sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
+                addr->ether_addr_octet[0],
+                addr->ether_addr_octet[1],
+                addr->ether_addr_octet[2],
+                addr->ether_addr_octet[3],
+                addr->ether_addr_octet[4],
+                addr->ether_addr_octet[5]);
+
+        return buffer;
+}
index 7033138788c1bf984971b5a852357d46485403c3..008f3b893e592a137c3dcf21ff9bdf19b60296fa 100644 (file)
@@ -25,3 +25,7 @@
 
 #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
 #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
+
+#define ETHER_ADDR_TO_STRING_MAX (3*6)
+
+char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
new file mode 100644 (file)
index 0000000..fd49569
--- /dev/null
@@ -0,0 +1,289 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "escape.h"
+#include "extract-word.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
+        _cleanup_free_ char *s = NULL;
+        size_t allocated = 0, sz = 0;
+        char c;
+        int r;
+
+        char quote = 0;                 /* 0 or ' or " */
+        bool backslash = false;         /* whether we've just seen a backslash */
+
+        assert(p);
+        assert(ret);
+
+        /* Bail early if called after last value or with no input */
+        if (!*p)
+                goto finish_force_terminate;
+        c = **p;
+
+        if (!separators)
+                separators = WHITESPACE;
+
+        /* Parses the first word of a string, and returns it in
+         * *ret. Removes all quotes in the process. When parsing fails
+         * (because of an uneven number of quotes or similar), leaves
+         * the pointer *p at the first invalid character. */
+
+        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+                if (!GREEDY_REALLOC(s, allocated, sz+1))
+                        return -ENOMEM;
+
+        for (;; (*p) ++, c = **p) {
+                if (c == 0)
+                        goto finish_force_terminate;
+                else if (strchr(separators, c)) {
+                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+                                (*p) ++;
+                                goto finish_force_next;
+                        }
+                } else {
+                        /* We found a non-blank character, so we will always
+                         * want to return a string (even if it is empty),
+                         * allocate it here. */
+                        if (!GREEDY_REALLOC(s, allocated, sz+1))
+                                return -ENOMEM;
+                        break;
+                }
+        }
+
+        for (;; (*p) ++, c = **p) {
+                if (backslash) {
+                        if (!GREEDY_REALLOC(s, allocated, sz+7))
+                                return -ENOMEM;
+
+                        if (c == 0) {
+                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+                                    (!quote || flags & EXTRACT_RELAX)) {
+                                        /* If we find an unquoted trailing backslash and we're in
+                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+                                         * output.
+                                         *
+                                         * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
+                                         */
+                                        s[sz++] = '\\';
+                                        goto finish_force_terminate;
+                                }
+                                if (flags & EXTRACT_RELAX)
+                                        goto finish_force_terminate;
+                                return -EINVAL;
+                        }
+
+                        if (flags & EXTRACT_CUNESCAPE) {
+                                uint32_t u;
+
+                                r = cunescape_one(*p, (size_t) -1, &c, &u);
+                                if (r < 0) {
+                                        if (flags & EXTRACT_CUNESCAPE_RELAX) {
+                                                s[sz++] = '\\';
+                                                s[sz++] = c;
+                                        } else
+                                                return -EINVAL;
+                                } else {
+                                        (*p) += r - 1;
+
+                                        if (c != 0)
+                                                s[sz++] = c; /* normal explicit char */
+                                        else
+                                                sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+                                }
+                        } else
+                                s[sz++] = c;
+
+                        backslash = false;
+
+                } else if (quote) {     /* inside either single or double quotes */
+                        for (;; (*p) ++, c = **p) {
+                                if (c == 0) {
+                                        if (flags & EXTRACT_RELAX)
+                                                goto finish_force_terminate;
+                                        return -EINVAL;
+                                } else if (c == quote) {        /* found the end quote */
+                                        quote = 0;
+                                        break;
+                                } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
+                                        backslash = true;
+                                        break;
+                                } else {
+                                        if (!GREEDY_REALLOC(s, allocated, sz+2))
+                                                return -ENOMEM;
+
+                                        s[sz++] = c;
+                                }
+                        }
+
+                } else {
+                        for (;; (*p) ++, c = **p) {
+                                if (c == 0)
+                                        goto finish_force_terminate;
+                                else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
+                                        quote = c;
+                                        break;
+                                } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) {
+                                        backslash = true;
+                                        break;
+                                } else if (strchr(separators, c)) {
+                                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+                                                (*p) ++;
+                                                goto finish_force_next;
+                                        }
+                                        /* Skip additional coalesced separators. */
+                                        for (;; (*p) ++, c = **p) {
+                                                if (c == 0)
+                                                        goto finish_force_terminate;
+                                                if (!strchr(separators, c))
+                                                        break;
+                                        }
+                                        goto finish;
+
+                                } else {
+                                        if (!GREEDY_REALLOC(s, allocated, sz+2))
+                                                return -ENOMEM;
+
+                                        s[sz++] = c;
+                                }
+                        }
+                }
+        }
+
+finish_force_terminate:
+        *p = NULL;
+finish:
+        if (!s) {
+                *p = NULL;
+                *ret = NULL;
+                return 0;
+        }
+
+finish_force_next:
+        s[sz] = 0;
+        *ret = s;
+        s = NULL;
+
+        return 1;
+}
+
+int extract_first_word_and_warn(
+                const char **p,
+                char **ret,
+                const char *separators,
+                ExtractFlags flags,
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *rvalue) {
+
+        /* Try to unquote it, if it fails, warn about it and try again
+         * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
+         * backslashes verbatim in invalid escape sequences. */
+
+        const char *save;
+        int r;
+
+        save = *p;
+        r = extract_first_word(p, ret, separators, flags);
+        if (r >= 0)
+                return r;
+
+        if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+
+                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
+                *p = save;
+                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
+                if (r >= 0) {
+                        /* It worked this time, hence it must have been an invalid escape sequence we could correct. */
+                        log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue);
+                        return r;
+                }
+
+                /* If it's still EINVAL; then it must be unbalanced quoting, report this. */
+                if (r == -EINVAL)
+                        return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue);
+        }
+
+        /* Can be any error, report it */
+        return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
+}
+
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+        va_list ap;
+        char **l;
+        int n = 0, i, c, r;
+
+        /* Parses a number of words from a string, stripping any
+         * quotes if necessary. */
+
+        assert(p);
+
+        /* Count how many words are expected */
+        va_start(ap, flags);
+        for (;;) {
+                if (!va_arg(ap, char **))
+                        break;
+                n++;
+        }
+        va_end(ap);
+
+        if (n <= 0)
+                return 0;
+
+        /* Read all words into a temporary array */
+        l = newa0(char*, n);
+        for (c = 0; c < n; c++) {
+
+                r = extract_first_word(p, &l[c], separators, flags);
+                if (r < 0) {
+                        int j;
+
+                        for (j = 0; j < c; j++)
+                                free(l[j]);
+
+                        return r;
+                }
+
+                if (r == 0)
+                        break;
+        }
+
+        /* If we managed to parse all words, return them in the passed
+         * in parameters */
+        va_start(ap, flags);
+        for (i = 0; i < n; i++) {
+                char **v;
+
+                v = va_arg(ap, char **);
+                assert(v);
+
+                *v = l[i];
+        }
+        va_end(ap);
+
+        return c;
+}
diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
new file mode 100644 (file)
index 0000000..9606ab6
--- /dev/null
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "macro.h"
+
+typedef enum ExtractFlags {
+        EXTRACT_RELAX                    = 1,
+        EXTRACT_CUNESCAPE                = 2,
+        EXTRACT_CUNESCAPE_RELAX          = 4,
+        EXTRACT_QUOTES                   = 8,
+        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
+        EXTRACT_RETAIN_ESCAPE            = 32,
+} ExtractFlags;
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
+int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
new file mode 100644 (file)
index 0000000..d1b1db3
--- /dev/null
@@ -0,0 +1,351 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "dirent-util.h"
+#include "fd-util.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "util.h"
+
+int close_nointr(int fd) {
+        assert(fd >= 0);
+
+        if (close(fd) >= 0)
+                return 0;
+
+        /*
+         * Just ignore EINTR; a retry loop is the wrong thing to do on
+         * Linux.
+         *
+         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+         */
+        if (errno == EINTR)
+                return 0;
+
+        return -errno;
+}
+
+int safe_close(int fd) {
+
+        /*
+         * Like close_nointr() but cannot fail. Guarantees errno is
+         * unchanged. Is a NOP with negative fds passed, and returns
+         * -1, so that it can be used in this syntax:
+         *
+         * fd = safe_close(fd);
+         */
+
+        if (fd >= 0) {
+                PROTECT_ERRNO;
+
+                /* The kernel might return pretty much any error code
+                 * via close(), but the fd will be closed anyway. The
+                 * only condition we want to check for here is whether
+                 * the fd was invalid at all... */
+
+                assert_se(close_nointr(fd) != -EBADF);
+        }
+
+        return -1;
+}
+
+void safe_close_pair(int p[]) {
+        assert(p);
+
+        if (p[0] == p[1]) {
+                /* Special case pairs which use the same fd in both
+                 * directions... */
+                p[0] = p[1] = safe_close(p[0]);
+                return;
+        }
+
+        p[0] = safe_close(p[0]);
+        p[1] = safe_close(p[1]);
+}
+
+void close_many(const int fds[], unsigned n_fd) {
+        unsigned i;
+
+        assert(fds || n_fd <= 0);
+
+        for (i = 0; i < n_fd; i++)
+                safe_close(fds[i]);
+}
+
+int fclose_nointr(FILE *f) {
+        assert(f);
+
+        /* Same as close_nointr(), but for fclose() */
+
+        if (fclose(f) == 0)
+                return 0;
+
+        if (errno == EINTR)
+                return 0;
+
+        return -errno;
+}
+
+FILE* safe_fclose(FILE *f) {
+
+        /* Same as safe_close(), but for fclose() */
+
+        if (f) {
+                PROTECT_ERRNO;
+
+                assert_se(fclose_nointr(f) != EBADF);
+        }
+
+        return NULL;
+}
+
+DIR* safe_closedir(DIR *d) {
+
+        if (d) {
+                PROTECT_ERRNO;
+
+                assert_se(closedir(d) >= 0 || errno != EBADF);
+        }
+
+        return NULL;
+}
+
+int fd_nonblock(int fd, bool nonblock) {
+        int flags, nflags;
+
+        assert(fd >= 0);
+
+        flags = fcntl(fd, F_GETFL, 0);
+        if (flags < 0)
+                return -errno;
+
+        if (nonblock)
+                nflags = flags | O_NONBLOCK;
+        else
+                nflags = flags & ~O_NONBLOCK;
+
+        if (nflags == flags)
+                return 0;
+
+        if (fcntl(fd, F_SETFL, nflags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int fd_cloexec(int fd, bool cloexec) {
+        int flags, nflags;
+
+        assert(fd >= 0);
+
+        flags = fcntl(fd, F_GETFD, 0);
+        if (flags < 0)
+                return -errno;
+
+        if (cloexec)
+                nflags = flags | FD_CLOEXEC;
+        else
+                nflags = flags & ~FD_CLOEXEC;
+
+        if (nflags == flags)
+                return 0;
+
+        if (fcntl(fd, F_SETFD, nflags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
+        unsigned i;
+
+        assert(n_fdset == 0 || fdset);
+
+        for (i = 0; i < n_fdset; i++)
+                if (fdset[i] == fd)
+                        return true;
+
+        return false;
+}
+
+int close_all_fds(const int except[], unsigned n_except) {
+        _cleanup_closedir_ DIR *d = NULL;
+        struct dirent *de;
+        int r = 0;
+
+        assert(n_except == 0 || except);
+
+        d = opendir("/proc/self/fd");
+        if (!d) {
+                int fd;
+                struct rlimit rl;
+
+                /* When /proc isn't available (for example in chroots)
+                 * the fallback is brute forcing through the fd
+                 * table */
+
+                assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
+                for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
+
+                        if (fd_in_set(fd, except, n_except))
+                                continue;
+
+                        if (close_nointr(fd) < 0)
+                                if (errno != EBADF && r == 0)
+                                        r = -errno;
+                }
+
+                return r;
+        }
+
+        while ((de = readdir(d))) {
+                int fd = -1;
+
+                if (hidden_file(de->d_name))
+                        continue;
+
+                if (safe_atoi(de->d_name, &fd) < 0)
+                        /* Let's better ignore this, just in case */
+                        continue;
+
+                if (fd < 3)
+                        continue;
+
+                if (fd == dirfd(d))
+                        continue;
+
+                if (fd_in_set(fd, except, n_except))
+                        continue;
+
+                if (close_nointr(fd) < 0) {
+                        /* Valgrind has its own FD and doesn't want to have it closed */
+                        if (errno != EBADF && r == 0)
+                                r = -errno;
+                }
+        }
+
+        return r;
+}
+
+int same_fd(int a, int b) {
+        struct stat sta, stb;
+        pid_t pid;
+        int r, fa, fb;
+
+        assert(a >= 0);
+        assert(b >= 0);
+
+        /* Compares two file descriptors. Note that semantics are
+         * quite different depending on whether we have kcmp() or we
+         * don't. If we have kcmp() this will only return true for
+         * dup()ed file descriptors, but not otherwise. If we don't
+         * have kcmp() this will also return true for two fds of the same
+         * file, created by separate open() calls. Since we use this
+         * call mostly for filtering out duplicates in the fd store
+         * this difference hopefully doesn't matter too much. */
+
+        if (a == b)
+                return true;
+
+        /* Try to use kcmp() if we have it. */
+        pid = getpid();
+        r = kcmp(pid, pid, KCMP_FILE, a, b);
+        if (r == 0)
+                return true;
+        if (r > 0)
+                return false;
+        if (errno != ENOSYS)
+                return -errno;
+
+        /* We don't have kcmp(), use fstat() instead. */
+        if (fstat(a, &sta) < 0)
+                return -errno;
+
+        if (fstat(b, &stb) < 0)
+                return -errno;
+
+        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
+                return false;
+
+        /* We consider all device fds different, since two device fds
+         * might refer to quite different device contexts even though
+         * they share the same inode and backing dev_t. */
+
+        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
+                return false;
+
+        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
+                return false;
+
+        /* The fds refer to the same inode on disk, let's also check
+         * if they have the same fd flags. This is useful to
+         * distinguish the read and write side of a pipe created with
+         * pipe(). */
+        fa = fcntl(a, F_GETFL);
+        if (fa < 0)
+                return -errno;
+
+        fb = fcntl(b, F_GETFL);
+        if (fb < 0)
+                return -errno;
+
+        return fa == fb;
+}
+
+void cmsg_close_all(struct msghdr *mh) {
+        struct cmsghdr *cmsg;
+
+        assert(mh);
+
+        CMSG_FOREACH(cmsg, mh)
+                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+                        close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+}
+
+bool fdname_is_valid(const char *s) {
+        const char *p;
+
+        /* Validates a name for $LISTEN_FDNAMES. We basically allow
+         * everything ASCII that's not a control character. Also, as
+         * special exception the ":" character is not allowed, as we
+         * use that as field separator in $LISTEN_FDNAMES.
+         *
+         * Note that the empty string is explicitly allowed
+         * here. However, we limit the length of the names to 255
+         * characters. */
+
+        if (!s)
+                return false;
+
+        for (p = s; *p; p++) {
+                if (*p < ' ')
+                        return false;
+                if (*p >= 127)
+                        return false;
+                if (*p == ':')
+                        return false;
+        }
+
+        return p - s < 256;
+}
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
new file mode 100644 (file)
index 0000000..1ca10f0
--- /dev/null
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdio.h>
+#include <dirent.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include "macro.h"
+
+int close_nointr(int fd);
+int safe_close(int fd);
+void safe_close_pair(int p[]);
+
+void close_many(const int fds[], unsigned n_fd);
+
+int fclose_nointr(FILE *f);
+FILE* safe_fclose(FILE *f);
+DIR* safe_closedir(DIR *f);
+
+static inline void closep(int *fd) {
+        safe_close(*fd);
+}
+
+static inline void close_pairp(int (*p)[2]) {
+        safe_close_pair(*p);
+}
+
+static inline void fclosep(FILE **f) {
+        safe_fclose(*f);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
+
+#define _cleanup_close_ _cleanup_(closep)
+#define _cleanup_fclose_ _cleanup_(fclosep)
+#define _cleanup_pclose_ _cleanup_(pclosep)
+#define _cleanup_closedir_ _cleanup_(closedirp)
+#define _cleanup_close_pair_ _cleanup_(close_pairp)
+
+int fd_nonblock(int fd, bool nonblock);
+int fd_cloexec(int fd, bool cloexec);
+
+int close_all_fds(const int except[], unsigned n_except);
+
+int same_fd(int a, int b);
+
+void cmsg_close_all(struct msghdr *mh);
+
+bool fdname_is_valid(const char *s);
index d70fe156a26044a3940920b1a8f20edf2f5b2fdc..42b0b2b98f635eaa33c8a5b2c7c24e537264d2b0 100644 (file)
 #include <dirent.h>
 #include <fcntl.h>
 
+#include "sd-daemon.h"
+
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fdset.h"
+#include "macro.h"
+#include "parse-util.h"
 #include "set.h"
 #include "util.h"
-#include "macro.h"
-#include "fdset.h"
-#include "sd-daemon.h"
 
 #define MAKE_SET(s) ((Set*) s)
 #define MAKE_FDSET(s) ((FDSet*) s)
@@ -40,7 +44,7 @@ FDSet *fdset_new(void) {
         return MAKE_FDSET(set_new(NULL));
 }
 
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) {
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) {
         unsigned i;
         FDSet *s;
         int r;
index 340438d7c401ce9cc4565242e46f11b34801a7dd..70d8acbcff3434e5e0983f1a93eeaea391d5afe1 100644 (file)
@@ -35,7 +35,7 @@ int fdset_consume(FDSet *s, int fd);
 bool fdset_contains(FDSet *s, int fd);
 int fdset_remove(FDSet *s, int fd);
 
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds);
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds);
 int fdset_new_fill(FDSet **ret);
 int fdset_new_listen_fds(FDSet **ret, bool unset);
 
index 13a85e11583e88b28f82cafb92d4745999d47f72..10aacdc56dc11f1465034cf9c57d083b6b77bdf2 100644 (file)
 
 #include <unistd.h>
 
-#include "util.h"
-#include "strv.h"
-#include "utf8.h"
+#include "alloc-util.h"
 #include "ctype.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "random-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "utf8.h"
+#include "util.h"
 
 int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
 
@@ -51,7 +62,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
         if (r < 0)
                 return r;
 
-        fchmod_umask(fileno(f), 0644);
+        (void) fchmod_umask(fileno(f), 0644);
 
         r = write_string_stream(f, line, enforce_newline);
         if (r >= 0) {
@@ -60,13 +71,14 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
         }
 
         if (r < 0)
-                unlink(p);
+                (void) unlink(p);
 
         return r;
 }
 
 int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
         _cleanup_fclose_ FILE *f = NULL;
+        int q, r;
 
         assert(fn);
         assert(line);
@@ -74,30 +86,58 @@ int write_string_file(const char *fn, const char *line, WriteStringFileFlags fla
         if (flags & WRITE_STRING_FILE_ATOMIC) {
                 assert(flags & WRITE_STRING_FILE_CREATE);
 
-                return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+                r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+                if (r < 0)
+                        goto fail;
+
+                return r;
         }
 
         if (flags & WRITE_STRING_FILE_CREATE) {
                 f = fopen(fn, "we");
-                if (!f)
-                        return -errno;
+                if (!f) {
+                        r = -errno;
+                        goto fail;
+                }
         } else {
                 int fd;
 
                 /* We manually build our own version of fopen(..., "we") that
                  * works without O_CREAT */
                 fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0)
-                        return -errno;
+                if (fd < 0) {
+                        r = -errno;
+                        goto fail;
+                }
 
                 f = fdopen(fd, "we");
                 if (!f) {
+                        r = -errno;
                         safe_close(fd);
-                        return -errno;
+                        goto fail;
                 }
         }
 
-        return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+        r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+        if (r < 0)
+                goto fail;
+
+        return 0;
+
+fail:
+        if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE))
+                return r;
+
+        f = safe_fclose(f);
+
+        /* OK, the operation failed, but let's see if the right
+         * contents in place already. If so, eat up the error. */
+
+        q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
+        if (q <= 0)
+                return r;
+
+        return 0;
 }
 
 int read_one_line_file(const char *fn, char **line) {
@@ -128,15 +168,41 @@ int read_one_line_file(const char *fn, char **line) {
         return 0;
 }
 
-int verify_one_line_file(const char *fn, const char *line) {
-        _cleanup_free_ char *value = NULL;
-        int r;
+int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *buf = NULL;
+        size_t l, k;
 
-        r = read_one_line_file(fn, &value);
-        if (r < 0)
-                return r;
+        assert(fn);
+        assert(blob);
+
+        l = strlen(blob);
+
+        if (accept_extra_nl && endswith(blob, "\n"))
+                accept_extra_nl = false;
+
+        buf = malloc(l + accept_extra_nl + 1);
+        if (!buf)
+                return -ENOMEM;
 
-        return streq(value, line);
+        f = fopen(fn, "re");
+        if (!f)
+                return -errno;
+
+        /* We try to read one byte more than we need, so that we know whether we hit eof */
+        errno = 0;
+        k = fread(buf, 1, l + accept_extra_nl + 1, f);
+        if (ferror(f))
+                return errno > 0 ? -errno : -EIO;
+
+        if (k != l && k != l + accept_extra_nl)
+                return 0;
+        if (memcmp(buf, blob, l) != 0)
+                return 0;
+        if (k > l && buf[l] != '\n')
+                return 0;
+
+        return 1;
 }
 
 int read_full_stream(FILE *f, char **contents, size_t *size) {
@@ -845,3 +911,332 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
         *field = f;
         return 0;
 }
+
+DIR *xopendirat(int fd, const char *name, int flags) {
+        int nfd;
+        DIR *d;
+
+        assert(!(flags & O_CREAT));
+
+        nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
+        if (nfd < 0)
+                return NULL;
+
+        d = fdopendir(nfd);
+        if (!d) {
+                safe_close(nfd);
+                return NULL;
+        }
+
+        return d;
+}
+
+static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
+        char **i;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (!path_strv_resolve_uniq(search, root))
+                return -ENOMEM;
+
+        STRV_FOREACH(i, search) {
+                _cleanup_free_ char *p = NULL;
+                FILE *f;
+
+                if (root)
+                        p = strjoin(root, *i, "/", path, NULL);
+                else
+                        p = strjoin(*i, "/", path, NULL);
+                if (!p)
+                        return -ENOMEM;
+
+                f = fopen(p, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                if (errno != ENOENT)
+                        return -errno;
+        }
+
+        return -ENOENT;
+}
+
+int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        copy = strv_copy((char**) search);
+        if (!copy)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, root, copy, _f);
+}
+
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        s = strv_split_nulstr(search);
+        if (!s)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, root, s, _f);
+}
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+        FILE *f;
+        char *t;
+        int r, fd;
+
+        assert(path);
+        assert(_f);
+        assert(_temp_path);
+
+        r = tempfn_xxxxxx(path, NULL, &t);
+        if (r < 0)
+                return r;
+
+        fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
+        if (fd < 0) {
+                free(t);
+                return -errno;
+        }
+
+        f = fdopen(fd, "we");
+        if (!f) {
+                unlink_noerrno(t);
+                free(t);
+                safe_close(fd);
+                return -errno;
+        }
+
+        *_f = f;
+        *_temp_path = t;
+
+        return 0;
+}
+
+int fflush_and_check(FILE *f) {
+        assert(f);
+
+        errno = 0;
+        fflush(f);
+
+        if (ferror(f))
+                return errno ? -errno : -EIO;
+
+        return 0;
+}
+
+/* This is much like like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern, int flags) {
+        _cleanup_umask_ mode_t u;
+        int fd;
+
+        assert(pattern);
+
+        u = umask(077);
+
+        fd = mkostemp(pattern, flags);
+        if (fd < 0)
+                return -errno;
+
+        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;
+
+        assert(p);
+        assert(ret);
+
+        /*
+         * Turns this:
+         *         /foo/bar/waldo
+         *
+         * Into this:
+         *         /foo/bar/.#<extra>waldoXXXXXX
+         */
+
+        fn = basename(p);
+        if (!filename_is_valid(fn))
+                return -EINVAL;
+
+        if (extra == NULL)
+                extra = "";
+
+        t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
+
+        *ret = path_kill_slashes(t);
+        return 0;
+}
+
+int tempfn_random(const char *p, const char *extra, char **ret) {
+        const char *fn;
+        char *t, *x;
+        uint64_t u;
+        unsigned i;
+
+        assert(p);
+        assert(ret);
+
+        /*
+         * Turns this:
+         *         /foo/bar/waldo
+         *
+         * Into this:
+         *         /foo/bar/.#<extra>waldobaa2a261115984a9
+         */
+
+        fn = basename(p);
+        if (!filename_is_valid(fn))
+                return -EINVAL;
+
+        if (!extra)
+                extra = "";
+
+        t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
+
+        u = random_u64();
+        for (i = 0; i < 16; i++) {
+                *(x++) = hexchar(u & 0xF);
+                u >>= 4;
+        }
+
+        *x = 0;
+
+        *ret = path_kill_slashes(t);
+        return 0;
+}
+
+int tempfn_random_child(const char *p, const char *extra, char **ret) {
+        char *t, *x;
+        uint64_t u;
+        unsigned i;
+
+        assert(p);
+        assert(ret);
+
+        /* Turns this:
+         *         /foo/bar/waldo
+         * Into this:
+         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
+         */
+
+        if (!extra)
+                extra = "";
+
+        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
+        if (!t)
+                return -ENOMEM;
+
+        x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
+
+        u = random_u64();
+        for (i = 0; i < 16; i++) {
+                *(x++) = hexchar(u & 0xF);
+                u >>= 4;
+        }
+
+        *x = 0;
+
+        *ret = path_kill_slashes(t);
+        return 0;
+}
+
+int write_timestamp_file_atomic(const char *fn, usec_t n) {
+        char ln[DECIMAL_STR_MAX(n)+2];
+
+        /* Creates a "timestamp" file, that contains nothing but a
+         * usec_t timestamp, formatted in ASCII. */
+
+        if (n <= 0 || n >= USEC_INFINITY)
+                return -ERANGE;
+
+        xsprintf(ln, USEC_FMT "\n", n);
+
+        return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+}
+
+int read_timestamp_file(const char *fn, usec_t *ret) {
+        _cleanup_free_ char *ln = NULL;
+        uint64_t t;
+        int r;
+
+        r = read_one_line_file(fn, &ln);
+        if (r < 0)
+                return r;
+
+        r = safe_atou64(ln, &t);
+        if (r < 0)
+                return r;
+
+        if (t <= 0 || t >= (uint64_t) USEC_INFINITY)
+                return -ERANGE;
+
+        *ret = (usec_t) t;
+        return 0;
+}
index 4998d4d04232e31acaa7f4ef0a90fcd7a94df7c8..95e8698941c4d9914ae47828ecf83b67f925f58a 100644 (file)
   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 <dirent.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <sys/types.h>
 
 #include "macro.h"
+#include "time-util.h"
 
 typedef enum {
         WRITE_STRING_FILE_CREATE = 1,
         WRITE_STRING_FILE_ATOMIC = 2,
         WRITE_STRING_FILE_AVOID_NEWLINE = 4,
+        WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8,
 } WriteStringFileFlags;
 
 int write_string_stream(FILE *f, const char *line, bool enforce_newline);
@@ -38,7 +44,7 @@ int read_one_line_file(const char *fn, char **line);
 int read_full_file(const char *fn, char **contents, size_t *size);
 int read_full_stream(FILE *f, char **contents, size_t *size);
 
-int verify_one_line_file(const char *fn, const char *line);
+int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
 
 int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
 int load_env_file(FILE *f, const char *fname, const char *separator, char ***l);
@@ -49,3 +55,30 @@ int write_env_file(const char *fname, char **l);
 int executable_is_script(const char *path, char **interpreter);
 
 int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
+
+DIR *xopendirat(int dirfd, const char *name, int flags);
+
+int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
+
+#define FOREACH_LINE(line, f, on_error)                         \
+        for (;;)                                                \
+                if (!fgets(line, sizeof(line), f)) {            \
+                        if (ferror(f)) {                        \
+                                on_error;                       \
+                        }                                       \
+                        break;                                  \
+                } else
+
+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);
+int tempfn_random_child(const char *p, const char *extra, char **ret);
+
+int write_timestamp_file_atomic(const char *fn, usec_t n);
+int read_timestamp_file(const char *fn, usec_t *ret);
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
new file mode 100644 (file)
index 0000000..2b6189a
--- /dev/null
@@ -0,0 +1,500 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+
+int unlink_noerrno(const char *path) {
+        PROTECT_ERRNO;
+        int r;
+
+        r = unlink(path);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int rmdir_parents(const char *path, const char *stop) {
+        size_t l;
+        int r = 0;
+
+        assert(path);
+        assert(stop);
+
+        l = strlen(path);
+
+        /* Skip trailing slashes */
+        while (l > 0 && path[l-1] == '/')
+                l--;
+
+        while (l > 0) {
+                char *t;
+
+                /* Skip last component */
+                while (l > 0 && path[l-1] != '/')
+                        l--;
+
+                /* Skip trailing slashes */
+                while (l > 0 && path[l-1] == '/')
+                        l--;
+
+                if (l <= 0)
+                        break;
+
+                t = strndup(path, l);
+                if (!t)
+                        return -ENOMEM;
+
+                if (path_startswith(stop, t)) {
+                        free(t);
+                        return 0;
+                }
+
+                r = rmdir(t);
+                free(t);
+
+                if (r < 0)
+                        if (errno != ENOENT)
+                                return -errno;
+        }
+
+        return 0;
+}
+
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
+        struct stat buf;
+        int ret;
+
+        ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
+        if (ret >= 0)
+                return 0;
+
+        /* renameat2() exists since Linux 3.15, btrfs added support for it later.
+         * If it is not implemented, fallback to another method. */
+        if (!IN_SET(errno, EINVAL, ENOSYS))
+                return -errno;
+
+        /* The link()/unlink() fallback does not work on directories. But
+         * renameat() without RENAME_NOREPLACE gives the same semantics on
+         * directories, except when newpath is an *empty* directory. This is
+         * good enough. */
+        ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
+        if (ret >= 0 && S_ISDIR(buf.st_mode)) {
+                ret = renameat(olddirfd, oldpath, newdirfd, newpath);
+                return ret >= 0 ? 0 : -errno;
+        }
+
+        /* If it is not a directory, use the link()/unlink() fallback. */
+        ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
+        if (ret < 0)
+                return -errno;
+
+        ret = unlinkat(olddirfd, oldpath, 0);
+        if (ret < 0) {
+                /* backup errno before the following unlinkat() alters it */
+                ret = errno;
+                (void) unlinkat(newdirfd, newpath, 0);
+                errno = ret;
+                return -errno;
+        }
+
+        return 0;
+}
+
+int readlinkat_malloc(int fd, const char *p, char **ret) {
+        size_t l = 100;
+        int r;
+
+        assert(p);
+        assert(ret);
+
+        for (;;) {
+                char *c;
+                ssize_t n;
+
+                c = new(char, l);
+                if (!c)
+                        return -ENOMEM;
+
+                n = readlinkat(fd, p, c, l-1);
+                if (n < 0) {
+                        r = -errno;
+                        free(c);
+                        return r;
+                }
+
+                if ((size_t) n < l-1) {
+                        c[n] = 0;
+                        *ret = c;
+                        return 0;
+                }
+
+                free(c);
+                l *= 2;
+        }
+}
+
+int readlink_malloc(const char *p, char **ret) {
+        return readlinkat_malloc(AT_FDCWD, p, ret);
+}
+
+int readlink_value(const char *p, char **ret) {
+        _cleanup_free_ char *link = NULL;
+        char *value;
+        int r;
+
+        r = readlink_malloc(p, &link);
+        if (r < 0)
+                return r;
+
+        value = basename(link);
+        if (!value)
+                return -ENOENT;
+
+        value = strdup(value);
+        if (!value)
+                return -ENOMEM;
+
+        *ret = value;
+
+        return 0;
+}
+
+int readlink_and_make_absolute(const char *p, char **r) {
+        _cleanup_free_ char *target = NULL;
+        char *k;
+        int j;
+
+        assert(p);
+        assert(r);
+
+        j = readlink_malloc(p, &target);
+        if (j < 0)
+                return j;
+
+        k = file_in_same_dir(p, target);
+        if (!k)
+                return -ENOMEM;
+
+        *r = k;
+        return 0;
+}
+
+int readlink_and_canonicalize(const char *p, char **r) {
+        char *t, *s;
+        int j;
+
+        assert(p);
+        assert(r);
+
+        j = readlink_and_make_absolute(p, &t);
+        if (j < 0)
+                return j;
+
+        s = canonicalize_file_name(t);
+        if (s) {
+                free(t);
+                *r = s;
+        } else
+                *r = t;
+
+        path_kill_slashes(*r);
+
+        return 0;
+}
+
+int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) {
+        _cleanup_free_ char *target = NULL, *t = NULL;
+        const char *full;
+        int r;
+
+        full = prefix_roota(root, path);
+        r = readlink_malloc(full, &target);
+        if (r < 0)
+                return r;
+
+        t = file_in_same_dir(path, target);
+        if (!t)
+                return -ENOMEM;
+
+        *ret = t;
+        t = NULL;
+
+        return 0;
+}
+
+int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+        assert(path);
+
+        /* Under the assumption that we are running privileged we
+         * first change the access mode and only then hand out
+         * ownership to avoid a window where access is too open. */
+
+        if (mode != MODE_INVALID)
+                if (chmod(path, mode) < 0)
+                        return -errno;
+
+        if (uid != UID_INVALID || gid != GID_INVALID)
+                if (chown(path, uid, gid) < 0)
+                        return -errno;
+
+        return 0;
+}
+
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+        assert(fd >= 0);
+
+        /* Under the assumption that we are running privileged we
+         * first change the access mode and only then hand out
+         * ownership to avoid a window where access is too open. */
+
+        if (mode != MODE_INVALID)
+                if (fchmod(fd, mode) < 0)
+                        return -errno;
+
+        if (uid != UID_INVALID || gid != GID_INVALID)
+                if (fchown(fd, uid, gid) < 0)
+                        return -errno;
+
+        return 0;
+}
+
+int fchmod_umask(int fd, mode_t m) {
+        mode_t u;
+        int r;
+
+        u = umask(0777);
+        r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
+        umask(u);
+
+        return r;
+}
+
+int fd_warn_permissions(const char *path, int fd) {
+        struct stat st;
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (st.st_mode & 0111)
+                log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
+
+        if (st.st_mode & 0002)
+                log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
+
+        if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+                log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
+
+        return 0;
+}
+
+int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
+        _cleanup_close_ int fd;
+        int r;
+
+        assert(path);
+
+        if (parents)
+                mkdir_parents(path, 0755);
+
+        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
+        if (fd < 0)
+                return -errno;
+
+        if (mode != MODE_INVALID) {
+                r = fchmod(fd, mode);
+                if (r < 0)
+                        return -errno;
+        }
+
+        if (uid != UID_INVALID || gid != GID_INVALID) {
+                r = fchown(fd, uid, gid);
+                if (r < 0)
+                        return -errno;
+        }
+
+        if (stamp != USEC_INFINITY) {
+                struct timespec ts[2];
+
+                timespec_store(&ts[0], stamp);
+                ts[1] = ts[0];
+                r = futimens(fd, ts);
+        } else
+                r = futimens(fd, NULL);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int touch(const char *path) {
+        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
+}
+
+int symlink_idempotent(const char *from, const char *to) {
+        _cleanup_free_ char *p = NULL;
+        int r;
+
+        assert(from);
+        assert(to);
+
+        if (symlink(from, to) < 0) {
+                if (errno != EEXIST)
+                        return -errno;
+
+                r = readlink_malloc(to, &p);
+                if (r < 0)
+                        return r;
+
+                if (!streq(p, from))
+                        return -EINVAL;
+        }
+
+        return 0;
+}
+
+int symlink_atomic(const char *from, const char *to) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert(from);
+        assert(to);
+
+        r = tempfn_random(to, NULL, &t);
+        if (r < 0)
+                return r;
+
+        if (symlink(from, t) < 0)
+                return -errno;
+
+        if (rename(t, to) < 0) {
+                unlink_noerrno(t);
+                return -errno;
+        }
+
+        return 0;
+}
+
+int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert(path);
+
+        r = tempfn_random(path, NULL, &t);
+        if (r < 0)
+                return r;
+
+        if (mknod(t, mode, dev) < 0)
+                return -errno;
+
+        if (rename(t, path) < 0) {
+                unlink_noerrno(t);
+                return -errno;
+        }
+
+        return 0;
+}
+
+int mkfifo_atomic(const char *path, mode_t mode) {
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        assert(path);
+
+        r = tempfn_random(path, NULL, &t);
+        if (r < 0)
+                return r;
+
+        if (mkfifo(t, mode) < 0)
+                return -errno;
+
+        if (rename(t, path) < 0) {
+                unlink_noerrno(t);
+                return -errno;
+        }
+
+        return 0;
+}
+
+int get_files_in_directory(const char *path, char ***list) {
+        _cleanup_closedir_ DIR *d = NULL;
+        size_t bufsize = 0, n = 0;
+        _cleanup_strv_free_ char **l = NULL;
+
+        assert(path);
+
+        /* Returns all files in a directory in *list, and the number
+         * of files as return value. If list is NULL returns only the
+         * number. */
+
+        d = opendir(path);
+        if (!d)
+                return -errno;
+
+        for (;;) {
+                struct dirent *de;
+
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
+                if (!de)
+                        break;
+
+                dirent_ensure_type(d, de);
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                if (list) {
+                        /* one extra slot is needed for the terminating NULL */
+                        if (!GREEDY_REALLOC(l, bufsize, n + 2))
+                                return -ENOMEM;
+
+                        l[n] = strdup(de->d_name);
+                        if (!l[n])
+                                return -ENOMEM;
+
+                        l[++n] = NULL;
+                } else
+                        n++;
+        }
+
+        if (list) {
+                *list = l;
+                l = NULL; /* avoid freeing */
+        }
+
+        return n;
+}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
new file mode 100644 (file)
index 0000000..902c7e2
--- /dev/null
@@ -0,0 +1,75 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <sys/inotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "time-util.h"
+
+int unlink_noerrno(const char *path);
+
+int rmdir_parents(const char *path, const char *stop);
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+int readlinkat_malloc(int fd, const char *p, char **ret);
+int readlink_malloc(const char *p, char **r);
+int readlink_value(const char *p, char **ret);
+int readlink_and_make_absolute(const char *p, char **r);
+int readlink_and_canonicalize(const char *p, char **r);
+int readlink_and_make_absolute_root(const char *root, const char *path, char **ret);
+
+int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
+
+int fchmod_umask(int fd, mode_t mode);
+
+int fd_warn_permissions(const char *path, int fd);
+
+#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
+
+int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
+int touch(const char *path);
+
+int symlink_idempotent(const char *from, const char *to);
+
+int symlink_atomic(const char *from, const char *to);
+int mknod_atomic(const char *path, mode_t mode, dev_t dev);
+int mkfifo_atomic(const char *path, mode_t mode);
+
+int get_files_in_directory(const char *path, char ***list);
+
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
+
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
+        for ((e) = &buffer.ev;                                \
+             (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
+             (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
+
+union inotify_event_buffer {
+        struct inotify_event ev;
+        uint8_t raw[INOTIFY_EVENT_MAX];
+};
diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c
new file mode 100644 (file)
index 0000000..0bfbcb1
--- /dev/null
@@ -0,0 +1,72 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <glob.h>
+
+#include "glob-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+
+int glob_exists(const char *path) {
+        _cleanup_globfree_ glob_t g = {};
+        int k;
+
+        assert(path);
+
+        errno = 0;
+        k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+        if (k == GLOB_NOMATCH)
+                return 0;
+        if (k == GLOB_NOSPACE)
+                return -ENOMEM;
+        if (k != 0)
+                return errno ? -errno : -EIO;
+
+        return !strv_isempty(g.gl_pathv);
+}
+
+int glob_extend(char ***strv, const char *path) {
+        _cleanup_globfree_ glob_t g = {};
+        int k;
+        char **p;
+
+        errno = 0;
+        k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+        if (k == GLOB_NOMATCH)
+                return -ENOENT;
+        if (k == GLOB_NOSPACE)
+                return -ENOMEM;
+        if (k != 0)
+                return errno ? -errno : -EIO;
+        if (strv_isempty(g.gl_pathv))
+                return -ENOENT;
+
+        STRV_FOREACH(p, g.gl_pathv) {
+                k = strv_extend(strv, *p);
+                if (k < 0)
+                        return k;
+        }
+
+        return 0;
+}
diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h
new file mode 100644 (file)
index 0000000..793adf4
--- /dev/null
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <string.h>
+
+#include "macro.h"
+#include "string-util.h"
+
+int glob_exists(const char *path);
+int glob_extend(char ***strv, const char *path);
+
+#define _cleanup_globfree_ _cleanup_(globfree)
+
+_pure_ static inline bool string_is_glob(const char *p) {
+        /* Check if a string contains any glob patterns. */
+        return !!strpbrk(p, GLOB_CHARS);
+}
index 20e7e51d9e223deebe7fe9e39a22f37c5abeba06..4109a08c6cafcc426bb4b18087122bed645481a1 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
 #include <pthread.h>
+#include <stdlib.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "hashmap.h"
-#include "set.h"
 #include "macro.h"
-#include "siphash24.h"
-#include "strv.h"
 #include "mempool.h"
+#include "process-util.h"
 #include "random-util.h"
+#include "set.h"
+#include "siphash24.h"
+#include "strv.h"
+#include "util.h"
 
 #ifdef ENABLE_DEBUG_HASHMAP
 #include "list.h"
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
new file mode 100644 (file)
index 0000000..4eb566b
--- /dev/null
@@ -0,0 +1,698 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <ctype.h>
+#include <inttypes.h>
+
+#include "alloc-util.h"
+#include "hexdecoct.h"
+#include "util.h"
+
+char octchar(int x) {
+        return '0' + (x & 7);
+}
+
+int unoctchar(char c) {
+
+        if (c >= '0' && c <= '7')
+                return c - '0';
+
+        return -EINVAL;
+}
+
+char decchar(int x) {
+        return '0' + (x % 10);
+}
+
+int undecchar(char c) {
+
+        if (c >= '0' && c <= '9')
+                return c - '0';
+
+        return -EINVAL;
+}
+
+char hexchar(int x) {
+        static const char table[16] = "0123456789abcdef";
+
+        return table[x & 15];
+}
+
+int unhexchar(char c) {
+
+        if (c >= '0' && c <= '9')
+                return c - '0';
+
+        if (c >= 'a' && c <= 'f')
+                return c - 'a' + 10;
+
+        if (c >= 'A' && c <= 'F')
+                return c - 'A' + 10;
+
+        return -EINVAL;
+}
+
+char *hexmem(const void *p, size_t l) {
+        char *r, *z;
+        const uint8_t *x;
+
+        z = r = malloc(l * 2 + 1);
+        if (!r)
+                return NULL;
+
+        for (x = p; x < (const uint8_t*) p + l; x++) {
+                *(z++) = hexchar(*x >> 4);
+                *(z++) = hexchar(*x & 15);
+        }
+
+        *z = 0;
+        return r;
+}
+
+int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
+        _cleanup_free_ uint8_t *r = NULL;
+        uint8_t *z;
+        const char *x;
+
+        assert(mem);
+        assert(len);
+        assert(p);
+
+        z = r = malloc((l + 1) / 2 + 1);
+        if (!r)
+                return -ENOMEM;
+
+        for (x = p; x < p + l; x += 2) {
+                int a, b;
+
+                a = unhexchar(x[0]);
+                if (a < 0)
+                        return a;
+                else if (x+1 < p + l) {
+                        b = unhexchar(x[1]);
+                        if (b < 0)
+                                return b;
+                } else
+                        b = 0;
+
+                *(z++) = (uint8_t) a << 4 | (uint8_t) b;
+        }
+
+        *z = 0;
+
+        *mem = r;
+        r = NULL;
+        *len = (l + 1) / 2;
+
+        return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-6
+ * Notice that base32hex differs from base32 in the alphabet it uses.
+ * The distinction is that the base32hex representation preserves the
+ * order of the underlying data when compared as bytestrings, this is
+ * useful when representing NSEC3 hashes, as one can then verify the
+ * order of hashes directly from their representation. */
+char base32hexchar(int x) {
+        static const char table[32] = "0123456789"
+                                      "ABCDEFGHIJKLMNOPQRSTUV";
+
+        return table[x & 31];
+}
+
+int unbase32hexchar(char c) {
+        unsigned offset;
+
+        if (c >= '0' && c <= '9')
+                return c - '0';
+
+        offset = '9' - '0' + 1;
+
+        if (c >= 'A' && c <= 'V')
+                return c - 'A' + offset;
+
+        return -EINVAL;
+}
+
+char *base32hexmem(const void *p, size_t l, bool padding) {
+        char *r, *z;
+        const uint8_t *x;
+        size_t len;
+
+        if (padding)
+                /* five input bytes makes eight output bytes, padding is added so we must round up */
+                len = 8 * (l + 4) / 5;
+        else {
+                /* same, but round down as there is no padding */
+                len = 8 * l / 5;
+
+                switch (l % 5) {
+                case 4:
+                        len += 7;
+                        break;
+                case 3:
+                        len += 5;
+                        break;
+                case 2:
+                        len += 4;
+                        break;
+                case 1:
+                        len += 2;
+                        break;
+                }
+        }
+
+        z = r = malloc(len + 1);
+        if (!r)
+                return NULL;
+
+        for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
+                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
+                   x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
+                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
+                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
+                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
+                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
+                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
+                *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
+                *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
+        }
+
+        switch (l % 5) {
+        case 4:
+                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
+                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
+                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
+                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
+                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
+                *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
+                if (padding)
+                        *(z++) = '=';
+
+                break;
+
+        case 3:
+                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
+                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
+                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+                *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
+                if (padding) {
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                }
+
+                break;
+
+        case 2:
+                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
+                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
+                *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
+                if (padding) {
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                }
+
+                break;
+
+        case 1:
+                *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
+                *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
+                if (padding) {
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                        *(z++) = '=';
+                }
+
+                break;
+        }
+
+        *z = 0;
+        return r;
+}
+
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
+        _cleanup_free_ uint8_t *r = NULL;
+        int a, b, c, d, e, f, g, h;
+        uint8_t *z;
+        const char *x;
+        size_t len;
+        unsigned pad = 0;
+
+        assert(p);
+
+        /* padding ensures any base32hex input has input divisible by 8 */
+        if (padding && l % 8 != 0)
+                return -EINVAL;
+
+        if (padding) {
+                /* strip the padding */
+                while (l > 0 && p[l - 1] == '=' && pad < 7) {
+                        pad ++;
+                        l --;
+                }
+        }
+
+        /* a group of eight input bytes needs five output bytes, in case of
+           padding we need to add some extra bytes */
+        len = (l / 8) * 5;
+
+        switch (l % 8) {
+        case 7:
+                len += 4;
+                break;
+        case 5:
+                len += 3;
+                break;
+        case 4:
+                len += 2;
+                break;
+        case 2:
+                len += 1;
+                break;
+        case 0:
+                break;
+        default:
+                return -EINVAL;
+        }
+
+        z = r = malloc(len + 1);
+        if (!r)
+                return -ENOMEM;
+
+        for (x = p; x < p + (l / 8) * 8; x += 8) {
+                /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
+                   e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
+                a = unbase32hexchar(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase32hexchar(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase32hexchar(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase32hexchar(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                e = unbase32hexchar(x[4]);
+                if (e < 0)
+                        return -EINVAL;
+
+                f = unbase32hexchar(x[5]);
+                if (f < 0)
+                        return -EINVAL;
+
+                g = unbase32hexchar(x[6]);
+                if (g < 0)
+                        return -EINVAL;
+
+                h = unbase32hexchar(x[7]);
+                if (h < 0)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
+                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
+                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+                *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
+        }
+
+        switch (l % 8) {
+        case 7:
+                a = unbase32hexchar(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase32hexchar(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase32hexchar(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase32hexchar(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                e = unbase32hexchar(x[4]);
+                if (e < 0)
+                        return -EINVAL;
+
+                f = unbase32hexchar(x[5]);
+                if (f < 0)
+                        return -EINVAL;
+
+                g = unbase32hexchar(x[6]);
+                if (g < 0)
+                        return -EINVAL;
+
+                /* g == 000VV000 */
+                if (g & 7)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
+                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
+                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+
+                break;
+        case 5:
+                a = unbase32hexchar(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase32hexchar(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase32hexchar(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase32hexchar(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                e = unbase32hexchar(x[4]);
+                if (e < 0)
+                        return -EINVAL;
+
+                /* e == 000SSSS0 */
+                if (e & 1)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
+                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
+
+                break;
+        case 4:
+                a = unbase32hexchar(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase32hexchar(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase32hexchar(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase32hexchar(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                /* d == 000W0000 */
+                if (d & 15)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
+                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+
+                break;
+        case 2:
+                a = unbase32hexchar(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase32hexchar(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                /* b == 000YYY00 */
+                if (b & 3)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+
+                break;
+        case 0:
+                break;
+        default:
+                return -EINVAL;
+        }
+
+        *z = 0;
+
+        *mem = r;
+        r = NULL;
+        *_len = len;
+
+        return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-4 */
+char base64char(int x) {
+        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                      "abcdefghijklmnopqrstuvwxyz"
+                                      "0123456789+/";
+        return table[x & 63];
+}
+
+int unbase64char(char c) {
+        unsigned offset;
+
+        if (c >= 'A' && c <= 'Z')
+                return c - 'A';
+
+        offset = 'Z' - 'A' + 1;
+
+        if (c >= 'a' && c <= 'z')
+                return c - 'a' + offset;
+
+        offset += 'z' - 'a' + 1;
+
+        if (c >= '0' && c <= '9')
+                return c - '0' + offset;
+
+        offset += '9' - '0' + 1;
+
+        if (c == '+')
+                return offset;
+
+        offset ++;
+
+        if (c == '/')
+                return offset;
+
+        return -EINVAL;
+}
+
+char *base64mem(const void *p, size_t l) {
+        char *r, *z;
+        const uint8_t *x;
+
+        /* three input bytes makes four output bytes, padding is added so we must round up */
+        z = r = malloc(4 * (l + 2) / 3 + 1);
+        if (!r)
+                return NULL;
+
+        for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
+                *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
+                *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
+                *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
+        }
+
+        switch (l % 3) {
+        case 2:
+                *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+                *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
+                *(z++) = '=';
+
+                break;
+        case 1:
+                *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
+                *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
+                *(z++) = '=';
+                *(z++) = '=';
+
+                break;
+        }
+
+        *z = 0;
+        return r;
+}
+
+int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
+        _cleanup_free_ uint8_t *r = NULL;
+        int a, b, c, d;
+        uint8_t *z;
+        const char *x;
+        size_t len;
+
+        assert(p);
+
+        /* padding ensures any base63 input has input divisible by 4 */
+        if (l % 4 != 0)
+                return -EINVAL;
+
+        /* strip the padding */
+        if (l > 0 && p[l - 1] == '=')
+                l --;
+        if (l > 0 && p[l - 1] == '=')
+                l --;
+
+        /* a group of four input bytes needs three output bytes, in case of
+           padding we need to add two or three extra bytes */
+        len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+
+        z = r = malloc(len + 1);
+        if (!r)
+                return -ENOMEM;
+
+        for (x = p; x < p + (l / 4) * 4; x += 4) {
+                /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase64char(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                d = unbase64char(x[3]);
+                if (d < 0)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
+        }
+
+        switch (l % 4) {
+        case 3:
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                c = unbase64char(x[2]);
+                if (c < 0)
+                        return -EINVAL;
+
+                /* c == 00ZZZZ00 */
+                if (c & 3)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+
+                break;
+        case 2:
+                a = unbase64char(x[0]);
+                if (a < 0)
+                        return -EINVAL;
+
+                b = unbase64char(x[1]);
+                if (b < 0)
+                        return -EINVAL;
+
+                /* b == 00YY0000 */
+                if (b & 15)
+                        return -EINVAL;
+
+                *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+
+                break;
+        case 0:
+
+                break;
+        default:
+                return -EINVAL;
+        }
+
+        *z = 0;
+
+        *mem = r;
+        r = NULL;
+        *_len = len;
+
+        return 0;
+}
+
+void hexdump(FILE *f, const void *p, size_t s) {
+        const uint8_t *b = p;
+        unsigned n = 0;
+
+        assert(s == 0 || b);
+
+        while (s > 0) {
+                size_t i;
+
+                fprintf(f, "%04x  ", n);
+
+                for (i = 0; i < 16; i++) {
+
+                        if (i >= s)
+                                fputs("   ", f);
+                        else
+                                fprintf(f, "%02x ", b[i]);
+
+                        if (i == 7)
+                                fputc(' ', f);
+                }
+
+                fputc(' ', f);
+
+                for (i = 0; i < 16; i++) {
+
+                        if (i >= s)
+                                fputc(' ', f);
+                        else
+                                fputc(isprint(b[i]) ? (char) b[i] : '.', f);
+                }
+
+                fputc('\n', f);
+
+                if (s < 16)
+                        break;
+
+                n += 16;
+                b += 16;
+                s -= 16;
+        }
+}
diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h
new file mode 100644 (file)
index 0000000..4aeb4c3
--- /dev/null
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+char octchar(int x) _const_;
+int unoctchar(char c) _const_;
+
+char decchar(int x) _const_;
+int undecchar(char c) _const_;
+
+char hexchar(int x) _const_;
+int unhexchar(char c) _const_;
+
+char *hexmem(const void *p, size_t l);
+int unhexmem(const char *p, size_t l, void **mem, size_t *len);
+
+char base32hexchar(int x) _const_;
+int unbase32hexchar(char c) _const_;
+
+char base64char(int x) _const_;
+int unbase64char(char c) _const_;
+
+char *base32hexmem(const void *p, size_t l, bool padding);
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
+
+char *base64mem(const void *p, size_t l);
+int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
+
+void hexdump(FILE *f, const void *p, size_t s);
index 1b816fb77af6823d4febde3a2480952ca910e3f1..ea0528c6fcbd19dafbfcdd7d1b687151366c2199 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/utsname.h>
 #include <ctype.h>
+#include <sys/utsname.h>
 
-#include "util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "hostname-util.h"
+#include "string-util.h"
+#include "util.h"
 
 bool hostname_is_set(void) {
         struct utsname u;
index d88864b5987f7387ebd99e2ea9a689d05038c478..f4e24121e7b80b8a0c49e1df2f81a2f45ea9dcc7 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <arpa/inet.h>
 
+#include "alloc-util.h"
 #include "in-addr-util.h"
 
 int in_addr_is_null(int family, const union in_addr_union *u) {
diff --git a/src/basic/io-util.c b/src/basic/io-util.c
new file mode 100644 (file)
index 0000000..ac8f93f
--- /dev/null
@@ -0,0 +1,261 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <poll.h>
+#include <unistd.h>
+
+#include "io-util.h"
+
+int flush_fd(int fd) {
+        struct pollfd pollfd = {
+                .fd = fd,
+                .events = POLLIN,
+        };
+
+        for (;;) {
+                char buf[LINE_MAX];
+                ssize_t l;
+                int r;
+
+                r = poll(&pollfd, 1, 0);
+                if (r < 0) {
+                        if (errno == EINTR)
+                                continue;
+
+                        return -errno;
+
+                } else if (r == 0)
+                        return 0;
+
+                l = read(fd, buf, sizeof(buf));
+                if (l < 0) {
+
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN)
+                                return 0;
+
+                        return -errno;
+                } else if (l == 0)
+                        return 0;
+        }
+}
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
+        uint8_t *p = buf;
+        ssize_t n = 0;
+
+        assert(fd >= 0);
+        assert(buf);
+
+        /* If called with nbytes == 0, let's call read() at least
+         * once, to validate the operation */
+
+        if (nbytes > (size_t) SSIZE_MAX)
+                return -EINVAL;
+
+        do {
+                ssize_t k;
+
+                k = read(fd, p, nbytes);
+                if (k < 0) {
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN && do_poll) {
+
+                                /* We knowingly ignore any return value here,
+                                 * and expect that any error/EOF is reported
+                                 * via read() */
+
+                                (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+                                continue;
+                        }
+
+                        return n > 0 ? n : -errno;
+                }
+
+                if (k == 0)
+                        return n;
+
+                assert((size_t) k <= nbytes);
+
+                p += k;
+                nbytes -= k;
+                n += k;
+        } while (nbytes > 0);
+
+        return n;
+}
+
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
+        ssize_t n;
+
+        n = loop_read(fd, buf, nbytes, do_poll);
+        if (n < 0)
+                return (int) n;
+        if ((size_t) n != nbytes)
+                return -EIO;
+
+        return 0;
+}
+
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
+        const uint8_t *p = buf;
+
+        assert(fd >= 0);
+        assert(buf);
+
+        if (nbytes > (size_t) SSIZE_MAX)
+                return -EINVAL;
+
+        do {
+                ssize_t k;
+
+                k = write(fd, p, nbytes);
+                if (k < 0) {
+                        if (errno == EINTR)
+                                continue;
+
+                        if (errno == EAGAIN && do_poll) {
+                                /* We knowingly ignore any return value here,
+                                 * and expect that any error/EOF is reported
+                                 * via write() */
+
+                                (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
+                                continue;
+                        }
+
+                        return -errno;
+                }
+
+                if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
+                        return -EIO;
+
+                assert((size_t) k <= nbytes);
+
+                p += k;
+                nbytes -= k;
+        } while (nbytes > 0);
+
+        return 0;
+}
+
+int pipe_eof(int fd) {
+        struct pollfd pollfd = {
+                .fd = fd,
+                .events = POLLIN|POLLHUP,
+        };
+
+        int r;
+
+        r = poll(&pollfd, 1, 0);
+        if (r < 0)
+                return -errno;
+
+        if (r == 0)
+                return 0;
+
+        return pollfd.revents & POLLHUP;
+}
+
+int fd_wait_for_event(int fd, int event, usec_t t) {
+
+        struct pollfd pollfd = {
+                .fd = fd,
+                .events = event,
+        };
+
+        struct timespec ts;
+        int r;
+
+        r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
+        if (r < 0)
+                return -errno;
+
+        if (r == 0)
+                return 0;
+
+        return pollfd.revents;
+}
+
+static size_t nul_length(const uint8_t *p, size_t sz) {
+        size_t n = 0;
+
+        while (sz > 0) {
+                if (*p != 0)
+                        break;
+
+                n++;
+                p++;
+                sz--;
+        }
+
+        return n;
+}
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
+        const uint8_t *q, *w, *e;
+        ssize_t l;
+
+        q = w = p;
+        e = q + sz;
+        while (q < e) {
+                size_t n;
+
+                n = nul_length(q, e - q);
+
+                /* If there are more than the specified run length of
+                 * NUL bytes, or if this is the beginning or the end
+                 * of the buffer, then seek instead of write */
+                if ((n > run_length) ||
+                    (n > 0 && q == p) ||
+                    (n > 0 && q + n >= e)) {
+                        if (q > w) {
+                                l = write(fd, w, q - w);
+                                if (l < 0)
+                                        return -errno;
+                                if (l != q -w)
+                                        return -EIO;
+                        }
+
+                        if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
+                                return -errno;
+
+                        q += n;
+                        w = q;
+                } else if (n > 0)
+                        q += n;
+                else
+                        q ++;
+        }
+
+        if (q > w) {
+                l = write(fd, w, q - w);
+                if (l < 0)
+                        return -errno;
+                if (l != q - w)
+                        return -EIO;
+        }
+
+        return q - (const uint8_t*) p;
+}
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
new file mode 100644 (file)
index 0000000..cd2aa75
--- /dev/null
@@ -0,0 +1,76 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include "time-util.h"
+
+int flush_fd(int fd);
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
+
+int pipe_eof(int fd);
+
+int fd_wait_for_event(int fd, int event, usec_t timeout);
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
+
+#define IOVEC_SET_STRING(i, s)                  \
+        do {                                    \
+                struct iovec *_i = &(i);        \
+                char *_s = (char *)(s);         \
+                _i->iov_base = _s;              \
+                _i->iov_len = strlen(_s);       \
+        } while(false)
+
+static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
+        unsigned j;
+        size_t r = 0;
+
+        for (j = 0; j < n; j++)
+                r += i[j].iov_len;
+
+        return r;
+}
+
+static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
+        unsigned j;
+
+        for (j = 0; j < n; j++) {
+                size_t sub;
+
+                if (_unlikely_(k <= 0))
+                        break;
+
+                sub = MIN(i[j].iov_len, k);
+                i[j].iov_len -= sub;
+                i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
+                k -= sub;
+        }
+
+        return k;
+}
index be40a0d203d9e76d771acc63e2270ed0bc7410b1..716705e5ff52a047549ce3d2c5a21df8508126d1 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/types.h>
 #include <math.h>
+#include <sys/types.h>
+
+#include "alloc-util.h"
+#include "json.h"
 #include "macro.h"
+#include "hexdecoct.h"
+#include "string-util.h"
 #include "utf8.h"
-#include "json.h"
 
 int json_variant_new(JsonVariant **ret, JsonVariantType type) {
         JsonVariant *v;
index 61db9a8125d1a77c4072ea4efa569bd192075d42..b87fd7670bf410a58aa1bff5a2805821e37e1026 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <langinfo.h>
+#include <locale.h>
 #include <sys/mman.h>
 
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "locale-util.h"
+#include "path-util.h"
 #include "set.h"
-#include "util.h"
-#include "utf8.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
-
-#include "locale-util.h"
+#include "utf8.h"
+#include "util.h"
 
 static int add_locales_from_archive(Set *locales) {
         /* Stolen from glibc... */
@@ -204,6 +210,88 @@ bool locale_is_valid(const char *name) {
         return true;
 }
 
+void init_gettext(void) {
+        setlocale(LC_ALL, "");
+        textdomain(GETTEXT_PACKAGE);
+}
+
+bool is_locale_utf8(void) {
+        const char *set;
+        static int cached_answer = -1;
+
+        /* Note that we default to 'true' here, since today UTF8 is
+         * pretty much supported everywhere. */
+
+        if (cached_answer >= 0)
+                goto out;
+
+        if (!setlocale(LC_ALL, "")) {
+                cached_answer = true;
+                goto out;
+        }
+
+        set = nl_langinfo(CODESET);
+        if (!set) {
+                cached_answer = true;
+                goto out;
+        }
+
+        if (streq(set, "UTF-8")) {
+                cached_answer = true;
+                goto out;
+        }
+
+        /* For LC_CTYPE=="C" return true, because CTYPE is effectly
+         * unset and everything can do to UTF-8 nowadays. */
+        set = setlocale(LC_CTYPE, NULL);
+        if (!set) {
+                cached_answer = true;
+                goto out;
+        }
+
+        /* Check result, but ignore the result if C was set
+         * explicitly. */
+        cached_answer =
+                STR_IN_SET(set, "C", "POSIX") &&
+                !getenv("LC_ALL") &&
+                !getenv("LC_CTYPE") &&
+                !getenv("LANG");
+
+out:
+        return (bool) cached_answer;
+}
+
+
+const char *draw_special_char(DrawSpecialChar ch) {
+
+        static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
+
+                /* UTF-8 */ {
+                        [DRAW_TREE_VERTICAL]      = "\342\224\202 ",            /* │  */
+                        [DRAW_TREE_BRANCH]        = "\342\224\234\342\224\200", /* ├─ */
+                        [DRAW_TREE_RIGHT]         = "\342\224\224\342\224\200", /* └─ */
+                        [DRAW_TREE_SPACE]         = "  ",                       /*    */
+                        [DRAW_TRIANGULAR_BULLET]  = "\342\200\243",             /* ‣ */
+                        [DRAW_BLACK_CIRCLE]       = "\342\227\217",             /* ● */
+                        [DRAW_ARROW]              = "\342\206\222",             /* → */
+                        [DRAW_DASH]               = "\342\200\223",             /* – */
+                },
+
+                /* ASCII fallback */ {
+                        [DRAW_TREE_VERTICAL]      = "| ",
+                        [DRAW_TREE_BRANCH]        = "|-",
+                        [DRAW_TREE_RIGHT]         = "`-",
+                        [DRAW_TREE_SPACE]         = "  ",
+                        [DRAW_TRIANGULAR_BULLET]  = ">",
+                        [DRAW_BLACK_CIRCLE]       = "*",
+                        [DRAW_ARROW]              = "->",
+                        [DRAW_DASH]               = "-",
+                }
+        };
+
+        return draw_table[!is_locale_utf8()][ch];
+}
+
 static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
         [VARIABLE_LANG] = "LANG",
         [VARIABLE_LANGUAGE] = "LANGUAGE",
index e48aa3d9af04c1c13cba5e849f45bc7afd3d6fad..c71d145139d06fc75866cd7179e3c983bb38b100 100644 (file)
@@ -21,6 +21,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <libintl.h>
 #include <stdbool.h>
 
 #include "macro.h"
@@ -50,5 +51,25 @@ typedef enum LocaleVariable {
 int get_locales(char ***l);
 bool locale_is_valid(const char *name);
 
+#define _(String) gettext(String)
+#define N_(String) String
+void init_gettext(void);
+
+bool is_locale_utf8(void);
+
+typedef enum DrawSpecialChar {
+        DRAW_TREE_VERTICAL,
+        DRAW_TREE_BRANCH,
+        DRAW_TREE_RIGHT,
+        DRAW_TREE_SPACE,
+        DRAW_TRIANGULAR_BULLET,
+        DRAW_BLACK_CIRCLE,
+        DRAW_ARROW,
+        DRAW_DASH,
+        _DRAW_SPECIAL_CHAR_MAX
+} DrawSpecialChar;
+
+const char *draw_special_char(DrawSpecialChar ch);
+
 const char* locale_variable_to_string(LocaleVariable i) _const_;
 LocaleVariable locale_variable_from_string(const char *s) _pure_;
index f3ec6a3e5243431988ee37ac356ba71e1b7ac3d5..87c3aef7afebb52c1885b10e493af1f2c3b1a095 100644 (file)
 #include <limits.h>
 #include <sys/file.h>
 
-#include "util.h"
-#include "lockfile-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
+#include "lockfile-util.h"
+#include "path-util.h"
+#include "util.h"
 
 int make_lock_file(const char *p, int operation, LockFile *ret) {
         _cleanup_close_ int fd = -1;
index e6d7d151820e8d05a8e11d44eb8ef3b0e52e4d71..fe29cacd9e3e6a0498aabd1279cc2659464bf26d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdarg.h>
-#include <stdio.h>
 #include <errno.h>
-#include <unistd.h>
 #include <fcntl.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <stddef.h>
-#include <printf.h>
+#include <unistd.h>
 
 #include "sd-messages.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
 #include "log.h"
-#include "util.h"
-#include "missing.h"
 #include "macro.h"
-#include "socket-util.h"
-#include "formats-util.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
 #include "process-util.h"
-#include "terminal-util.h"
 #include "signal-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
@@ -435,7 +445,7 @@ static int write_to_syslog(
 static int write_to_kmsg(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *object_field,
@@ -506,7 +516,7 @@ static int log_do_header(
 static int write_to_journal(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *object_field,
@@ -640,7 +650,7 @@ int log_dump_internal(
 int log_internalv(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *format,
@@ -667,7 +677,7 @@ int log_internalv(
 int log_internal(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *format, ...) {
@@ -685,7 +695,7 @@ int log_internal(
 int log_object_internalv(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *object_field,
@@ -729,7 +739,7 @@ int log_object_internalv(
 int log_object_internal(
                 int level,
                 int error,
-                const char*file,
+                const char *file,
                 int line,
                 const char *func,
                 const char *object_field,
index 369d6b1127c9d3f7c6d7d5fc08a47fcdca3140f0..cda1e45cc8d3cd491459def4795292c491e1f0e5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
+#include <errno.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdlib.h>
-#include <syslog.h>
 #include <sys/signalfd.h>
-#include <errno.h>
+#include <syslog.h>
 
 #include "sd-id128.h"
+
 #include "macro.h"
 
 typedef enum LogTarget{
index e25437f0f4661b1853af68fc8c33a87776dc5d36..832f477bd2bb842781ef6d2b55eb2f013dfaf6a8 100644 (file)
@@ -19,8 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "login-util.h"
 #include "def.h"
+#include "string-util.h"
+#include "login-util.h"
 
 bool session_id_valid(const char *id) {
 
index a79f20c1b1e6b1a3f507de8125effeae0ae4e748..be5bb648700febd04d84c4ceac281691ff299389 100644 (file)
 #pragma once
 
 #include <stdbool.h>
+#include <unistd.h>
 
 bool session_id_valid(const char *id);
+
+static inline bool logind_running(void) {
+        return access("/run/systemd/seats/", F_OK) >= 0;
+}
index f55d65e2f1545cb4ebe0e0901096dfe04fb4e1b5..5088e6720d8640e8e13c1d58e7c74a1da7ff9423 100644 (file)
 ***/
 
 #include <assert.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/uio.h>
 #include <inttypes.h>
 #include <stdbool.h>
+#include <sys/param.h>
+#include <sys/types.h>
 
 #define _printf_(a,b) __attribute__ ((format (printf, a, b)))
 #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -295,111 +294,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
 #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
 #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
 
-/* The following macros add 1 when converting things, since UID 0 is a
- * valid UID, while the pointer NULL is special */
-#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
-#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
-
-#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
-#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
-
-#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
-#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
-
-#define memzero(x,l) (memset((x), 0, (l)))
-#define zero(x) (memzero(&(x), sizeof(x)))
-
 #define CHAR_TO_STR(x) ((char[2]) { x, 0 })
 
 #define char_array_0(x) x[sizeof(x)-1] = 0;
 
-#define IOVEC_SET_STRING(i, s)                  \
-        do {                                    \
-                struct iovec *_i = &(i);        \
-                char *_s = (char *)(s);         \
-                _i->iov_base = _s;              \
-                _i->iov_len = strlen(_s);       \
-        } while(false)
-
-static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
-        unsigned j;
-        size_t r = 0;
-
-        for (j = 0; j < n; j++)
-                r += i[j].iov_len;
-
-        return r;
-}
-
-static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
-        unsigned j;
-
-        for (j = 0; j < n; j++) {
-                size_t sub;
-
-                if (_unlikely_(k <= 0))
-                        break;
-
-                sub = MIN(i[j].iov_len, k);
-                i[j].iov_len -= sub;
-                i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
-                k -= sub;
-        }
-
-        return k;
-}
-
-#define VA_FORMAT_ADVANCE(format, ap)                                   \
-do {                                                                    \
-        int _argtypes[128];                                             \
-        size_t _i, _k;                                                  \
-        _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
-        assert(_k < ELEMENTSOF(_argtypes));                             \
-        for (_i = 0; _i < _k; _i++) {                                   \
-                if (_argtypes[_i] & PA_FLAG_PTR)  {                     \
-                        (void) va_arg(ap, void*);                       \
-                        continue;                                       \
-                }                                                       \
-                                                                        \
-                switch (_argtypes[_i]) {                                \
-                case PA_INT:                                            \
-                case PA_INT|PA_FLAG_SHORT:                              \
-                case PA_CHAR:                                           \
-                        (void) va_arg(ap, int);                         \
-                        break;                                          \
-                case PA_INT|PA_FLAG_LONG:                               \
-                        (void) va_arg(ap, long int);                    \
-                        break;                                          \
-                case PA_INT|PA_FLAG_LONG_LONG:                          \
-                        (void) va_arg(ap, long long int);               \
-                        break;                                          \
-                case PA_WCHAR:                                          \
-                        (void) va_arg(ap, wchar_t);                     \
-                        break;                                          \
-                case PA_WSTRING:                                        \
-                case PA_STRING:                                         \
-                case PA_POINTER:                                        \
-                        (void) va_arg(ap, void*);                       \
-                        break;                                          \
-                case PA_FLOAT:                                          \
-                case PA_DOUBLE:                                         \
-                        (void) va_arg(ap, double);                      \
-                        break;                                          \
-                case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:                     \
-                        (void) va_arg(ap, long double);                 \
-                        break;                                          \
-                default:                                                \
-                        assert_not_reached("Unknown format string argument."); \
-                }                                                       \
-        }                                                               \
-} while(false)
-
- /* Because statfs.t_type can be int on some architectures, we have to cast
-  * the const magic to the type, otherwise the compiler warns about
-  * signed/unsigned comparison, because the magic can be 32 bit unsigned.
- */
-#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
-
 /* Returns the number of chars needed to format variables of the
  * specified type as a decimal string. Adds in extra space for a
  * negative '-' prefix (hence works correctly on signed
@@ -410,6 +308,15 @@ do {                                                                    \
             sizeof(type) <= 4 ? 10 :                                    \
             sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
 
+#define DECIMAL_STR_WIDTH(x)                            \
+        ({                                              \
+                typeof(x) _x_ = (x);                    \
+                unsigned ans = 1;                       \
+                while (_x_ /= 10)                       \
+                        ans++;                          \
+                ans;                                    \
+        })
+
 #define SET_FLAG(v, flag, b) \
         (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
 
@@ -427,21 +334,6 @@ do {                                                                    \
                 _found;                                                 \
         })
 
-/* Return a nulstr for a standard cascade of configuration directories,
- * suitable to pass to conf_files_list_nulstr or config_parse_many. */
-#define CONF_DIRS_NULSTR(n) \
-        "/etc/" n ".d\0" \
-        "/run/" n ".d\0" \
-        "/usr/local/lib/" n ".d\0" \
-        "/usr/lib/" n ".d\0" \
-        CONF_DIR_SPLIT_USR(n)
-
-#ifdef HAVE_SPLIT_USR
-#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
-#else
-#define CONF_DIR_SPLIT_USR(n)
-#endif
-
 /* Define C11 thread_local attribute even on older gcc compiler
  * version */
 #ifndef thread_local
@@ -466,10 +358,6 @@ do {                                                                    \
 #endif
 #endif
 
-#define UID_INVALID ((uid_t) -1)
-#define GID_INVALID ((gid_t) -1)
-#define MODE_INVALID ((mode_t) -1)
-
 #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)                 \
         static inline void func##p(type *p) {                   \
                 if (*p)                                         \
@@ -477,7 +365,4 @@ do {                                                                    \
         }                                                       \
         struct __useless_struct_to_allow_trailing_semicolon__
 
-#define CMSG_FOREACH(cmsg, mh)                                          \
-        for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
-
 #include "log.h"
index e99a738e1f88a79af71c8ad899c556da5fdd2b9c..92630f6b2591b5e226599f73f35270ef7184bd31 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-
 #ifdef HAVE_LINUX_MEMFD_H
-#  include <linux/memfd.h>
+#include <linux/memfd.h>
 #endif
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "memfd-util.h"
-#include "utf8.h"
 #include "missing.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
 
 int memfd_new(const char *name) {
         _cleanup_free_ char *g = NULL;
index 3ed551fb372874971d7815f8505cc23e76877527..2cb404ea811099f1cdc05b5d15be44a8032aecac 100644 (file)
@@ -21,7 +21,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
+#include <sys/types.h>
+#include <inttypes.h>
 
 int memfd_new(const char *name);
 int memfd_new_and_map(const char *name, size_t sz, void **p);
index 59e835a4664b84b61392710ac2a1308d512cc335..d539ed00e4065e576ac67bc565df97c064580013 100644 (file)
 
 /* Missing glibc definitions to access certain kernel APIs */
 
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
 #include <errno.h>
-#include <linux/oom.h>
-#include <linux/input.h>
-#include <linux/if_link.h>
-#include <linux/loop.h>
+#include <fcntl.h>
 #include <linux/audit.h>
 #include <linux/capability.h>
+#include <linux/if_link.h>
+#include <linux/input.h>
+#include <linux/loop.h>
 #include <linux/neighbour.h>
+#include <linux/oom.h>
+#include <linux/rtnetlink.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <unistd.h>
 
 #ifdef HAVE_AUDIT
 #include <libaudit.h>
 #define SOL_NETLINK 270
 #endif
 
+#ifndef NETLINK_LIST_MEMBERSHIPS
+#define NETLINK_LIST_MEMBERSHIPS 9
+#endif
+
 #if !HAVE_DECL_PIVOT_ROOT
 static inline int pivot_root(const char *new_root, const char *put_old) {
         return syscall(SYS_pivot_root, new_root, put_old);
@@ -248,6 +253,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
 #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
 #endif
 
+#ifndef BTRFS_QGROUP_LEVEL_SHIFT
+#define BTRFS_QGROUP_LEVEL_SHIFT 48
+#endif
+
 #ifndef HAVE_LINUX_BTRFS_H
 struct btrfs_ioctl_vol_args {
         int64_t fd;
@@ -486,6 +495,10 @@ struct btrfs_ioctl_quota_ctl_args {
 #define BTRFS_QGROUP_LIMIT_KEY 244
 #endif
 
+#ifndef BTRFS_QGROUP_RELATION_KEY
+#define BTRFS_QGROUP_RELATION_KEY 246
+#endif
+
 #ifndef BTRFS_ROOT_BACKREF_KEY
 #define BTRFS_ROOT_BACKREF_KEY 144
 #endif
@@ -888,6 +901,10 @@ static inline int setns(int fd, int nstype) {
 #define NDA_MAX (__NDA_MAX - 1)
 #endif
 
+#ifndef RTA_PREF
+#define RTA_PREF 20
+#endif
+
 #ifndef IPV6_UNICAST_IF
 #define IPV6_UNICAST_IF 76
 #endif
index 7ee4546988b353aef2f1fb4f95dcda635e49bdf1..0214c4627ef1e0d16564b9da38b0b82af5ddf29c 100644 (file)
 #include <string.h>
 #include <errno.h>
 
-#include "util.h"
-#include "path-util.h"
+#include "fs-util.h"
 #include "mkdir.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "user-util.h"
+#include "util.h"
 
 int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
         struct stat st;
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
new file mode 100644 (file)
index 0000000..29997b1
--- /dev/null
@@ -0,0 +1,529 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <string.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "util.h"
+
+static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
+        char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+        _cleanup_free_ char *fdinfo = NULL;
+        _cleanup_close_ int subfd = -1;
+        char *p;
+        int r;
+
+        if ((flags & AT_EMPTY_PATH) && isempty(filename))
+                xsprintf(path, "/proc/self/fdinfo/%i", fd);
+        else {
+                subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
+                if (subfd < 0)
+                        return -errno;
+
+                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
+        }
+
+        r = read_full_file(path, &fdinfo, NULL);
+        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
+                return -EOPNOTSUPP;
+        if (r < 0)
+                return -errno;
+
+        p = startswith(fdinfo, "mnt_id:");
+        if (!p) {
+                p = strstr(fdinfo, "\nmnt_id:");
+                if (!p) /* The mnt_id field is a relatively new addition */
+                        return -EOPNOTSUPP;
+
+                p += 8;
+        }
+
+        p += strspn(p, WHITESPACE);
+        p[strcspn(p, WHITESPACE)] = 0;
+
+        return safe_atoi(p, mnt_id);
+}
+
+
+int fd_is_mount_point(int fd, const char *filename, int flags) {
+        union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
+        int mount_id = -1, mount_id_parent = -1;
+        bool nosupp = false, check_st_dev = true;
+        struct stat a, b;
+        int r;
+
+        assert(fd >= 0);
+        assert(filename);
+
+        /* First we will try the name_to_handle_at() syscall, which
+         * tells us the mount id and an opaque file "handle". It is
+         * not supported everywhere though (kernel compile-time
+         * option, not all file systems are hooked up). If it works
+         * the mount id is usually good enough to tell us whether
+         * something is a mount point.
+         *
+         * If that didn't work we will try to read the mount id from
+         * /proc/self/fdinfo/<fd>. This is almost as good as
+         * name_to_handle_at(), however, does not return the
+         * opaque file handle. The opaque file handle is pretty useful
+         * to detect the root directory, which we should always
+         * consider a mount point. Hence we use this only as
+         * fallback. Exporting the mnt_id in fdinfo is a pretty recent
+         * kernel addition.
+         *
+         * As last fallback we do traditional fstat() based st_dev
+         * comparisons. This is how things were traditionally done,
+         * but unionfs breaks breaks this since it exposes file
+         * systems with a variety of st_dev reported. Also, btrfs
+         * subvolumes have different st_dev, even though they aren't
+         * real mounts of their own. */
+
+        r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
+        if (r < 0) {
+                if (errno == ENOSYS)
+                        /* This kernel does not support name_to_handle_at()
+                         * fall back to simpler logic. */
+                        goto fallback_fdinfo;
+                else if (errno == EOPNOTSUPP)
+                        /* This kernel or file system does not support
+                         * name_to_handle_at(), hence let's see if the
+                         * upper fs supports it (in which case it is a
+                         * mount point), otherwise fallback to the
+                         * traditional stat() logic */
+                        nosupp = true;
+                else
+                        return -errno;
+        }
+
+        r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
+        if (r < 0) {
+                if (errno == EOPNOTSUPP) {
+                        if (nosupp)
+                                /* Neither parent nor child do name_to_handle_at()?
+                                   We have no choice but to fall back. */
+                                goto fallback_fdinfo;
+                        else
+                                /* The parent can't do name_to_handle_at() but the
+                                 * directory we are interested in can?
+                                 * If so, it must be a mount point. */
+                                return 1;
+                } else
+                        return -errno;
+        }
+
+        /* The parent can do name_to_handle_at() but the
+         * directory we are interested in can't? If so, it
+         * must be a mount point. */
+        if (nosupp)
+                return 1;
+
+        /* If the file handle for the directory we are
+         * interested in and its parent are identical, we
+         * assume this is the root directory, which is a mount
+         * point. */
+
+        if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
+            h.handle.handle_type == h_parent.handle.handle_type &&
+            memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
+                return 1;
+
+        return mount_id != mount_id_parent;
+
+fallback_fdinfo:
+        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
+        if (r == -EOPNOTSUPP)
+                goto fallback_fstat;
+        if (r < 0)
+                return r;
+
+        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
+        if (r < 0)
+                return r;
+
+        if (mount_id != mount_id_parent)
+                return 1;
+
+        /* Hmm, so, the mount ids are the same. This leaves one
+         * special case though for the root file system. For that,
+         * let's see if the parent directory has the same inode as we
+         * are interested in. Hence, let's also do fstat() checks now,
+         * too, but avoid the st_dev comparisons, since they aren't
+         * that useful on unionfs mounts. */
+        check_st_dev = false;
+
+fallback_fstat:
+        /* yay for fstatat() taking a different set of flags than the other
+         * _at() above */
+        if (flags & AT_SYMLINK_FOLLOW)
+                flags &= ~AT_SYMLINK_FOLLOW;
+        else
+                flags |= AT_SYMLINK_NOFOLLOW;
+        if (fstatat(fd, filename, &a, flags) < 0)
+                return -errno;
+
+        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
+                return -errno;
+
+        /* A directory with same device and inode as its parent? Must
+         * be the root directory */
+        if (a.st_dev == b.st_dev &&
+            a.st_ino == b.st_ino)
+                return 1;
+
+        return check_st_dev && (a.st_dev != b.st_dev);
+}
+
+/* flags can be AT_SYMLINK_FOLLOW or 0 */
+int path_is_mount_point(const char *t, int flags) {
+        _cleanup_close_ int fd = -1;
+        _cleanup_free_ char *canonical = NULL, *parent = NULL;
+
+        assert(t);
+
+        if (path_equal(t, "/"))
+                return 1;
+
+        /* we need to resolve symlinks manually, we can't just rely on
+         * fd_is_mount_point() to do that for us; if we have a structure like
+         * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
+         * look at needs to be /usr, not /. */
+        if (flags & AT_SYMLINK_FOLLOW) {
+                canonical = canonicalize_file_name(t);
+                if (!canonical)
+                        return -errno;
+
+                t = canonical;
+        }
+
+        parent = dirname_malloc(t);
+        if (!parent)
+                return -ENOMEM;
+
+        fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
+        if (fd < 0)
+                return -errno;
+
+        return fd_is_mount_point(fd, basename(t), flags);
+}
+
+int umount_recursive(const char *prefix, int flags) {
+        bool again;
+        int n = 0, r;
+
+        /* Try to umount everything recursively below a
+         * directory. Also, take care of stacked mounts, and keep
+         * unmounting them until they are gone. */
+
+        do {
+                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+
+                again = false;
+                r = 0;
+
+                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+                if (!proc_self_mountinfo)
+                        return -errno;
+
+                for (;;) {
+                        _cleanup_free_ char *path = NULL, *p = NULL;
+                        int k;
+
+                        k = fscanf(proc_self_mountinfo,
+                                   "%*s "       /* (1) mount id */
+                                   "%*s "       /* (2) parent id */
+                                   "%*s "       /* (3) major:minor */
+                                   "%*s "       /* (4) root */
+                                   "%ms "       /* (5) mount point */
+                                   "%*s"        /* (6) mount options */
+                                   "%*[^-]"     /* (7) optional fields */
+                                   "- "         /* (8) separator */
+                                   "%*s "       /* (9) file system type */
+                                   "%*s"        /* (10) mount source */
+                                   "%*s"        /* (11) mount options 2 */
+                                   "%*[^\n]",   /* some rubbish at the end */
+                                   &path);
+                        if (k != 1) {
+                                if (k == EOF)
+                                        break;
+
+                                continue;
+                        }
+
+                        r = cunescape(path, UNESCAPE_RELAX, &p);
+                        if (r < 0)
+                                return r;
+
+                        if (!path_startswith(p, prefix))
+                                continue;
+
+                        if (umount2(p, flags) < 0) {
+                                r = -errno;
+                                continue;
+                        }
+
+                        again = true;
+                        n++;
+
+                        break;
+                }
+
+        } while (again);
+
+        return r ? r : n;
+}
+
+static int get_mount_flags(const char *path, unsigned long *flags) {
+        struct statvfs buf;
+
+        if (statvfs(path, &buf) < 0)
+                return -errno;
+        *flags = buf.f_flag;
+        return 0;
+}
+
+int bind_remount_recursive(const char *prefix, bool ro) {
+        _cleanup_set_free_free_ Set *done = NULL;
+        _cleanup_free_ char *cleaned = NULL;
+        int r;
+
+        /* Recursively remount a directory (and all its submounts)
+         * read-only or read-write. If the directory is already
+         * mounted, we reuse the mount and simply mark it
+         * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
+         * operation). If it isn't we first make it one. Afterwards we
+         * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
+         * submounts we can access, too. When mounts are stacked on
+         * the same mount point we only care for each individual
+         * "top-level" mount on each point, as we cannot
+         * influence/access the underlying mounts anyway. We do not
+         * have any effect on future submounts that might get
+         * propagated, they migt be writable. This includes future
+         * submounts that have been triggered via autofs. */
+
+        cleaned = strdup(prefix);
+        if (!cleaned)
+                return -ENOMEM;
+
+        path_kill_slashes(cleaned);
+
+        done = set_new(&string_hash_ops);
+        if (!done)
+                return -ENOMEM;
+
+        for (;;) {
+                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+                _cleanup_set_free_free_ Set *todo = NULL;
+                bool top_autofs = false;
+                char *x;
+                unsigned long orig_flags;
+
+                todo = set_new(&string_hash_ops);
+                if (!todo)
+                        return -ENOMEM;
+
+                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+                if (!proc_self_mountinfo)
+                        return -errno;
+
+                for (;;) {
+                        _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
+                        int k;
+
+                        k = fscanf(proc_self_mountinfo,
+                                   "%*s "       /* (1) mount id */
+                                   "%*s "       /* (2) parent id */
+                                   "%*s "       /* (3) major:minor */
+                                   "%*s "       /* (4) root */
+                                   "%ms "       /* (5) mount point */
+                                   "%*s"        /* (6) mount options (superblock) */
+                                   "%*[^-]"     /* (7) optional fields */
+                                   "- "         /* (8) separator */
+                                   "%ms "       /* (9) file system type */
+                                   "%*s"        /* (10) mount source */
+                                   "%*s"        /* (11) mount options (bind mount) */
+                                   "%*[^\n]",   /* some rubbish at the end */
+                                   &path,
+                                   &type);
+                        if (k != 2) {
+                                if (k == EOF)
+                                        break;
+
+                                continue;
+                        }
+
+                        r = cunescape(path, UNESCAPE_RELAX, &p);
+                        if (r < 0)
+                                return r;
+
+                        /* Let's ignore autofs mounts.  If they aren't
+                         * triggered yet, we want to avoid triggering
+                         * them, as we don't make any guarantees for
+                         * future submounts anyway.  If they are
+                         * already triggered, then we will find
+                         * another entry for this. */
+                        if (streq(type, "autofs")) {
+                                top_autofs = top_autofs || path_equal(cleaned, p);
+                                continue;
+                        }
+
+                        if (path_startswith(p, cleaned) &&
+                            !set_contains(done, p)) {
+
+                                r = set_consume(todo, p);
+                                p = NULL;
+
+                                if (r == -EEXIST)
+                                        continue;
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+
+                /* If we have no submounts to process anymore and if
+                 * the root is either already done, or an autofs, we
+                 * are done */
+                if (set_isempty(todo) &&
+                    (top_autofs || set_contains(done, cleaned)))
+                        return 0;
+
+                if (!set_contains(done, cleaned) &&
+                    !set_contains(todo, cleaned)) {
+                        /* The prefix directory itself is not yet a
+                         * mount, make it one. */
+                        if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
+                                return -errno;
+
+                        orig_flags = 0;
+                        (void) get_mount_flags(cleaned, &orig_flags);
+                        orig_flags &= ~MS_RDONLY;
+
+                        if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+                                return -errno;
+
+                        x = strdup(cleaned);
+                        if (!x)
+                                return -ENOMEM;
+
+                        r = set_consume(done, x);
+                        if (r < 0)
+                                return r;
+                }
+
+                while ((x = set_steal_first(todo))) {
+
+                        r = set_consume(done, x);
+                        if (r == -EEXIST || r == 0)
+                                continue;
+                        if (r < 0)
+                                return r;
+
+                        /* Try to reuse the original flag set, but
+                         * don't care for errors, in case of
+                         * obstructed mounts */
+                        orig_flags = 0;
+                        (void) get_mount_flags(x, &orig_flags);
+                        orig_flags &= ~MS_RDONLY;
+
+                        if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
+
+                                /* Deal with mount points that are
+                                 * obstructed by a later mount */
+
+                                if (errno != ENOENT)
+                                        return -errno;
+                        }
+
+                }
+        }
+}
+
+int mount_move_root(const char *path) {
+        assert(path);
+
+        if (chdir(path) < 0)
+                return -errno;
+
+        if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
+                return -errno;
+
+        if (chroot(".") < 0)
+                return -errno;
+
+        if (chdir("/") < 0)
+                return -errno;
+
+        return 0;
+}
+
+bool fstype_is_network(const char *fstype) {
+        static const char table[] =
+                "afs\0"
+                "cifs\0"
+                "smbfs\0"
+                "sshfs\0"
+                "ncpfs\0"
+                "ncp\0"
+                "nfs\0"
+                "nfs4\0"
+                "gfs\0"
+                "gfs2\0"
+                "glusterfs\0";
+
+        const char *x;
+
+        x = startswith(fstype, "fuse.");
+        if (x)
+                fstype = x;
+
+        return nulstr_contains(table, fstype);
+}
+
+int repeat_unmount(const char *path, int flags) {
+        bool done = false;
+
+        assert(path);
+
+        /* If there are multiple mounts on a mount point, this
+         * removes them all */
+
+        for (;;) {
+                if (umount2(path, flags) < 0) {
+
+                        if (errno == EINVAL)
+                                return done;
+
+                        return -errno;
+                }
+
+                done = true;
+        }
+}
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
new file mode 100644 (file)
index 0000000..48954c2
--- /dev/null
@@ -0,0 +1,52 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <mntent.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "missing.h"
+
+int fd_is_mount_point(int fd, const char *filename, int flags);
+int path_is_mount_point(const char *path, int flags);
+
+int repeat_unmount(const char *path, int flags);
+
+int umount_recursive(const char *target, int flags);
+int bind_remount_recursive(const char *prefix, bool ro);
+
+int mount_move_root(const char *path);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
+#define _cleanup_endmntent_ _cleanup_(endmntentp)
+
+bool fstype_is_network(const char *fstype);
+
+union file_handle_union {
+        struct file_handle handle;
+        char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
+};
+
+#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
new file mode 100644 (file)
index 0000000..151067e
--- /dev/null
@@ -0,0 +1,492 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "extract-word.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
+
+int parse_boolean(const char *v) {
+        assert(v);
+
+        if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
+                return 1;
+        else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
+                return 0;
+
+        return -EINVAL;
+}
+
+int parse_pid(const char *s, pid_t* ret_pid) {
+        unsigned long ul = 0;
+        pid_t pid;
+        int r;
+
+        assert(s);
+        assert(ret_pid);
+
+        r = safe_atolu(s, &ul);
+        if (r < 0)
+                return r;
+
+        pid = (pid_t) ul;
+
+        if ((unsigned long) pid != ul)
+                return -ERANGE;
+
+        if (pid <= 0)
+                return -ERANGE;
+
+        *ret_pid = pid;
+        return 0;
+}
+
+int parse_mode(const char *s, mode_t *ret) {
+        char *x;
+        long l;
+
+        assert(s);
+        assert(ret);
+
+        s += strspn(s, WHITESPACE);
+        if (s[0] == '-')
+                return -ERANGE;
+
+        errno = 0;
+        l = strtol(s, &x, 8);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (l < 0 || l  > 07777)
+                return -ERANGE;
+
+        *ret = (mode_t) l;
+        return 0;
+}
+
+int parse_ifindex(const char *s, int *ret) {
+        int ifi, r;
+
+        r = safe_atoi(s, &ifi);
+        if (r < 0)
+                return r;
+        if (ifi <= 0)
+                return -EINVAL;
+
+        *ret = ifi;
+        return 0;
+}
+
+int parse_size(const char *t, uint64_t base, uint64_t *size) {
+
+        /* Soo, sometimes we want to parse IEC binary suffixes, and
+         * sometimes SI decimal suffixes. This function can parse
+         * both. Which one is the right way depends on the
+         * context. Wikipedia suggests that SI is customary for
+         * hardware metrics and network speeds, while IEC is
+         * customary for most data sizes used by software and volatile
+         * (RAM) memory. Hence be careful which one you pick!
+         *
+         * In either case we use just K, M, G as suffix, and not Ki,
+         * Mi, Gi or so (as IEC would suggest). That's because that's
+         * frickin' ugly. But this means you really need to make sure
+         * to document which base you are parsing when you use this
+         * call. */
+
+        struct table {
+                const char *suffix;
+                unsigned long long factor;
+        };
+
+        static const struct table iec[] = {
+                { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+                { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+                { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
+                { "G", 1024ULL*1024ULL*1024ULL },
+                { "M", 1024ULL*1024ULL },
+                { "K", 1024ULL },
+                { "B", 1ULL },
+                { "",  1ULL },
+        };
+
+        static const struct table si[] = {
+                { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+                { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+                { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
+                { "G", 1000ULL*1000ULL*1000ULL },
+                { "M", 1000ULL*1000ULL },
+                { "K", 1000ULL },
+                { "B", 1ULL },
+                { "",  1ULL },
+        };
+
+        const struct table *table;
+        const char *p;
+        unsigned long long r = 0;
+        unsigned n_entries, start_pos = 0;
+
+        assert(t);
+        assert(base == 1000 || base == 1024);
+        assert(size);
+
+        if (base == 1000) {
+                table = si;
+                n_entries = ELEMENTSOF(si);
+        } else {
+                table = iec;
+                n_entries = ELEMENTSOF(iec);
+        }
+
+        p = t;
+        do {
+                unsigned long long l, tmp;
+                double frac = 0;
+                char *e;
+                unsigned i;
+
+                p += strspn(p, WHITESPACE);
+
+                errno = 0;
+                l = strtoull(p, &e, 10);
+                if (errno != 0)
+                        return -errno;
+                if (e == p)
+                        return -EINVAL;
+                if (*p == '-')
+                        return -ERANGE;
+
+                if (*e == '.') {
+                        e++;
+
+                        /* strtoull() itself would accept space/+/- */
+                        if (*e >= '0' && *e <= '9') {
+                                unsigned long long l2;
+                                char *e2;
+
+                                l2 = strtoull(e, &e2, 10);
+                                if (errno != 0)
+                                        return -errno;
+
+                                /* Ignore failure. E.g. 10.M is valid */
+                                frac = l2;
+                                for (; e < e2; e++)
+                                        frac /= 10;
+                        }
+                }
+
+                e += strspn(e, WHITESPACE);
+
+                for (i = start_pos; i < n_entries; i++)
+                        if (startswith(e, table[i].suffix))
+                                break;
+
+                if (i >= n_entries)
+                        return -EINVAL;
+
+                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
+                        return -ERANGE;
+
+                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
+                if (tmp > ULLONG_MAX - r)
+                        return -ERANGE;
+
+                r += tmp;
+                if ((unsigned long long) (uint64_t) r != r)
+                        return -ERANGE;
+
+                p = e + strlen(table[i].suffix);
+
+                start_pos = i + 1;
+
+        } while (*p);
+
+        *size = r;
+
+        return 0;
+}
+
+int parse_range(const char *t, unsigned *lower, unsigned *upper) {
+        _cleanup_free_ char *word = NULL;
+        unsigned l, u;
+        int r;
+
+        assert(lower);
+        assert(upper);
+
+        /* Extract the lower bound. */
+        r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EINVAL;
+
+        r = safe_atou(word, &l);
+        if (r < 0)
+                return r;
+
+        /* Check for the upper bound and extract it if needed */
+        if (!t)
+                /* Single number with no dashes. */
+                u = l;
+        else if (!*t)
+                /* Trailing dash is an error. */
+                return -EINVAL;
+        else {
+                r = safe_atou(t, &u);
+                if (r < 0)
+                        return r;
+        }
+
+        *lower = l;
+        *upper = u;
+        return 0;
+}
+
+char *format_bytes(char *buf, size_t l, uint64_t t) {
+        unsigned i;
+
+        /* This only does IEC units so far */
+
+        static const struct {
+                const char *suffix;
+                uint64_t factor;
+        } table[] = {
+                { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+                { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+                { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+                { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+                { "M", UINT64_C(1024)*UINT64_C(1024) },
+                { "K", UINT64_C(1024) },
+        };
+
+        if (t == (uint64_t) -1)
+                return NULL;
+
+        for (i = 0; i < ELEMENTSOF(table); i++) {
+
+                if (t >= table[i].factor) {
+                        snprintf(buf, l,
+                                 "%" PRIu64 ".%" PRIu64 "%s",
+                                 t / table[i].factor,
+                                 ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
+                                 table[i].suffix);
+
+                        goto finish;
+                }
+        }
+
+        snprintf(buf, l, "%" PRIu64 "B", t);
+
+finish:
+        buf[l-1] = 0;
+        return buf;
+
+}
+
+int safe_atou(const char *s, unsigned *ret_u) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret_u);
+
+        /* strtoul() is happy to parse negative values, and silently
+         * converts them to unsigned values without generating an
+         * error. We want a clean error, hence let's look for the "-"
+         * prefix on our own, and generate an error. But let's do so
+         * only after strtoul() validated that the string is clean
+         * otherwise, so that we return EINVAL preferably over
+         * ERANGE. */
+
+        s += strspn(s, WHITESPACE);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
+        if ((unsigned long) (unsigned) l != l)
+                return -ERANGE;
+
+        *ret_u = (unsigned) l;
+        return 0;
+}
+
+int safe_atoi(const char *s, int *ret_i) {
+        char *x = NULL;
+        long l;
+
+        assert(s);
+        assert(ret_i);
+
+        errno = 0;
+        l = strtol(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if ((long) (int) l != l)
+                return -ERANGE;
+
+        *ret_i = (int) l;
+        return 0;
+}
+
+int safe_atollu(const char *s, long long unsigned *ret_llu) {
+        char *x = NULL;
+        unsigned long long l;
+
+        assert(s);
+        assert(ret_llu);
+
+        s += strspn(s, WHITESPACE);
+
+        errno = 0;
+        l = strtoull(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (*s == '-')
+                return -ERANGE;
+
+        *ret_llu = l;
+        return 0;
+}
+
+int safe_atolli(const char *s, long long int *ret_lli) {
+        char *x = NULL;
+        long long l;
+
+        assert(s);
+        assert(ret_lli);
+
+        errno = 0;
+        l = strtoll(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+
+        *ret_lli = l;
+        return 0;
+}
+
+int safe_atou8(const char *s, uint8_t *ret) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret);
+
+        s += strspn(s, WHITESPACE);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
+        if ((unsigned long) (uint8_t) l != l)
+                return -ERANGE;
+
+        *ret = (uint8_t) l;
+        return 0;
+}
+
+int safe_atou16(const char *s, uint16_t *ret) {
+        char *x = NULL;
+        unsigned long l;
+
+        assert(s);
+        assert(ret);
+
+        s += strspn(s, WHITESPACE);
+
+        errno = 0;
+        l = strtoul(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if (s[0] == '-')
+                return -ERANGE;
+        if ((unsigned long) (uint16_t) l != l)
+                return -ERANGE;
+
+        *ret = (uint16_t) l;
+        return 0;
+}
+
+int safe_atoi16(const char *s, int16_t *ret) {
+        char *x = NULL;
+        long l;
+
+        assert(s);
+        assert(ret);
+
+        errno = 0;
+        l = strtol(s, &x, 0);
+        if (errno != 0)
+                return -errno;
+        if (!x || x == s || *x)
+                return -EINVAL;
+        if ((long) (int16_t) l != l)
+                return -ERANGE;
+
+        *ret = (int16_t) l;
+        return 0;
+}
+
+int safe_atod(const char *s, double *ret_d) {
+        char *x = NULL;
+        double d = 0;
+        locale_t loc;
+
+        assert(s);
+        assert(ret_d);
+
+        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
+        if (loc == (locale_t) 0)
+                return -errno;
+
+        errno = 0;
+        d = strtod_l(s, &x, loc);
+        if (errno != 0) {
+                freelocale(loc);
+                return -errno;
+        }
+        if (!x || x == s || *x) {
+                freelocale(loc);
+                return -EINVAL;
+        }
+
+        freelocale(loc);
+        *ret_d = (double) d;
+        return 0;
+}
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
new file mode 100644 (file)
index 0000000..408690d
--- /dev/null
@@ -0,0 +1,92 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <inttypes.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+#define MODE_INVALID ((mode_t) -1)
+
+int parse_boolean(const char *v) _pure_;
+int parse_pid(const char *s, pid_t* ret_pid);
+int parse_mode(const char *s, mode_t *ret);
+int parse_ifindex(const char *s, int *ret);
+
+int parse_size(const char *t, uint64_t base, uint64_t *size);
+int parse_range(const char *t, unsigned *lower, unsigned *upper);
+
+#define FORMAT_BYTES_MAX 8
+char *format_bytes(char *buf, size_t l, uint64_t t);
+
+int safe_atou(const char *s, unsigned *ret_u);
+int safe_atoi(const char *s, int *ret_i);
+int safe_atollu(const char *s, unsigned long long *ret_u);
+int safe_atolli(const char *s, long long int *ret_i);
+
+int safe_atou8(const char *s, uint8_t *ret);
+
+int safe_atou16(const char *s, uint16_t *ret);
+int safe_atoi16(const char *s, int16_t *ret);
+
+static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+        return safe_atou(s, (unsigned*) ret_u);
+}
+
+static inline int safe_atoi32(const char *s, int32_t *ret_i) {
+        assert_cc(sizeof(int32_t) == sizeof(int));
+        return safe_atoi(s, (int*) ret_i);
+}
+
+static inline int safe_atou64(const char *s, uint64_t *ret_u) {
+        assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
+        return safe_atollu(s, (unsigned long long*) ret_u);
+}
+
+static inline int safe_atoi64(const char *s, int64_t *ret_i) {
+        assert_cc(sizeof(int64_t) == sizeof(long long int));
+        return safe_atolli(s, (long long int*) ret_i);
+}
+
+#if LONG_MAX == INT_MAX
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+        assert_cc(sizeof(unsigned long) == sizeof(unsigned));
+        return safe_atou(s, (unsigned*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+        assert_cc(sizeof(long int) == sizeof(int));
+        return safe_atoi(s, (int*) ret_u);
+}
+#else
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+        assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
+        return safe_atollu(s, (unsigned long long*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+        assert_cc(sizeof(long int) == sizeof(long long int));
+        return safe_atolli(s, (long long int*) ret_u);
+}
+#endif
+
+int safe_atod(const char *s, double *ret_d);
index 5cbfc145a48c843131b7ec5305abcfd326b73eaa..ec90c432a4bdb48d5a906de58adef2f0eb8fc3e2 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
-#include <unistd.h>
 #include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/statvfs.h>
+#include <unistd.h>
 
-#include "macro.h"
-#include "util.h"
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the
+ * POSIX version which is really broken. We prefer GNU basename(). */
+#include <libgen.h>
+#undef basename
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "log.h"
-#include "strv.h"
-#include "path-util.h"
+#include "macro.h"
 #include "missing.h"
-#include "fileio.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 bool path_is_absolute(const char *p) {
         return p[0] == '/';
@@ -43,61 +55,25 @@ bool is_path(const char *p) {
         return !!strchr(p, '/');
 }
 
-int path_get_parent(const char *path, char **_r) {
-        const char *e, *a = NULL, *b = NULL, *p;
-        char *r;
-        bool slash = false;
-
-        assert(path);
-        assert(_r);
-
-        if (!*path)
-                return -EINVAL;
-
-        for (e = path; *e; e++) {
-
-                if (!slash && *e == '/') {
-                        a = b;
-                        b = e;
-                        slash = true;
-                } else if (slash && *e != '/')
-                        slash = false;
-        }
-
-        if (*(e-1) == '/')
-                p = a;
-        else
-                p = b;
-
-        if (!p)
-                return -EINVAL;
-
-        if (p == path)
-                r = strdup("/");
-        else
-                r = strndup(path, p-path);
-
-        if (!r)
-                return -ENOMEM;
-
-        *_r = r;
-        return 0;
-}
-
-char **path_split_and_make_absolute(const char *p) {
+int path_split_and_make_absolute(const char *p, char ***ret) {
         char **l;
+        int r;
+
         assert(p);
+        assert(ret);
 
         l = strv_split(p, ":");
         if (!l)
-                return NULL;
+                return -ENOMEM;
 
-        if (!path_strv_make_absolute_cwd(l)) {
+        r = path_strv_make_absolute_cwd(l);
+        if (r < 0) {
                 strv_free(l);
-                return NULL;
+                return r;
         }
 
-        return l;
+        *ret = l;
+        return r;
 }
 
 char *path_make_absolute(const char *p, const char *prefix) {
@@ -112,22 +88,31 @@ char *path_make_absolute(const char *p, const char *prefix) {
         return strjoin(prefix, "/", p, NULL);
 }
 
-char *path_make_absolute_cwd(const char *p) {
-        _cleanup_free_ char *cwd = NULL;
+int path_make_absolute_cwd(const char *p, char **ret) {
+        char *c;
 
         assert(p);
+        assert(ret);
 
         /* Similar to path_make_absolute(), but prefixes with the
          * current working directory. */
 
         if (path_is_absolute(p))
-                return strdup(p);
+                c = strdup(p);
+        else {
+                _cleanup_free_ char *cwd = NULL;
 
-        cwd = get_current_dir_name();
-        if (!cwd)
-                return NULL;
+                cwd = get_current_dir_name();
+                if (!cwd)
+                        return -errno;
+
+                c = strjoin(cwd, "/", p, NULL);
+        }
+        if (!c)
+                return -ENOMEM;
 
-        return strjoin(cwd, "/", p, NULL);
+        *ret = c;
+        return 0;
 }
 
 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
@@ -215,8 +200,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
         return 0;
 }
 
-char **path_strv_make_absolute_cwd(char **l) {
+int path_strv_make_absolute_cwd(char **l) {
         char **s;
+        int r;
 
         /* Goes through every item in the string list and makes it
          * absolute. This works in place and won't rollback any
@@ -225,15 +211,15 @@ char **path_strv_make_absolute_cwd(char **l) {
         STRV_FOREACH(s, l) {
                 char *t;
 
-                t = path_make_absolute_cwd(*s);
-                if (!t)
-                        return NULL;
+                r = path_make_absolute_cwd(*s, &t);
+                if (r < 0)
+                        return r;
 
                 free(*s);
                 *s = t;
         }
 
-        return l;
+        return 0;
 }
 
 char **path_strv_resolve(char **l, const char *prefix) {
@@ -411,7 +397,7 @@ int path_compare(const char *a, const char *b) {
          * Which one is sorted before the other does not really matter.
          * Here a relative path is ordered before an absolute path. */
         d = (a[0] == '/') - (b[0] == '/');
-        if (d)
+        if (d != 0)
                 return d;
 
         for (;;) {
@@ -434,12 +420,12 @@ int path_compare(const char *a, const char *b) {
 
                 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
                 d = memcmp(a, b, MIN(j, k));
-                if (d)
+                if (d != 0)
                         return (d > 0) - (d < 0); /* sign of d */
 
                 /* Sort "/foo/a" before "/foo/aaa" */
                 d = (j > k) - (j < k);  /* sign of (j - k) */
-                if (d)
+                if (d != 0)
                         return d;
 
                 a += j;
@@ -471,294 +457,66 @@ char* path_join(const char *root, const char *path, const char *rest) {
                                NULL);
 }
 
-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
-        char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
-        _cleanup_free_ char *fdinfo = NULL;
-        _cleanup_close_ int subfd = -1;
-        char *p;
-        int r;
-
-        if ((flags & AT_EMPTY_PATH) && isempty(filename))
-                xsprintf(path, "/proc/self/fdinfo/%i", fd);
-        else {
-                subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
-                if (subfd < 0)
-                        return -errno;
-
-                xsprintf(path, "/proc/self/fdinfo/%i", subfd);
-        }
-
-        r = read_full_file(path, &fdinfo, NULL);
-        if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
-                return -EOPNOTSUPP;
-        if (r < 0)
-                return -errno;
-
-        p = startswith(fdinfo, "mnt_id:");
-        if (!p) {
-                p = strstr(fdinfo, "\nmnt_id:");
-                if (!p) /* The mnt_id field is a relatively new addition */
-                        return -EOPNOTSUPP;
-
-                p += 8;
-        }
-
-        p += strspn(p, WHITESPACE);
-        p[strcspn(p, WHITESPACE)] = 0;
-
-        return safe_atoi(p, mnt_id);
-}
-
-int fd_is_mount_point(int fd, const char *filename, int flags) {
-        union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
-        int mount_id = -1, mount_id_parent = -1;
-        bool nosupp = false, check_st_dev = true;
-        struct stat a, b;
-        int r;
+int find_binary(const char *name, char **ret) {
+        int last_error, r;
+        const char *p;
 
-        assert(fd >= 0);
-        assert(filename);
-
-        /* First we will try the name_to_handle_at() syscall, which
-         * tells us the mount id and an opaque file "handle". It is
-         * not supported everywhere though (kernel compile-time
-         * option, not all file systems are hooked up). If it works
-         * the mount id is usually good enough to tell us whether
-         * something is a mount point.
-         *
-         * If that didn't work we will try to read the mount id from
-         * /proc/self/fdinfo/<fd>. This is almost as good as
-         * name_to_handle_at(), however, does not return the
-         * opaque file handle. The opaque file handle is pretty useful
-         * to detect the root directory, which we should always
-         * consider a mount point. Hence we use this only as
-         * fallback. Exporting the mnt_id in fdinfo is a pretty recent
-         * kernel addition.
-         *
-         * As last fallback we do traditional fstat() based st_dev
-         * comparisons. This is how things were traditionally done,
-         * but unionfs breaks breaks this since it exposes file
-         * systems with a variety of st_dev reported. Also, btrfs
-         * subvolumes have different st_dev, even though they aren't
-         * real mounts of their own. */
-
-        r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
-        if (r < 0) {
-                if (errno == ENOSYS)
-                        /* This kernel does not support name_to_handle_at()
-                         * fall back to simpler logic. */
-                        goto fallback_fdinfo;
-                else if (errno == EOPNOTSUPP)
-                        /* This kernel or file system does not support
-                         * name_to_handle_at(), hence let's see if the
-                         * upper fs supports it (in which case it is a
-                         * mount point), otherwise fallback to the
-                         * traditional stat() logic */
-                        nosupp = true;
-                else
-                        return -errno;
-        }
+        assert(name);
 
-        r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
-        if (r < 0) {
-                if (errno == EOPNOTSUPP) {
-                        if (nosupp)
-                                /* Neither parent nor child do name_to_handle_at()?
-                                   We have no choice but to fall back. */
-                                goto fallback_fdinfo;
-                        else
-                                /* The parent can't do name_to_handle_at() but the
-                                 * directory we are interested in can?
-                                 * If so, it must be a mount point. */
-                                return 1;
-                } else
+        if (is_path(name)) {
+                if (access(name, X_OK) < 0)
                         return -errno;
-        }
-
-        /* The parent can do name_to_handle_at() but the
-         * directory we are interested in can't? If so, it
-         * must be a mount point. */
-        if (nosupp)
-                return 1;
-
-        /* If the file handle for the directory we are
-         * interested in and its parent are identical, we
-         * assume this is the root directory, which is a mount
-         * point. */
-
-        if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
-            h.handle.handle_type == h_parent.handle.handle_type &&
-            memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
-                return 1;
-
-        return mount_id != mount_id_parent;
-
-fallback_fdinfo:
-        r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
-        if (r == -EOPNOTSUPP)
-                goto fallback_fstat;
-        if (r < 0)
-                return r;
-
-        r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
-        if (r < 0)
-                return r;
-
-        if (mount_id != mount_id_parent)
-                return 1;
-
-        /* Hmm, so, the mount ids are the same. This leaves one
-         * special case though for the root file system. For that,
-         * let's see if the parent directory has the same inode as we
-         * are interested in. Hence, let's also do fstat() checks now,
-         * too, but avoid the st_dev comparisons, since they aren't
-         * that useful on unionfs mounts. */
-        check_st_dev = false;
-
-fallback_fstat:
-        /* yay for fstatat() taking a different set of flags than the other
-         * _at() above */
-        if (flags & AT_SYMLINK_FOLLOW)
-                flags &= ~AT_SYMLINK_FOLLOW;
-        else
-                flags |= AT_SYMLINK_NOFOLLOW;
-        if (fstatat(fd, filename, &a, flags) < 0)
-                return -errno;
-
-        if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
-                return -errno;
-
-        /* A directory with same device and inode as its parent? Must
-         * be the root directory */
-        if (a.st_dev == b.st_dev &&
-            a.st_ino == b.st_ino)
-                return 1;
-
-        return check_st_dev && (a.st_dev != b.st_dev);
-}
 
-/* flags can be AT_SYMLINK_FOLLOW or 0 */
-int path_is_mount_point(const char *t, int flags) {
-        _cleanup_close_ int fd = -1;
-        _cleanup_free_ char *canonical = NULL, *parent = NULL;
-        int r;
-
-        assert(t);
-
-        if (path_equal(t, "/"))
-                return 1;
-
-        /* we need to resolve symlinks manually, we can't just rely on
-         * fd_is_mount_point() to do that for us; if we have a structure like
-         * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
-         * look at needs to be /usr, not /. */
-        if (flags & AT_SYMLINK_FOLLOW) {
-                canonical = canonicalize_file_name(t);
-                if (!canonical)
-                        return -errno;
+                if (ret) {
+                        r = path_make_absolute_cwd(name, ret);
+                        if (r < 0)
+                                return r;
+                }
 
-                t = canonical;
+                return 0;
         }
 
-        r = path_get_parent(t, &parent);
-        if (r < 0)
-                return r;
-
-        fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
-        if (fd < 0)
-                return -errno;
-
-        return fd_is_mount_point(fd, basename(t), flags);
-}
-
-int path_is_read_only_fs(const char *path) {
-        struct statvfs st;
-
-        assert(path);
-
-        if (statvfs(path, &st) < 0)
-                return -errno;
-
-        if (st.f_flag & ST_RDONLY)
-                return true;
-
-        /* On NFS, statvfs() might not reflect whether we can actually
-         * write to the remote share. Let's try again with
-         * access(W_OK) which is more reliable, at least sometimes. */
-        if (access(path, W_OK) < 0 && errno == EROFS)
-                return true;
-
-        return false;
-}
-
-int path_is_os_tree(const char *path) {
-        char *p;
-        int r;
-
-        /* We use /usr/lib/os-release as flag file if something is an OS */
-        p = strjoina(path, "/usr/lib/os-release");
-        r = access(p, F_OK);
-
-        if (r >= 0)
-                return 1;
-
-        /* Also check for the old location in /etc, just in case. */
-        p = strjoina(path, "/etc/os-release");
-        r = access(p, F_OK);
-
-        return r >= 0;
-}
-
-int find_binary(const char *name, bool local, char **filename) {
-        assert(name);
+        /**
+         * Plain getenv, not secure_getenv, because we want
+         * to actually allow the user to pick the binary.
+         */
+        p = getenv("PATH");
+        if (!p)
+                p = DEFAULT_PATH;
 
-        if (is_path(name)) {
-                if (local && access(name, X_OK) < 0)
-                        return -errno;
+        last_error = -ENOENT;
 
-                if (filename) {
-                        char *p;
+        for (;;) {
+                _cleanup_free_ char *j = NULL, *element = NULL;
 
-                        p = path_make_absolute_cwd(name);
-                        if (!p)
-                                return -ENOMEM;
+                r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
 
-                        *filename = p;
-                }
+                if (!path_is_absolute(element))
+                        continue;
 
-                return 0;
-        } else {
-                const char *path;
-                const char *word, *state;
-                size_t l;
-
-                /**
-                 * Plain getenv, not secure_getenv, because we want
-                 * to actually allow the user to pick the binary.
-                 */
-                path = getenv("PATH");
-                if (!path)
-                        path = DEFAULT_PATH;
-
-                FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
-                        _cleanup_free_ char *p = NULL;
-
-                        if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
-                                return -ENOMEM;
+                j = strjoin(element, "/", name, NULL);
+                if (!j)
+                        return -ENOMEM;
 
-                        if (access(p, X_OK) < 0)
-                                continue;
+                if (access(j, X_OK) >= 0) {
+                        /* Found it! */
 
-                        if (filename) {
-                                *filename = path_kill_slashes(p);
-                                p = NULL;
+                        if (ret) {
+                                *ret = path_kill_slashes(j);
+                                j = NULL;
                         }
 
                         return 0;
                 }
 
-                return -ENOENT;
+                last_error = -errno;
         }
+
+        return last_error;
 }
 
 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
@@ -796,14 +554,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
         return changed;
 }
 
-int fsck_exists(const char *fstype) {
+static int binary_is_good(const char *binary) {
         _cleanup_free_ char *p = NULL, *d = NULL;
-        const char *checker;
         int r;
 
-        checker = strjoina("fsck.", fstype);
-
-        r = find_binary(checker, true, &p);
+        r = find_binary(binary, &p);
+        if (r == -ENOENT)
+                return 0;
         if (r < 0)
                 return r;
 
@@ -811,13 +568,39 @@ int fsck_exists(const char *fstype) {
          * fsck */
 
         r = readlink_malloc(p, &d);
-        if (r >= 0 &&
-            (path_equal(d, "/bin/true") ||
-             path_equal(d, "/usr/bin/true") ||
-             path_equal(d, "/dev/null")))
-                return -ENOENT;
+        if (r == -EINVAL) /* not a symlink */
+                return 1;
+        if (r < 0)
+                return r;
 
-        return 0;
+        return !path_equal(d, "true") &&
+               !path_equal(d, "/bin/true") &&
+               !path_equal(d, "/usr/bin/true") &&
+               !path_equal(d, "/dev/null");
+}
+
+int fsck_exists(const char *fstype) {
+        const char *checker;
+
+        assert(fstype);
+
+        if (streq(fstype, "auto"))
+                return -EINVAL;
+
+        checker = strjoina("fsck.", fstype);
+        return binary_is_good(checker);
+}
+
+int mkfs_exists(const char *fstype) {
+        const char *mkfs;
+
+        assert(fstype);
+
+        if (streq(fstype, "auto"))
+                return -EINVAL;
+
+        mkfs = strjoina("mkfs.", fstype);
+        return binary_is_good(mkfs);
 }
 
 char *prefix_root(const char *root, const char *path) {
@@ -853,3 +636,166 @@ char *prefix_root(const char *root, const char *path) {
         strcpy(p, path);
         return n;
 }
+
+int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
+        char *p;
+        int r;
+
+        /*
+         * This function is intended to be used in command line
+         * parsers, to handle paths that are passed in. It makes the
+         * path absolute, and reduces it to NULL if omitted or
+         * root (the latter optionally).
+         *
+         * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
+         * SUCCESS! Hence, do not pass in uninitialized pointers.
+         */
+
+        if (isempty(path)) {
+                *arg = mfree(*arg);
+                return 0;
+        }
+
+        r = path_make_absolute_cwd(path, &p);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
+
+        path_kill_slashes(p);
+        if (suppress_root && path_equal(p, "/"))
+                p = mfree(p);
+
+        free(*arg);
+        *arg = p;
+        return 0;
+}
+
+char* dirname_malloc(const char *path) {
+        char *d, *dir, *dir2;
+
+        assert(path);
+
+        d = strdup(path);
+        if (!d)
+                return NULL;
+
+        dir = dirname(d);
+        assert(dir);
+
+        if (dir == d)
+                return d;
+
+        dir2 = strdup(dir);
+        free(d);
+
+        return dir2;
+}
+
+bool filename_is_valid(const char *p) {
+        const char *e;
+
+        if (isempty(p))
+                return false;
+
+        if (streq(p, "."))
+                return false;
+
+        if (streq(p, ".."))
+                return false;
+
+        e = strchrnul(p, '/');
+        if (*e != 0)
+                return false;
+
+        if (e - p > FILENAME_MAX)
+                return false;
+
+        return true;
+}
+
+bool path_is_safe(const char *p) {
+
+        if (isempty(p))
+                return false;
+
+        if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
+                return false;
+
+        if (strlen(p)+1 > PATH_MAX)
+                return false;
+
+        /* The following two checks are not really dangerous, but hey, they still are confusing */
+        if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
+                return false;
+
+        if (strstr(p, "//"))
+                return false;
+
+        return true;
+}
+
+char *file_in_same_dir(const char *path, const char *filename) {
+        char *e, *ret;
+        size_t k;
+
+        assert(path);
+        assert(filename);
+
+        /* This removes the last component of path and appends
+         * filename, unless the latter is absolute anyway or the
+         * former isn't */
+
+        if (path_is_absolute(filename))
+                return strdup(filename);
+
+        e = strrchr(path, '/');
+        if (!e)
+                return strdup(filename);
+
+        k = strlen(filename);
+        ret = new(char, (e + 1 - path) + k + 1);
+        if (!ret)
+                return NULL;
+
+        memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
+        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_file(const char *filename) {
+        assert(filename);
+
+        if (endswith(filename, "~"))
+                return true;
+
+        return hidden_file_allow_backup(filename);
+}
+
+bool is_device_path(const char *path) {
+
+        /* Returns true on paths that refer to a device, either in
+         * sysfs or in /dev */
+
+        return
+                path_startswith(path, "/dev/") ||
+                path_startswith(path, "/sys/");
+}
index 1eac89c51b6a1b7a9a211b053cc7baa0ff34cdb1..989e0f900498324103082dc5962287bd60fcd848 100644 (file)
 #endif
 
 bool is_path(const char *p) _pure_;
-char** path_split_and_make_absolute(const char *p);
-int path_get_parent(const char *path, char **parent);
+int path_split_and_make_absolute(const char *p, char ***ret);
 bool path_is_absolute(const char *p) _pure_;
 char* path_make_absolute(const char *p, const char *prefix);
-char* path_make_absolute_cwd(const char *p);
+int path_make_absolute_cwd(const char *p, char **ret);
 int path_make_relative(const char *from_dir, const char *to_path, char **_r);
 char* path_kill_slashes(char *path);
 char* path_startswith(const char *path, const char *prefix) _pure_;
@@ -49,20 +48,16 @@ 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);
 
-char** path_strv_make_absolute_cwd(char **l);
+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);
 
-int fd_is_mount_point(int fd, const char *filename, int flags);
-int path_is_mount_point(const char *path, int flags);
-int path_is_read_only_fs(const char *path);
-int path_is_os_tree(const char *path);
-
-int find_binary(const char *name, bool local, char **filename);
+int find_binary(const char *name, char **filename);
 
 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
 
 int fsck_exists(const char *fstype);
+int mkfs_exists(const char *fstype);
 
 /* Iterates through the path prefixes of the specified path, going up
  * the tree, to root. Also returns "" (and not "/"!) for the root
@@ -100,3 +95,17 @@ char *prefix_root(const char *root, const char *path);
                 }                                                       \
                 _ret;                                                   \
         })
+
+int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
+
+char* dirname_malloc(const char *path);
+
+bool filename_is_valid(const char *p) _pure_;
+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 is_device_path(const char *path);
index d55b348c22f2ec82d13d2dacff33dcc3f808abb7..75906989114bc4add71ccf8cd602e06b552e4129 100644 (file)
@@ -29,8 +29,9 @@
  * The underlying algorithm used in this implementation is a Heap.
  */
 
-#include "util.h"
+#include "alloc-util.h"
 #include "prioq.h"
+#include "util.h"
 
 struct prioq_item {
         void *data;
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
new file mode 100644 (file)
index 0000000..4464573
--- /dev/null
@@ -0,0 +1,174 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "extract-word.h"
+#include "fileio.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-util.h"
+#include "util.h"
+#include "virt.h"
+
+int proc_cmdline(char **ret) {
+        assert(ret);
+
+        if (detect_container() > 0)
+                return get_process_cmdline(1, 0, false, ret);
+        else
+                return read_one_line_file("/proc/cmdline", ret);
+}
+
+int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
+        _cleanup_free_ char *line = NULL;
+        const char *p;
+        int r;
+
+        assert(parse_item);
+
+        r = proc_cmdline(&line);
+        if (r < 0)
+                return r;
+
+        p = line;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                char *value = NULL;
+
+                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                /* Filter out arguments that are intended only for the
+                 * initrd */
+                if (!in_initrd() && startswith(word, "rd."))
+                        continue;
+
+                value = strchr(word, '=');
+                if (value)
+                        *(value++) = 0;
+
+                r = parse_item(word, value);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int get_proc_cmdline_key(const char *key, char **value) {
+        _cleanup_free_ char *line = NULL, *ret = NULL;
+        bool found = false;
+        const char *p;
+        int r;
+
+        assert(key);
+
+        r = proc_cmdline(&line);
+        if (r < 0)
+                return r;
+
+        p = line;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                const char *e;
+
+                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                /* Filter out arguments that are intended only for the
+                 * initrd */
+                if (!in_initrd() && startswith(word, "rd."))
+                        continue;
+
+                if (value) {
+                        e = startswith(word, key);
+                        if (!e)
+                                continue;
+
+                        r = free_and_strdup(&ret, e);
+                        if (r < 0)
+                                return r;
+
+                        found = true;
+                } else {
+                        if (streq(word, key))
+                                found = true;
+                }
+        }
+
+        if (value) {
+                *value = ret;
+                ret = NULL;
+        }
+
+        return found;
+
+}
+
+int shall_restore_state(void) {
+        _cleanup_free_ char *value = NULL;
+        int r;
+
+        r = get_proc_cmdline_key("systemd.restore_state=", &value);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return true;
+
+        return parse_boolean(value);
+}
+
+static const char * const rlmap[] = {
+        "emergency", SPECIAL_EMERGENCY_TARGET,
+        "-b",        SPECIAL_EMERGENCY_TARGET,
+        "rescue",    SPECIAL_RESCUE_TARGET,
+        "single",    SPECIAL_RESCUE_TARGET,
+        "-s",        SPECIAL_RESCUE_TARGET,
+        "s",         SPECIAL_RESCUE_TARGET,
+        "S",         SPECIAL_RESCUE_TARGET,
+        "1",         SPECIAL_RESCUE_TARGET,
+        "2",         SPECIAL_MULTI_USER_TARGET,
+        "3",         SPECIAL_MULTI_USER_TARGET,
+        "4",         SPECIAL_MULTI_USER_TARGET,
+        "5",         SPECIAL_GRAPHICAL_TARGET,
+};
+
+const char* runlevel_to_target(const char *word) {
+        size_t i;
+
+        if (!word)
+                return NULL;
+
+        for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
+                if (streq(word, rlmap[i]))
+                        return rlmap[i+1];
+
+        return NULL;
+}
diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h
new file mode 100644 (file)
index 0000000..ce6e849
--- /dev/null
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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/>.
+***/
+
+int proc_cmdline(char **ret);
+int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
+int get_proc_cmdline_key(const char *parameter, char **value);
+
+int shall_restore_state(void);
+const char* runlevel_to_target(const char *rl);
index d8a94a457286c49cc0f0b6b02f4b875ae7726408..7631928d5f11a0ba9c73930412204edacc534c12 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
-#include <sys/types.h>
-#include <string.h>
-#include <stdio.h>
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
-#include <unistd.h>
-#include <sys/wait.h>
+#include <sched.h>
 #include <signal.h>
-#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "util.h"
+#include "fs-util.h"
+#include "ioprio.h"
 #include "log.h"
-#include "signal-util.h"
 #include "process-util.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
 
 int get_process_state(pid_t pid) {
         const char *p;
@@ -174,6 +185,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
         return 0;
 }
 
+void rename_process(const char name[8]) {
+        assert(name);
+
+        /* This is a like a poor man's setproctitle(). It changes the
+         * comm field, argv[0], and also the glibc's internally used
+         * name of the process. For the first one a limit of 16 chars
+         * applies, to the second one usually one of 10 (i.e. length
+         * of "/sbin/init"), to the third one one of 7 (i.e. length of
+         * "systemd"). If you pass a longer string it will be
+         * truncated */
+
+        prctl(PR_SET_NAME, name);
+
+        if (program_invocation_name)
+                strncpy(program_invocation_name, name, strlen(program_invocation_name));
+
+        if (saved_argc > 0) {
+                int i;
+
+                if (saved_argv[0])
+                        strncpy(saved_argv[0], name, strlen(saved_argv[0]));
+
+                for (i = 1; i < saved_argc; i++) {
+                        if (!saved_argv[i])
+                                break;
+
+                        memzero(saved_argv[i], strlen(saved_argv[i]));
+                }
+        }
+}
+
 int is_kernel_thread(pid_t pid) {
         const char *p;
         size_t count;
@@ -364,7 +406,7 @@ int get_process_environ(pid_t pid, char **env) {
         return 0;
 }
 
-int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+int get_process_ppid(pid_t pid, pid_t *_ppid) {
         int r;
         _cleanup_free_ char *line = NULL;
         long unsigned ppid;
@@ -476,6 +518,16 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
         return -EPROTO;
 }
 
+void sigkill_wait(pid_t *pid) {
+        if (!pid)
+                return;
+        if (*pid <= 1)
+                return;
+
+        if (kill(*pid, SIGKILL) > 0)
+                (void) wait_for_terminate(*pid, NULL);
+}
+
 int kill_and_sigcont(pid_t pid, int sig) {
         int r;
 
@@ -547,9 +599,12 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
 bool pid_is_unwaited(pid_t pid) {
         /* Checks whether a PID is still valid at all, including a zombie */
 
-        if (pid <= 0)
+        if (pid < 0)
                 return false;
 
+        if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
+                return true;
+
         if (kill(pid, 0) >= 0)
                 return true;
 
@@ -561,12 +616,141 @@ bool pid_is_alive(pid_t pid) {
 
         /* Checks whether a PID is still valid and not a zombie */
 
-        if (pid <= 0)
+        if (pid < 0)
                 return false;
 
+        if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
+                return true;
+
         r = get_process_state(pid);
         if (r == -ESRCH || r == 'Z')
                 return false;
 
         return true;
 }
+
+bool is_main_thread(void) {
+        static thread_local int cached = 0;
+
+        if (_unlikely_(cached == 0))
+                cached = getpid() == gettid() ? 1 : -1;
+
+        return cached > 0;
+}
+
+noreturn void freeze(void) {
+
+        /* Make sure nobody waits for us on a socket anymore */
+        close_all_fds(NULL, 0);
+
+        sync();
+
+        for (;;)
+                pause();
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+        return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}
+
+unsigned long personality_from_string(const char *p) {
+
+        /* Parse a personality specifier. We introduce our own
+         * identifiers that indicate specific ABIs, rather than just
+         * hints regarding the register size, since we want to keep
+         * things open for multiple locally supported ABIs for the
+         * same register size. We try to reuse the ABI identifiers
+         * used by libseccomp. */
+
+#if defined(__x86_64__)
+
+        if (streq(p, "x86"))
+                return PER_LINUX32;
+
+        if (streq(p, "x86-64"))
+                return PER_LINUX;
+
+#elif defined(__i386__)
+
+        if (streq(p, "x86"))
+                return PER_LINUX;
+
+#elif defined(__s390x__)
+
+        if (streq(p, "s390"))
+                return PER_LINUX32;
+
+        if (streq(p, "s390x"))
+                return PER_LINUX;
+
+#elif defined(__s390__)
+
+        if (streq(p, "s390"))
+                return PER_LINUX;
+#endif
+
+        return PERSONALITY_INVALID;
+}
+
+const char* personality_to_string(unsigned long p) {
+
+#if defined(__x86_64__)
+
+        if (p == PER_LINUX32)
+                return "x86";
+
+        if (p == PER_LINUX)
+                return "x86-64";
+
+#elif defined(__i386__)
+
+        if (p == PER_LINUX)
+                return "x86";
+
+#elif defined(__s390x__)
+
+        if (p == PER_LINUX)
+                return "s390x";
+
+        if (p == PER_LINUX32)
+                return "s390";
+
+#elif defined(__s390__)
+
+        if (p == PER_LINUX)
+                return "s390";
+
+#endif
+
+        return NULL;
+}
+
+static const char *const ioprio_class_table[] = {
+        [IOPRIO_CLASS_NONE] = "none",
+        [IOPRIO_CLASS_RT] = "realtime",
+        [IOPRIO_CLASS_BE] = "best-effort",
+        [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
+
+static const char *const sigchld_code_table[] = {
+        [CLD_EXITED] = "exited",
+        [CLD_KILLED] = "killed",
+        [CLD_DUMPED] = "dumped",
+        [CLD_TRAPPED] = "trapped",
+        [CLD_STOPPED] = "stopped",
+        [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char* const sched_policy_table[] = {
+        [SCHED_OTHER] = "other",
+        [SCHED_BATCH] = "batch",
+        [SCHED_IDLE] = "idle",
+        [SCHED_FIFO] = "fifo",
+        [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
index 07431d043b79df374a81c873332e9c0475260ca7..72633ebf70581ff29ec5d26e5aa3c115cdfb2c6d 100644 (file)
@@ -27,6 +27,7 @@
 #include <signal.h>
 
 #include "formats-util.h"
+#include "macro.h"
 
 #define procfs_file_alloca(pid, field)                                  \
         ({                                                              \
@@ -51,15 +52,48 @@ int get_process_capeff(pid_t pid, char **capeff);
 int get_process_cwd(pid_t pid, char **cwd);
 int get_process_root(pid_t pid, char **root);
 int get_process_environ(pid_t pid, char **environ);
+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)
+
 int kill_and_sigcont(pid_t pid, int sig);
-pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
+
 void rename_process(const char name[8]);
 int is_kernel_thread(pid_t pid);
+
 int getenv_for_pid(pid_t pid, const char *field, char **_value);
 
 bool pid_is_alive(pid_t pid);
 bool pid_is_unwaited(pid_t pid);
+
+bool is_main_thread(void);
+
+noreturn void freeze(void);
+
+bool oom_score_adjust_is_valid(int oa);
+
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
+unsigned long personality_from_string(const char *p);
+const char *personality_to_string(unsigned long);
+
+int ioprio_class_to_string_alloc(int i, char **s);
+int ioprio_class_from_string(const char *s);
+
+const char *sigchld_code_to_string(int i) _const_;
+int sigchld_code_from_string(const char *s) _pure_;
+
+int sched_policy_to_string_alloc(int i, char **s);
+int sched_policy_from_string(const char *s);
+
+#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
+#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
index b230044f50994a12070c3a842c18563148211438..2f5c16e2afbdc7fc3230d7111007960ce8e7b996 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdint.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
-#include <time.h>
+#include <linux/random.h>
+#include <stdint.h>
 #ifdef HAVE_SYS_AUXV_H
 #include <sys/auxv.h>
 #endif
-#include <linux/random.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
 
+#include "fd-util.h"
+#include "io-util.h"
+#include "missing.h"
 #include "random-util.h"
 #include "time-util.h"
-#include "missing.h"
 #include "util.h"
 
 int dev_urandom(void *p, size_t n) {
index 478fc43a38858ac34ff38b6564a4e49e04edd71a..bf757cbc48e011ec39da9356111b207700b0b2fb 100644 (file)
 
 #include <string.h>
 
+#include "alloc-util.h"
 #include "macro.h"
-#include "util.h"
 #include "replace-var.h"
-#include "def.h"
+#include "string-util.h"
+#include "util.h"
 
 /*
  * Generic infrastructure for replacing @FOO@ style variables in
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
new file mode 100644 (file)
index 0000000..2627c81
--- /dev/null
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "missing.h"
+#include "rlimit-util.h"
+#include "string-table.h"
+#include "util.h"
+
+int setrlimit_closest(int resource, const struct rlimit *rlim) {
+        struct rlimit highest, fixed;
+
+        assert(rlim);
+
+        if (setrlimit(resource, rlim) >= 0)
+                return 0;
+
+        if (errno != EPERM)
+                return -errno;
+
+        /* So we failed to set the desired setrlimit, then let's try
+         * to get as close as we can */
+        assert_se(getrlimit(resource, &highest) == 0);
+
+        fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
+        fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
+
+        if (setrlimit(resource, &fixed) < 0)
+                return -errno;
+
+        return 0;
+}
+
+static const char* const rlimit_table[_RLIMIT_MAX] = {
+        [RLIMIT_CPU] = "LimitCPU",
+        [RLIMIT_FSIZE] = "LimitFSIZE",
+        [RLIMIT_DATA] = "LimitDATA",
+        [RLIMIT_STACK] = "LimitSTACK",
+        [RLIMIT_CORE] = "LimitCORE",
+        [RLIMIT_RSS] = "LimitRSS",
+        [RLIMIT_NOFILE] = "LimitNOFILE",
+        [RLIMIT_AS] = "LimitAS",
+        [RLIMIT_NPROC] = "LimitNPROC",
+        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
+        [RLIMIT_LOCKS] = "LimitLOCKS",
+        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
+        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
+        [RLIMIT_NICE] = "LimitNICE",
+        [RLIMIT_RTPRIO] = "LimitRTPRIO",
+        [RLIMIT_RTTIME] = "LimitRTTIME"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
similarity index 71%
rename from src/core/snapshot.h
rename to src/basic/rlimit-util.h
index 97747e18bdfd35cae3df9b41332de0fff2a6564f..262f86dd046072d937a4a2ab2daec089237b2286 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-typedef struct Snapshot Snapshot;
+#include <sys/resource.h>
 
-struct Snapshot {
-        Unit meta;
+#include "macro.h"
 
-        SnapshotState state, deserialized_state;
+const char *rlimit_to_string(int i) _const_;
+int rlimit_from_string(const char *s) _pure_;
 
-        bool cleanup;
-};
+int setrlimit_closest(int resource, const struct rlimit *rlim);
 
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s);
-void snapshot_remove(Snapshot *s);
+#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
index dbbe8176843e01a7d74b963328fc4b39583fbfd8..8ec7dd75ee19d31d2d8c6a60974420018d4dcc68 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "path-util.h"
 #include "btrfs-util.h"
+#include "fd-util.h"
+#include "mount-util.h"
+#include "path-util.h"
 #include "rm-rf.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
 
 int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
         _cleanup_closedir_ DIR *d = NULL;
@@ -120,7 +124,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
 
                                 /* This could be a subvolume, try to remove it */
 
-                                r = btrfs_subvol_remove_fd(fd, de->d_name, true);
+                                r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                                 if (r < 0) {
                                         if (r != -ENOTTY && r != -EINVAL) {
                                                 if (ret == 0)
@@ -178,7 +182,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
 
         if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
                 /* Try to remove as subvolume first */
-                r = btrfs_subvol_remove(path, true);
+                r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                 if (r >= 0)
                         return r;
 
index 747e6f4dbb3af7772ce043fdafb6835fad41322a..a821a3d5bb63e930eb14ca91ec562100725ae6e6 100644 (file)
@@ -29,6 +29,7 @@
 #include <selinux/context.h>
 #endif
 
+#include "alloc-util.h"
 #include "strv.h"
 #include "path-util.h"
 #include "selinux-util.h"
@@ -171,15 +172,15 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
 int mac_selinux_apply(const char *path, const char *label) {
 
 #ifdef HAVE_SELINUX
-        assert(path);
-        assert(label);
-
         if (!mac_selinux_use())
                 return 0;
 
+        assert(path);
+        assert(label);
+
         if (setfilecon(path, (security_context_t) label) < 0) {
                 log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
-                if (security_getenforce() == 1)
+                if (security_getenforce() > 0)
                         return -errno;
         }
 #endif
@@ -312,10 +313,10 @@ char* mac_selinux_free(char *label) {
 }
 
 int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
-        int r = 0;
 
 #ifdef HAVE_SELINUX
         _cleanup_security_context_free_ security_context_t filecon = NULL;
+        int r;
 
         assert(path);
 
@@ -325,34 +326,33 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
         if (path_is_absolute(path))
                 r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
         else {
-                _cleanup_free_ char *newpath;
+                _cleanup_free_ char *newpath = NULL;
 
-                newpath = path_make_absolute_cwd(path);
-                if (!newpath)
-                        return -ENOMEM;
+                r = path_make_absolute_cwd(path, &newpath);
+                if (r < 0)
+                        return r;
 
                 r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
         }
 
-        /* No context specified by the policy? Proceed without setting it. */
-        if (r < 0 && errno == ENOENT)
-                return 0;
+        if (r < 0) {
+                /* No context specified by the policy? Proceed without setting it. */
+                if (errno == ENOENT)
+                        return 0;
 
-        if (r < 0)
-                r = -errno;
-        else {
-                r = setfscreatecon(filecon);
-                if (r < 0) {
-                        log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
-                        r = -errno;
-                }
+                log_enforcing("Failed to determine SELinux security context for %s: %m", path);
+        } else {
+                if (setfscreatecon(filecon) >= 0)
+                        return 0; /* Success! */
+
+                log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
         }
 
-        if (r < 0 && security_getenforce() == 0)
-                r = 0;
-#endif
+        if (security_getenforce() > 0)
+                return -errno;
 
-        return r;
+#endif
+        return 0;
 }
 
 void mac_selinux_create_file_clear(void) {
@@ -405,6 +405,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
 #ifdef HAVE_SELINUX
         _cleanup_security_context_free_ security_context_t fcon = NULL;
         const struct sockaddr_un *un;
+        bool context_changed = false;
         char *path;
         int r;
 
@@ -420,7 +421,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
                 goto skipped;
 
         /* Filter out anonymous sockets */
-        if (addrlen < sizeof(sa_family_t) + 1)
+        if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
                 goto skipped;
 
         /* Filter out abstract namespace sockets */
@@ -433,36 +434,44 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
         if (path_is_absolute(path))
                 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
         else {
-                _cleanup_free_ char *newpath;
+                _cleanup_free_ char *newpath = NULL;
 
-                newpath = path_make_absolute_cwd(path);
-                if (!newpath)
-                        return -ENOMEM;
+                r = path_make_absolute_cwd(path, &newpath);
+                if (r < 0)
+                        return r;
 
                 r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
         }
 
-        if (r == 0)
-                r = setfscreatecon(fcon);
+        if (r < 0) {
+                /* No context specified by the policy? Proceed without setting it */
+                if (errno == ENOENT)
+                        goto skipped;
 
-        if (r < 0 && errno != ENOENT) {
-                log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
+                log_enforcing("Failed to determine SELinux security context for %s: %m", path);
+                if (security_getenforce() > 0)
+                        return -errno;
 
-                if (security_getenforce() == 1) {
-                        r = -errno;
-                        goto finish;
-                }
+        } else {
+                if (setfscreatecon(fcon) < 0) {
+                        log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
+                        if (security_getenforce() > 0)
+                                return -errno;
+                } else
+                        context_changed = true;
         }
 
-        r = bind(fd, addr, addrlen);
-        if (r < 0)
-                r = -errno;
+        r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
+
+        if (context_changed)
+                setfscreatecon(NULL);
 
-finish:
-        setfscreatecon(NULL);
         return r;
 
 skipped:
 #endif
-        return bind(fd, addr, addrlen) < 0 ? -errno : 0;
+        if (bind(fd, addr, addrlen) < 0)
+                return -errno;
+
+        return 0;
 }
index 90abe8af816d2df154d6ddbc123d0821475bbe87..8038bc891d52a3e963dca591da7394db9207814b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "parse-util.h"
 #include "signal-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
 
 int reset_all_signal_handlers(void) {
         static const struct sigaction sa = {
@@ -266,3 +269,7 @@ int signal_from_string_try_harder(const char *s) {
 
         return signo;
 }
+
+void nop_signal_handler(int sig) {
+        /* nothing here */
+}
index 5e6eb50b07f53ebabdf3d545c5896c5b54bfe6de..e7393e2dacaf2157cf7a34d621bca306ebc85897 100644 (file)
@@ -39,3 +39,5 @@ const char *signal_to_string(int i) _const_;
 int signal_from_string(const char *s) _pure_;
 
 int signal_from_string_try_harder(const char *s);
+
+void nop_signal_handler(int sig);
index 5f570ff02ae11c27fa620f05ab519230d86c6296..fcc046098dcd4a8ecf83ac15cfced98660220141 100644 (file)
 
 #include <sys/xattr.h>
 
-#include "util.h"
-#include "process-util.h"
-#include "path-util.h"
+#include "alloc-util.h"
 #include "fileio.h"
+#include "path-util.h"
+#include "process-util.h"
 #include "smack-util.h"
+#include "string-table.h"
+#include "util.h"
+#include "xattr-util.h"
 
 #ifdef HAVE_SMACK
 bool mac_smack_use(void) {
index 937124cc022c8ff41b20da2dad91aa67de510eae..e5d4efc719e61326d7dab7bafdc9f58898848215 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
-#include <unistd.h>
 #include <errno.h>
-#include <sys/stat.h>
 #include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "macro.h"
-#include "util.h"
-#include "mkdir.h"
 #include "missing.h"
+#include "mkdir.h"
 #include "selinux-util.h"
 #include "socket-util.h"
+#include "util.h"
 
 int socket_address_listen(
                 const SocketAddress *a,
index 8fd3149276e555a1fcad87045495902ecb53e0d8..1acab1ef95bab65534dad3bf0717a1b5e083235e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
 #include <arpa/inet.h>
-#include <stdio.h>
+#include <errno.h>
 #include <net/if.h>
-#include <sys/types.h>
-#include <stddef.h>
 #include <netdb.h>
+#include <netinet/ip.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
 #include "macro.h"
+#include "missing.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "util.h"
 #include "socket-util.h"
-#include "missing.h"
-#include "fileio.h"
-#include "formats-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
 
 int socket_address_parse(SocketAddress *a, const char *s) {
         char *e, *n;
@@ -749,21 +756,182 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b
         return false;
 }
 
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
-        assert(addr);
-        assert(buffer);
+int fd_inc_sndbuf(int fd, size_t n) {
+        int r, value;
+        socklen_t l = sizeof(value);
 
-        /* Like ether_ntoa() but uses %02x instead of %x to print
-         * ethernet addresses, which makes them look less funny. Also,
-         * doesn't use a static buffer. */
+        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
+        if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+                return 0;
 
-        sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
-                addr->ether_addr_octet[0],
-                addr->ether_addr_octet[1],
-                addr->ether_addr_octet[2],
-                addr->ether_addr_octet[3],
-                addr->ether_addr_octet[4],
-                addr->ether_addr_octet[5]);
+        /* If we have the privileges we will ignore the kernel limit. */
+
+        value = (int) n;
+        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+                        return -errno;
+
+        return 1;
+}
+
+int fd_inc_rcvbuf(int fd, size_t n) {
+        int r, value;
+        socklen_t l = sizeof(value);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
+        if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+                return 0;
+
+        /* If we have the privileges we will ignore the kernel limit. */
+
+        value = (int) n;
+        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
+                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+                        return -errno;
+        return 1;
+}
+
+static const char* const ip_tos_table[] = {
+        [IPTOS_LOWDELAY] = "low-delay",
+        [IPTOS_THROUGHPUT] = "throughput",
+        [IPTOS_RELIABILITY] = "reliability",
+        [IPTOS_LOWCOST] = "low-cost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
+
+int getpeercred(int fd, struct ucred *ucred) {
+        socklen_t n = sizeof(struct ucred);
+        struct ucred u;
+        int r;
+
+        assert(fd >= 0);
+        assert(ucred);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
+        if (r < 0)
+                return -errno;
+
+        if (n != sizeof(struct ucred))
+                return -EIO;
+
+        /* Check if the data is actually useful and not suppressed due
+         * to namespacing issues */
+        if (u.pid <= 0)
+                return -ENODATA;
+        if (u.uid == UID_INVALID)
+                return -ENODATA;
+        if (u.gid == GID_INVALID)
+                return -ENODATA;
+
+        *ucred = u;
+        return 0;
+}
+
+int getpeersec(int fd, char **ret) {
+        socklen_t n = 64;
+        char *s;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        s = new0(char, n);
+        if (!s)
+                return -ENOMEM;
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+        if (r < 0) {
+                free(s);
+
+                if (errno != ERANGE)
+                        return -errno;
+
+                s = new0(char, n);
+                if (!s)
+                        return -ENOMEM;
+
+                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+                if (r < 0) {
+                        free(s);
+                        return -errno;
+                }
+        }
+
+        if (isempty(s)) {
+                free(s);
+                return -EOPNOTSUPP;
+        }
+
+        *ret = s;
+        return 0;
+}
+
+int send_one_fd(int transport_fd, int fd, int flags) {
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int))];
+        } control = {};
+        struct msghdr mh = {
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+        };
+        struct cmsghdr *cmsg;
+
+        assert(transport_fd >= 0);
+        assert(fd >= 0);
+
+        cmsg = CMSG_FIRSTHDR(&mh);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+        memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+        mh.msg_controllen = CMSG_SPACE(sizeof(int));
+        if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int receive_one_fd(int transport_fd, int flags) {
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(int))];
+        } control = {};
+        struct msghdr mh = {
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+        };
+        struct cmsghdr *cmsg, *found = NULL;
+
+        assert(transport_fd >= 0);
+
+        /*
+         * Receive a single FD via @transport_fd. We don't care for
+         * the transport-type. We retrieve a single FD at most, so for
+         * packet-based transports, the caller must ensure to send
+         * only a single FD per packet.  This is best used in
+         * combination with send_one_fd().
+         */
+
+        if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
+                return -errno;
+
+        CMSG_FOREACH(cmsg, &mh) {
+                if (cmsg->cmsg_level == SOL_SOCKET &&
+                    cmsg->cmsg_type == SCM_RIGHTS &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+                        assert(!found);
+                        found = cmsg;
+                        break;
+                }
+        }
+
+        if (!found) {
+                cmsg_close_all(&mh);
+                return -EIO;
+        }
 
-        return buffer;
+        return *(int*) CMSG_DATA(found);
 }
index 6b0ce7836f599bd957c4bfd24c571da9caaa0234..c60f2556af840e86806adbea785ce7a86a30d239 100644 (file)
@@ -116,6 +116,17 @@ int netlink_family_from_string(const char *s) _pure_;
 
 bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
 
-#define ETHER_ADDR_TO_STRING_MAX (3*6)
+int fd_inc_sndbuf(int fd, size_t n);
+int fd_inc_rcvbuf(int fd, size_t n);
 
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
+int ip_tos_to_string_alloc(int i, char **s);
+int ip_tos_from_string(const char *s);
+
+int getpeercred(int fd, struct ucred *ucred);
+int getpeersec(int fd, char **ret);
+
+int send_one_fd(int transport_fd, int fd, int flags);
+int receive_one_fd(int transport_fd, int flags);
+
+#define CMSG_FOREACH(cmsg, mh)                                          \
+        for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
new file mode 100644 (file)
index 0000000..3bc66b3
--- /dev/null
@@ -0,0 +1,216 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010-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 <fcntl.h>
+#include <linux/magic.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "stat-util.h"
+#include "string-util.h"
+
+int is_symlink(const char *path) {
+        struct stat info;
+
+        assert(path);
+
+        if (lstat(path, &info) < 0)
+                return -errno;
+
+        return !!S_ISLNK(info.st_mode);
+}
+
+int is_dir(const char* path, bool follow) {
+        struct stat st;
+        int r;
+
+        assert(path);
+
+        if (follow)
+                r = stat(path, &st);
+        else
+                r = lstat(path, &st);
+        if (r < 0)
+                return -errno;
+
+        return !!S_ISDIR(st.st_mode);
+}
+
+int is_device_node(const char *path) {
+        struct stat info;
+
+        assert(path);
+
+        if (lstat(path, &info) < 0)
+                return -errno;
+
+        return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
+}
+
+int dir_is_empty(const char *path) {
+        _cleanup_closedir_ DIR *d;
+        struct dirent *de;
+
+        d = opendir(path);
+        if (!d)
+                return -errno;
+
+        FOREACH_DIRENT(de, d, return -errno)
+                return 0;
+
+        return 1;
+}
+
+bool null_or_empty(struct stat *st) {
+        assert(st);
+
+        if (S_ISREG(st->st_mode) && st->st_size <= 0)
+                return true;
+
+        /* We don't want to hardcode the major/minor of /dev/null,
+         * hence we do a simpler "is this a device node?" check. */
+
+        if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
+                return true;
+
+        return false;
+}
+
+int null_or_empty_path(const char *fn) {
+        struct stat st;
+
+        assert(fn);
+
+        if (stat(fn, &st) < 0)
+                return -errno;
+
+        return null_or_empty(&st);
+}
+
+int null_or_empty_fd(int fd) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        return null_or_empty(&st);
+}
+
+int path_is_read_only_fs(const char *path) {
+        struct statvfs st;
+
+        assert(path);
+
+        if (statvfs(path, &st) < 0)
+                return -errno;
+
+        if (st.f_flag & ST_RDONLY)
+                return true;
+
+        /* On NFS, statvfs() might not reflect whether we can actually
+         * write to the remote share. Let's try again with
+         * access(W_OK) which is more reliable, at least sometimes. */
+        if (access(path, W_OK) < 0 && errno == EROFS)
+                return true;
+
+        return false;
+}
+
+int path_is_os_tree(const char *path) {
+        char *p;
+        int r;
+
+        assert(path);
+
+        /* We use /usr/lib/os-release as flag file if something is an OS */
+        p = strjoina(path, "/usr/lib/os-release");
+        r = access(p, F_OK);
+        if (r >= 0)
+                return 1;
+
+        /* Also check for the old location in /etc, just in case. */
+        p = strjoina(path, "/etc/os-release");
+        r = access(p, F_OK);
+
+        return r >= 0;
+}
+
+int files_same(const char *filea, const char *fileb) {
+        struct stat a, b;
+
+        assert(filea);
+        assert(fileb);
+
+        if (stat(filea, &a) < 0)
+                return -errno;
+
+        if (stat(fileb, &b) < 0)
+                return -errno;
+
+        return a.st_dev == b.st_dev &&
+               a.st_ino == b.st_ino;
+}
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
+        assert(s);
+        assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
+
+        return F_TYPE_EQUAL(s->f_type, magic_value);
+}
+
+int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+        struct statfs s;
+
+        if (fstatfs(fd, &s) < 0)
+                return -errno;
+
+        return is_fs_type(&s, magic_value);
+}
+
+int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+        _cleanup_close_ int fd = -1;
+
+        fd = open(path, O_RDONLY);
+        if (fd < 0)
+                return -errno;
+
+        return fd_check_fstype(fd, magic_value);
+}
+
+bool is_temporary_fs(const struct statfs *s) {
+    return is_fs_type(s, TMPFS_MAGIC) ||
+           is_fs_type(s, RAMFS_MAGIC);
+}
+
+int fd_is_temporary_fs(int fd) {
+        struct statfs s;
+
+        if (fstatfs(fd, &s) < 0)
+                return -errno;
+
+        return is_temporary_fs(&s);
+}
diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
new file mode 100644 (file)
index 0000000..909b220
--- /dev/null
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010-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 <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#include "macro.h"
+
+int is_symlink(const char *path);
+int is_dir(const char *path, bool follow);
+int is_device_node(const char *path);
+
+int dir_is_empty(const char *path);
+
+static inline int dir_is_populated(const char *path) {
+        int r;
+        r = dir_is_empty(path);
+        if (r < 0)
+                return r;
+        return !r;
+}
+
+bool null_or_empty(struct stat *st) _pure_;
+int null_or_empty_path(const char *fn);
+int null_or_empty_fd(int fd);
+
+int path_is_read_only_fs(const char *path);
+int path_is_os_tree(const char *path);
+
+int files_same(const char *filea, const char *fileb);
+
+/* The .f_type field of struct statfs is really weird defined on
+ * different archs. Let's use our own type we know is sufficiently
+ * larger to store the possible values. */
+typedef long statfs_f_type_t;
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
+int fd_check_fstype(int fd, statfs_f_type_t magic_value);
+int path_check_fstype(const char *path, statfs_f_type_t magic_value);
+
+bool is_temporary_fs(const struct statfs *s) _pure_;
+int fd_is_temporary_fs(int fd);
+
+/* Because statfs.t_type can be int on some architectures, we have to cast
+ * the const magic to the type, otherwise the compiler warns about
+ * signed/unsigned comparison, because the magic can be 32 bit unsigned.
+ */
+#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h
new file mode 100644 (file)
index 0000000..b36e8a9
--- /dev/null
@@ -0,0 +1,78 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <printf.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+#define xsprintf(buf, fmt, ...) \
+        assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough")
+
+
+#define VA_FORMAT_ADVANCE(format, ap)                                   \
+do {                                                                    \
+        int _argtypes[128];                                             \
+        size_t _i, _k;                                                  \
+        _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
+        assert(_k < ELEMENTSOF(_argtypes));                             \
+        for (_i = 0; _i < _k; _i++) {                                   \
+                if (_argtypes[_i] & PA_FLAG_PTR)  {                     \
+                        (void) va_arg(ap, void*);                       \
+                        continue;                                       \
+                }                                                       \
+                                                                        \
+                switch (_argtypes[_i]) {                                \
+                case PA_INT:                                            \
+                case PA_INT|PA_FLAG_SHORT:                              \
+                case PA_CHAR:                                           \
+                        (void) va_arg(ap, int);                         \
+                        break;                                          \
+                case PA_INT|PA_FLAG_LONG:                               \
+                        (void) va_arg(ap, long int);                    \
+                        break;                                          \
+                case PA_INT|PA_FLAG_LONG_LONG:                          \
+                        (void) va_arg(ap, long long int);               \
+                        break;                                          \
+                case PA_WCHAR:                                          \
+                        (void) va_arg(ap, wchar_t);                     \
+                        break;                                          \
+                case PA_WSTRING:                                        \
+                case PA_STRING:                                         \
+                case PA_POINTER:                                        \
+                        (void) va_arg(ap, void*);                       \
+                        break;                                          \
+                case PA_FLOAT:                                          \
+                case PA_DOUBLE:                                         \
+                        (void) va_arg(ap, double);                      \
+                        break;                                          \
+                case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:                     \
+                        (void) va_arg(ap, long double);                 \
+                        break;                                          \
+                default:                                                \
+                        assert_not_reached("Unknown format string argument."); \
+                }                                                       \
+        }                                                               \
+} while(false)
index 01a076c2baf204e50f170bbcd2fbca44ed527f76..f4f702a05abd1775b7be27bb3ea26b50bfb47321 100644 (file)
@@ -22,8 +22,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "strbuf.h"
+#include "util.h"
 
 /*
  * Strbuf stores given strings in a single continuous allocated memory
diff --git a/src/basic/string-table.c b/src/basic/string-table.c
new file mode 100644 (file)
index 0000000..a860324
--- /dev/null
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "string-table.h"
+
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
+        size_t i;
+
+        if (!key)
+                return -1;
+
+        for (i = 0; i < len; ++i)
+                if (streq_ptr(table[i], key))
+                        return (ssize_t) i;
+
+        return -1;
+}
diff --git a/src/basic/string-table.h b/src/basic/string-table.h
new file mode 100644 (file)
index 0000000..51b6007
--- /dev/null
@@ -0,0 +1,88 @@
+
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "macro.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
+
+/* For basic lookup tables with strictly enumerated entries */
+#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
+        scope const char *name##_to_string(type i) {                    \
+                if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
+                        return NULL;                                    \
+                return name##_table[i];                                 \
+        }
+
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)        \
+        scope type name##_from_string(const char *s) {                  \
+                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(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)
+
+/* 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) {                \
+                char *s;                                                \
+                if (i < 0 || i > max)                                   \
+                        return -ERANGE;                                 \
+                if (i < (type) ELEMENTSOF(name##_table)) {              \
+                        s = strdup(name##_table[i]);                    \
+                        if (!s)                                         \
+                                return -ENOMEM;                         \
+                } else {                                                \
+                        if (asprintf(&s, "%i", i) < 0)                  \
+                                return -ENOMEM;                         \
+                }                                                       \
+                *str = s;                                               \
+                return 0;                                               \
+        }                                                               \
+        type name##_from_string(const char *s) {                        \
+                type i;                                                 \
+                unsigned u = 0;                                         \
+                if (!s)                                                 \
+                        return (type) -1;                               \
+                for (i = 0; i < (type) ELEMENTSOF(name##_table); i++)   \
+                        if (streq_ptr(name##_table[i], s))              \
+                                return i;                               \
+                if (safe_atou(s, &u) >= 0 && u <= max)                  \
+                        return (type) u;                                \
+                return (type) -1;                                       \
+        }                                                               \
+        struct __useless_struct_to_allow_trailing_semicolon__
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
new file mode 100644 (file)
index 0000000..6006767
--- /dev/null
@@ -0,0 +1,800 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 "gunicode.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int strcmp_ptr(const char *a, const char *b) {
+
+        /* Like strcmp(), but tries to make sense of NULL pointers */
+        if (a && b)
+                return strcmp(a, b);
+
+        if (!a && b)
+                return -1;
+
+        if (a && !b)
+                return 1;
+
+        return 0;
+}
+
+char* endswith(const char *s, const char *postfix) {
+        size_t sl, pl;
+
+        assert(s);
+        assert(postfix);
+
+        sl = strlen(s);
+        pl = strlen(postfix);
+
+        if (pl == 0)
+                return (char*) s + sl;
+
+        if (sl < pl)
+                return NULL;
+
+        if (memcmp(s + sl - pl, postfix, pl) != 0)
+                return NULL;
+
+        return (char*) s + sl - pl;
+}
+
+char* endswith_no_case(const char *s, const char *postfix) {
+        size_t sl, pl;
+
+        assert(s);
+        assert(postfix);
+
+        sl = strlen(s);
+        pl = strlen(postfix);
+
+        if (pl == 0)
+                return (char*) s + sl;
+
+        if (sl < pl)
+                return NULL;
+
+        if (strcasecmp(s + sl - pl, postfix) != 0)
+                return NULL;
+
+        return (char*) s + sl - pl;
+}
+
+char* first_word(const char *s, const char *word) {
+        size_t sl, wl;
+        const char *p;
+
+        assert(s);
+        assert(word);
+
+        /* Checks if the string starts with the specified word, either
+         * followed by NUL or by whitespace. Returns a pointer to the
+         * NUL or the first character after the whitespace. */
+
+        sl = strlen(s);
+        wl = strlen(word);
+
+        if (sl < wl)
+                return NULL;
+
+        if (wl == 0)
+                return (char*) s;
+
+        if (memcmp(s, word, wl) != 0)
+                return NULL;
+
+        p = s + wl;
+        if (*p == 0)
+                return (char*) p;
+
+        if (!strchr(WHITESPACE, *p))
+                return NULL;
+
+        p += strspn(p, WHITESPACE);
+        return (char*) p;
+}
+
+static size_t strcspn_escaped(const char *s, const char *reject) {
+        bool escaped = false;
+        int n;
+
+        for (n=0; s[n]; n++) {
+                if (escaped)
+                        escaped = false;
+                else if (s[n] == '\\')
+                        escaped = true;
+                else if (strchr(reject, s[n]))
+                        break;
+        }
+
+        /* if s ends in \, return index of previous char */
+        return n - escaped;
+}
+
+/* Split a string into words. */
+const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+        const char *current;
+
+        current = *state;
+
+        if (!*current) {
+                assert(**state == '\0');
+                return NULL;
+        }
+
+        current += strspn(current, separator);
+        if (!*current) {
+                *state = current;
+                return NULL;
+        }
+
+        if (quoted && strchr("\'\"", *current)) {
+                char quotechars[2] = {*current, '\0'};
+
+                *l = strcspn_escaped(current + 1, quotechars);
+                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+                        /* right quote missing or garbage at the end */
+                        *state = current;
+                        return NULL;
+                }
+                *state = current++ + *l + 2;
+        } else if (quoted) {
+                *l = strcspn_escaped(current, separator);
+                if (current[*l] && !strchr(separator, current[*l])) {
+                        /* unfinished escape */
+                        *state = current;
+                        return NULL;
+                }
+                *state = current + *l;
+        } else {
+                *l = strcspn(current, separator);
+                *state = current + *l;
+        }
+
+        return current;
+}
+
+char *strnappend(const char *s, const char *suffix, size_t b) {
+        size_t a;
+        char *r;
+
+        if (!s && !suffix)
+                return strdup("");
+
+        if (!s)
+                return strndup(suffix, b);
+
+        if (!suffix)
+                return strdup(s);
+
+        assert(s);
+        assert(suffix);
+
+        a = strlen(s);
+        if (b > ((size_t) -1) - a)
+                return NULL;
+
+        r = new(char, a+b+1);
+        if (!r)
+                return NULL;
+
+        memcpy(r, s, a);
+        memcpy(r+a, suffix, b);
+        r[a+b] = 0;
+
+        return r;
+}
+
+char *strappend(const char *s, const char *suffix) {
+        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+char *strjoin(const char *x, ...) {
+        va_list ap;
+        size_t l;
+        char *r, *p;
+
+        va_start(ap, x);
+
+        if (x) {
+                l = strlen(x);
+
+                for (;;) {
+                        const char *t;
+                        size_t n;
+
+                        t = va_arg(ap, const char *);
+                        if (!t)
+                                break;
+
+                        n = strlen(t);
+                        if (n > ((size_t) -1) - l) {
+                                va_end(ap);
+                                return NULL;
+                        }
+
+                        l += n;
+                }
+        } else
+                l = 0;
+
+        va_end(ap);
+
+        r = new(char, l+1);
+        if (!r)
+                return NULL;
+
+        if (x) {
+                p = stpcpy(r, x);
+
+                va_start(ap, x);
+
+                for (;;) {
+                        const char *t;
+
+                        t = va_arg(ap, const char *);
+                        if (!t)
+                                break;
+
+                        p = stpcpy(p, t);
+                }
+
+                va_end(ap);
+        } else
+                r[0] = 0;
+
+        return r;
+}
+
+char *strstrip(char *s) {
+        char *e;
+
+        /* Drops trailing whitespace. Modifies the string in
+         * place. Returns pointer to first non-space character */
+
+        s += strspn(s, WHITESPACE);
+
+        for (e = strchr(s, 0); e > s; e --)
+                if (!strchr(WHITESPACE, e[-1]))
+                        break;
+
+        *e = 0;
+
+        return s;
+}
+
+char *delete_chars(char *s, const char *bad) {
+        char *f, *t;
+
+        /* Drops all whitespace, regardless where in the string */
+
+        for (f = s, t = s; *f; f++) {
+                if (strchr(bad, *f))
+                        continue;
+
+                *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return s;
+}
+
+char *truncate_nl(char *s) {
+        assert(s);
+
+        s[strcspn(s, NEWLINE)] = 0;
+        return s;
+}
+
+char *ascii_strlower(char *t) {
+        char *p;
+
+        assert(t);
+
+        for (p = t; *p; p++)
+                if (*p >= 'A' && *p <= 'Z')
+                        *p = *p - 'A' + 'a';
+
+        return t;
+}
+
+bool chars_intersect(const char *a, const char *b) {
+        const char *p;
+
+        /* Returns true if any of the chars in a are in b. */
+        for (p = a; *p; p++)
+                if (strchr(b, *p))
+                        return true;
+
+        return false;
+}
+
+bool string_has_cc(const char *p, const char *ok) {
+        const char *t;
+
+        assert(p);
+
+        /*
+         * Check if a string contains control characters. If 'ok' is
+         * non-NULL it may be a string containing additional CCs to be
+         * considered OK.
+         */
+
+        for (t = p; *t; t++) {
+                if (ok && strchr(ok, *t))
+                        continue;
+
+                if (*t > 0 && *t < ' ')
+                        return true;
+
+                if (*t == 127)
+                        return true;
+        }
+
+        return false;
+}
+
+static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+        size_t x;
+        char *r;
+
+        assert(s);
+        assert(percent <= 100);
+        assert(new_length >= 3);
+
+        if (old_length <= 3 || old_length <= new_length)
+                return strndup(s, old_length);
+
+        r = new0(char, new_length+1);
+        if (!r)
+                return NULL;
+
+        x = (new_length * percent) / 100;
+
+        if (x > new_length - 3)
+                x = new_length - 3;
+
+        memcpy(r, s, x);
+        r[x] = '.';
+        r[x+1] = '.';
+        r[x+2] = '.';
+        memcpy(r + x + 3,
+               s + old_length - (new_length - x - 3),
+               new_length - x - 3);
+
+        return r;
+}
+
+char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+        size_t x;
+        char *e;
+        const char *i, *j;
+        unsigned k, len, len2;
+
+        assert(s);
+        assert(percent <= 100);
+        assert(new_length >= 3);
+
+        /* if no multibyte characters use ascii_ellipsize_mem for speed */
+        if (ascii_is_valid(s))
+                return ascii_ellipsize_mem(s, old_length, new_length, percent);
+
+        if (old_length <= 3 || old_length <= new_length)
+                return strndup(s, old_length);
+
+        x = (new_length * percent) / 100;
+
+        if (x > new_length - 3)
+                x = new_length - 3;
+
+        k = 0;
+        for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
+                int c;
+
+                c = utf8_encoded_to_unichar(i);
+                if (c < 0)
+                        return NULL;
+                k += unichar_iswide(c) ? 2 : 1;
+        }
+
+        if (k > x) /* last character was wide and went over quota */
+                x ++;
+
+        for (j = s + old_length; k < new_length && j > i; ) {
+                int c;
+
+                j = utf8_prev_char(j);
+                c = utf8_encoded_to_unichar(j);
+                if (c < 0)
+                        return NULL;
+                k += unichar_iswide(c) ? 2 : 1;
+        }
+        assert(i <= j);
+
+        /* we don't actually need to ellipsize */
+        if (i == j)
+                return memdup(s, old_length + 1);
+
+        /* make space for ellipsis */
+        j = utf8_next_char(j);
+
+        len = i - s;
+        len2 = s + old_length - j;
+        e = new(char, len + 3 + len2 + 1);
+        if (!e)
+                return NULL;
+
+        /*
+        printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
+               old_length, new_length, x, len, len2, k);
+        */
+
+        memcpy(e, s, len);
+        e[len]   = 0xe2; /* tri-dot ellipsis: … */
+        e[len + 1] = 0x80;
+        e[len + 2] = 0xa6;
+
+        memcpy(e + len + 3, j, len2 + 1);
+
+        return e;
+}
+
+char *ellipsize(const char *s, size_t length, unsigned percent) {
+        return ellipsize_mem(s, strlen(s), length, percent);
+}
+
+bool nulstr_contains(const char*nulstr, const char *needle) {
+        const char *i;
+
+        if (!nulstr)
+                return false;
+
+        NULSTR_FOREACH(i, nulstr)
+                if (streq(i, needle))
+                        return true;
+
+        return false;
+}
+
+char* strshorten(char *s, size_t l) {
+        assert(s);
+
+        if (l < strlen(s))
+                s[l] = 0;
+
+        return s;
+}
+
+char *strreplace(const char *text, const char *old_string, const char *new_string) {
+        const char *f;
+        char *t, *r;
+        size_t l, old_len, new_len;
+
+        assert(text);
+        assert(old_string);
+        assert(new_string);
+
+        old_len = strlen(old_string);
+        new_len = strlen(new_string);
+
+        l = strlen(text);
+        r = new(char, l+1);
+        if (!r)
+                return NULL;
+
+        f = text;
+        t = r;
+        while (*f) {
+                char *a;
+                size_t d, nl;
+
+                if (!startswith(f, old_string)) {
+                        *(t++) = *(f++);
+                        continue;
+                }
+
+                d = t - r;
+                nl = l - old_len + new_len;
+                a = realloc(r, nl + 1);
+                if (!a)
+                        goto oom;
+
+                l = nl;
+                r = a;
+                t = r + d;
+
+                t = stpcpy(t, new_string);
+                f += old_len;
+        }
+
+        *t = 0;
+        return r;
+
+oom:
+        free(r);
+        return NULL;
+}
+
+char *strip_tab_ansi(char **ibuf, size_t *_isz) {
+        const char *i, *begin = NULL;
+        enum {
+                STATE_OTHER,
+                STATE_ESCAPE,
+                STATE_BRACKET
+        } state = STATE_OTHER;
+        char *obuf = NULL;
+        size_t osz = 0, isz;
+        FILE *f;
+
+        assert(ibuf);
+        assert(*ibuf);
+
+        /* Strips ANSI color and replaces TABs by 8 spaces */
+
+        isz = _isz ? *_isz : strlen(*ibuf);
+
+        f = open_memstream(&obuf, &osz);
+        if (!f)
+                return NULL;
+
+        for (i = *ibuf; i < *ibuf + isz + 1; i++) {
+
+                switch (state) {
+
+                case STATE_OTHER:
+                        if (i >= *ibuf + isz) /* EOT */
+                                break;
+                        else if (*i == '\x1B')
+                                state = STATE_ESCAPE;
+                        else if (*i == '\t')
+                                fputs("        ", f);
+                        else
+                                fputc(*i, f);
+                        break;
+
+                case STATE_ESCAPE:
+                        if (i >= *ibuf + isz) { /* EOT */
+                                fputc('\x1B', f);
+                                break;
+                        } else if (*i == '[') {
+                                state = STATE_BRACKET;
+                                begin = i + 1;
+                        } else {
+                                fputc('\x1B', f);
+                                fputc(*i, f);
+                                state = STATE_OTHER;
+                        }
+
+                        break;
+
+                case STATE_BRACKET:
+
+                        if (i >= *ibuf + isz || /* EOT */
+                            (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
+                                fputc('\x1B', f);
+                                fputc('[', f);
+                                state = STATE_OTHER;
+                                i = begin-1;
+                        } else if (*i == 'm')
+                                state = STATE_OTHER;
+                        break;
+                }
+        }
+
+        if (ferror(f)) {
+                fclose(f);
+                free(obuf);
+                return NULL;
+        }
+
+        fclose(f);
+
+        free(*ibuf);
+        *ibuf = obuf;
+
+        if (_isz)
+                *_isz = osz;
+
+        return obuf;
+}
+
+char *strextend(char **x, ...) {
+        va_list ap;
+        size_t f, l;
+        char *r, *p;
+
+        assert(x);
+
+        l = f = *x ? strlen(*x) : 0;
+
+        va_start(ap, x);
+        for (;;) {
+                const char *t;
+                size_t n;
+
+                t = va_arg(ap, const char *);
+                if (!t)
+                        break;
+
+                n = strlen(t);
+                if (n > ((size_t) -1) - l) {
+                        va_end(ap);
+                        return NULL;
+                }
+
+                l += n;
+        }
+        va_end(ap);
+
+        r = realloc(*x, l+1);
+        if (!r)
+                return NULL;
+
+        p = r + f;
+
+        va_start(ap, x);
+        for (;;) {
+                const char *t;
+
+                t = va_arg(ap, const char *);
+                if (!t)
+                        break;
+
+                p = stpcpy(p, t);
+        }
+        va_end(ap);
+
+        *p = 0;
+        *x = r;
+
+        return r + l;
+}
+
+char *strrep(const char *s, unsigned n) {
+        size_t l;
+        char *r, *p;
+        unsigned i;
+
+        assert(s);
+
+        l = strlen(s);
+        p = r = malloc(l * n + 1);
+        if (!r)
+                return NULL;
+
+        for (i = 0; i < n; i++)
+                p = stpcpy(p, s);
+
+        *p = 0;
+        return r;
+}
+
+int split_pair(const char *s, const char *sep, char **l, char **r) {
+        char *x, *a, *b;
+
+        assert(s);
+        assert(sep);
+        assert(l);
+        assert(r);
+
+        if (isempty(sep))
+                return -EINVAL;
+
+        x = strstr(s, sep);
+        if (!x)
+                return -EINVAL;
+
+        a = strndup(s, x - s);
+        if (!a)
+                return -ENOMEM;
+
+        b = strdup(x + strlen(sep));
+        if (!b) {
+                free(a);
+                return -ENOMEM;
+        }
+
+        *l = a;
+        *r = b;
+
+        return 0;
+}
+
+int free_and_strdup(char **p, const char *s) {
+        char *t;
+
+        assert(p);
+
+        /* Replaces a string pointer with an strdup()ed new string,
+         * possibly freeing the old one. */
+
+        if (streq_ptr(*p, s))
+                return 0;
+
+        if (s) {
+                t = strdup(s);
+                if (!t)
+                        return -ENOMEM;
+        } else
+                t = NULL;
+
+        free(*p);
+        *p = t;
+
+        return 1;
+}
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+
+void* memory_erase(void *p, size_t l) {
+        volatile uint8_t* x = (volatile uint8_t*) p;
+
+        /* This basically does what memset() does, but hopefully isn't
+         * optimized away by the compiler. One of those days, when
+         * glibc learns memset_s() we should replace this call by
+         * memset_s(), but until then this has to do. */
+
+        for (; l > 0; l--)
+                *(x++) = 'x';
+
+        return p;
+}
+
+#pragma GCC pop_options
+
+char* string_erase(char *x) {
+
+        if (!x)
+                return NULL;
+
+        /* A delicious drop of snake-oil! To be called on memory where
+         * we stored passphrases or so, after we used them. */
+
+        return memory_erase(x, strlen(x));
+}
+
+char *string_free_erase(char *s) {
+        return mfree(string_erase(s));
+}
+
+bool string_is_safe(const char *p) {
+        const char *t;
+
+        if (!p)
+                return false;
+
+        for (t = p; *t; t++) {
+                if (*t > 0 && *t < ' ') /* no control characters */
+                        return false;
+
+                if (strchr(QUOTES "\\\x7f", *t))
+                        return false;
+        }
+
+        return true;
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
new file mode 100644 (file)
index 0000000..54f9d30
--- /dev/null
@@ -0,0 +1,184 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+#include <string.h>
+
+#include "macro.h"
+
+/* What is interpreted as whitespace? */
+#define WHITESPACE        " \t\n\r"
+#define NEWLINE           "\n\r"
+#define QUOTES            "\"\'"
+#define COMMENTS          "#;"
+#define GLOB_CHARS        "*?["
+#define DIGITS            "0123456789"
+#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define LETTERS           LOWERCASE_LETTERS UPPERCASE_LETTERS
+#define ALPHANUMERICAL    LETTERS DIGITS
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+
+int strcmp_ptr(const char *a, const char *b) _pure_;
+
+static inline bool streq_ptr(const char *a, const char *b) {
+        return strcmp_ptr(a, b) == 0;
+}
+
+static inline const char* strempty(const char *s) {
+        return s ? s : "";
+}
+
+static inline const char* strnull(const char *s) {
+        return s ? s : "(null)";
+}
+
+static inline const char *strna(const char *s) {
+        return s ? s : "n/a";
+}
+
+static inline bool isempty(const char *p) {
+        return !p || !p[0];
+}
+
+static inline char *startswith(const char *s, const char *prefix) {
+        size_t l;
+
+        l = strlen(prefix);
+        if (strncmp(s, prefix, l) == 0)
+                return (char*) s + l;
+
+        return NULL;
+}
+
+static inline char *startswith_no_case(const char *s, const char *prefix) {
+        size_t l;
+
+        l = strlen(prefix);
+        if (strncasecmp(s, prefix, l) == 0)
+                return (char*) s + l;
+
+        return NULL;
+}
+
+char *endswith(const char *s, const char *postfix) _pure_;
+char *endswith_no_case(const char *s, const char *postfix) _pure_;
+
+char *first_word(const char *s, const char *word) _pure_;
+
+const char* split(const char **state, size_t *l, const char *separator, bool quoted);
+
+#define FOREACH_WORD(word, length, s, state)                            \
+        _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
+        _FOREACH_WORD(word, length, s, separator, false, state)
+
+#define FOREACH_WORD_QUOTED(word, length, s, state)                     \
+        _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
+
+#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
+        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+
+char *strappend(const char *s, const char *suffix);
+char *strnappend(const char *s, const char *suffix, size_t length);
+
+char *strjoin(const char *x, ...) _sentinel_;
+
+#define strjoina(a, ...)                                                \
+        ({                                                              \
+                const char *_appendees_[] = { a, __VA_ARGS__ };         \
+                char *_d_, *_p_;                                        \
+                int _len_ = 0;                                          \
+                unsigned _i_;                                           \
+                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+                        _len_ += strlen(_appendees_[_i_]);              \
+                _p_ = _d_ = alloca(_len_ + 1);                          \
+                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+                        _p_ = stpcpy(_p_, _appendees_[_i_]);            \
+                *_p_ = 0;                                               \
+                _d_;                                                    \
+        })
+
+char *strstrip(char *s);
+char *delete_chars(char *s, const char *bad);
+char *truncate_nl(char *s);
+
+char *ascii_strlower(char *path);
+
+bool chars_intersect(const char *a, const char *b) _pure_;
+
+static inline bool _pure_ in_charset(const char *s, const char* charset) {
+        assert(s);
+        assert(charset);
+        return s[strspn(s, charset)] == '\0';
+}
+
+bool string_has_cc(const char *p, const char *ok) _pure_;
+
+char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
+char *ellipsize(const char *s, size_t length, unsigned percent);
+
+bool nulstr_contains(const char*nulstr, const char *needle);
+
+char* strshorten(char *s, size_t l);
+
+char *strreplace(const char *text, const char *old_string, const char *new_string);
+
+char *strip_tab_ansi(char **p, size_t *l);
+
+char *strextend(char **x, ...) _sentinel_;
+
+char *strrep(const char *s, unsigned n);
+
+int split_pair(const char *s, const char *sep, char **l, char **r);
+
+int free_and_strdup(char **p, const char *s);
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+        if (needlelen <= 0)
+                return (void*) haystack;
+
+        if (haystacklen < needlelen)
+                return NULL;
+
+        assert(haystack);
+        assert(needle);
+
+        return memmem(haystack, haystacklen, needle, needlelen);
+}
+
+void* memory_erase(void *p, size_t l);
+char *string_erase(char *x);
+
+char *string_free_erase(char *s);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
+#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
+
+bool string_is_safe(const char *p) _pure_;
index b66c176487747d312ee7295215ba19d7e58be46d..ba6df716a71c798e47396bfc97f45cae8a51dfd5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
+#include <errno.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
-#include <errno.h>
 
+#include "alloc-util.h"
+#include "escape.h"
+#include "string-util.h"
 #include "util.h"
 #include "strv.h"
 
@@ -86,6 +89,15 @@ char **strv_free(char **l) {
         return NULL;
 }
 
+char **strv_free_erase(char **l) {
+        char **i;
+
+        STRV_FOREACH(i, l)
+                string_erase(*i);
+
+        return strv_free(l);
+}
+
 char **strv_copy(char * const *l) {
         char **r, **k;
 
index e49f443835797b458700dcf25b7801044c3defcd..e66794fc34d9f59caebf38b2c8f72f97c1547979 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <fnmatch.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include <fnmatch.h>
 
+#include "extract-word.h"
 #include "util.h"
 
 char *strv_find(char **l, const char *name) _pure_;
@@ -35,6 +36,10 @@ char **strv_free(char **l);
 DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
 #define _cleanup_strv_free_ _cleanup_(strv_freep)
 
+char **strv_free_erase(char **l);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
+#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
+
 void strv_clear(char **l);
 
 char **strv_copy(char * const *l);
diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c
new file mode 100644 (file)
index 0000000..0157794
--- /dev/null
@@ -0,0 +1,115 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <syslog.h>
+
+#include "assert.h"
+#include "hexdecoct.h"
+#include "string-table.h"
+#include "syslog-util.h"
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
+        int a = 0, b = 0, c = 0;
+        int k;
+
+        assert(p);
+        assert(*p);
+        assert(priority);
+
+        if ((*p)[0] != '<')
+                return 0;
+
+        if (!strchr(*p, '>'))
+                return 0;
+
+        if ((*p)[2] == '>') {
+                c = undecchar((*p)[1]);
+                k = 3;
+        } else if ((*p)[3] == '>') {
+                b = undecchar((*p)[1]);
+                c = undecchar((*p)[2]);
+                k = 4;
+        } else if ((*p)[4] == '>') {
+                a = undecchar((*p)[1]);
+                b = undecchar((*p)[2]);
+                c = undecchar((*p)[3]);
+                k = 5;
+        } else
+                return 0;
+
+        if (a < 0 || b < 0 || c < 0 ||
+            (!with_facility && (a || b || c > 7)))
+                return 0;
+
+        if (with_facility)
+                *priority = a*100 + b*10 + c;
+        else
+                *priority = (*priority & LOG_FACMASK) | c;
+
+        *p += k;
+        return 1;
+}
+
+static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
+        [LOG_FAC(LOG_KERN)] = "kern",
+        [LOG_FAC(LOG_USER)] = "user",
+        [LOG_FAC(LOG_MAIL)] = "mail",
+        [LOG_FAC(LOG_DAEMON)] = "daemon",
+        [LOG_FAC(LOG_AUTH)] = "auth",
+        [LOG_FAC(LOG_SYSLOG)] = "syslog",
+        [LOG_FAC(LOG_LPR)] = "lpr",
+        [LOG_FAC(LOG_NEWS)] = "news",
+        [LOG_FAC(LOG_UUCP)] = "uucp",
+        [LOG_FAC(LOG_CRON)] = "cron",
+        [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
+        [LOG_FAC(LOG_FTP)] = "ftp",
+        [LOG_FAC(LOG_LOCAL0)] = "local0",
+        [LOG_FAC(LOG_LOCAL1)] = "local1",
+        [LOG_FAC(LOG_LOCAL2)] = "local2",
+        [LOG_FAC(LOG_LOCAL3)] = "local3",
+        [LOG_FAC(LOG_LOCAL4)] = "local4",
+        [LOG_FAC(LOG_LOCAL5)] = "local5",
+        [LOG_FAC(LOG_LOCAL6)] = "local6",
+        [LOG_FAC(LOG_LOCAL7)] = "local7"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
+
+bool log_facility_unshifted_is_valid(int facility) {
+        return facility >= 0 && facility <= LOG_FAC(~0);
+}
+
+static const char *const log_level_table[] = {
+        [LOG_EMERG] = "emerg",
+        [LOG_ALERT] = "alert",
+        [LOG_CRIT] = "crit",
+        [LOG_ERR] = "err",
+        [LOG_WARNING] = "warning",
+        [LOG_NOTICE] = "notice",
+        [LOG_INFO] = "info",
+        [LOG_DEBUG] = "debug"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
+
+bool log_level_is_valid(int level) {
+        return level >= 0 && level <= LOG_DEBUG;
+}
diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h
new file mode 100644 (file)
index 0000000..eb79c6d
--- /dev/null
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+
+int log_facility_unshifted_to_string_alloc(int i, char **s);
+int log_facility_unshifted_from_string(const char *s);
+bool log_facility_unshifted_is_valid(int faciliy);
+
+int log_level_to_string_alloc(int i, char **s);
+int log_level_from_string(const char *s);
+bool log_level_is_valid(int level);
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility);
index ca7554a9fad7d2acb0954ca5eba5e114079454ab..3931b03bc2a05bbf2029bf502cdf8c52e6de6b92 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <linux/tiocl.h>
+#include <linux/vt.h>
+#include <poll.h>
+#include <signal.h>
 #include <sys/ioctl.h>
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <termios.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <time.h>
-#include <assert.h>
-#include <poll.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <linux/kd.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "socket-util.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
 #include "time-util.h"
-#include "process-util.h"
 #include "util.h"
-#include "fileio.h"
-#include "path-util.h"
 
 static volatile unsigned cached_columns = 0;
 static volatile unsigned cached_lines = 0;
@@ -412,7 +420,7 @@ int acquire_terminal(
 
                 assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
 
-                /* Sometimes it makes sense to ignore TIOCSCTTY
+                /* Sometimes, it makes sense to ignore TIOCSCTTY
                  * returning EPERM, i.e. when very likely we already
                  * are have this controlling terminal. */
                 if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
@@ -620,84 +628,6 @@ int make_console_stdio(void) {
         return 0;
 }
 
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
-        static const char status_indent[] = "         "; /* "[" STATUS "] " */
-        _cleanup_free_ char *s = NULL;
-        _cleanup_close_ int fd = -1;
-        struct iovec iovec[6] = {};
-        int n = 0;
-        static bool prev_ephemeral;
-
-        assert(format);
-
-        /* This is independent of logging, as status messages are
-         * optional and go exclusively to the console. */
-
-        if (vasprintf(&s, format, ap) < 0)
-                return log_oom();
-
-        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
-        if (fd < 0)
-                return fd;
-
-        if (ellipse) {
-                char *e;
-                size_t emax, sl;
-                int c;
-
-                c = fd_columns(fd);
-                if (c <= 0)
-                        c = 80;
-
-                sl = status ? sizeof(status_indent)-1 : 0;
-
-                emax = c - sl - 1;
-                if (emax < 3)
-                        emax = 3;
-
-                e = ellipsize(s, emax, 50);
-                if (e) {
-                        free(s);
-                        s = e;
-                }
-        }
-
-        if (prev_ephemeral)
-                IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
-        prev_ephemeral = ephemeral;
-
-        if (status) {
-                if (!isempty(status)) {
-                        IOVEC_SET_STRING(iovec[n++], "[");
-                        IOVEC_SET_STRING(iovec[n++], status);
-                        IOVEC_SET_STRING(iovec[n++], "] ");
-                } else
-                        IOVEC_SET_STRING(iovec[n++], status_indent);
-        }
-
-        IOVEC_SET_STRING(iovec[n++], s);
-        if (!ephemeral)
-                IOVEC_SET_STRING(iovec[n++], "\n");
-
-        if (writev(fd, iovec, n) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
-        va_list ap;
-        int r;
-
-        assert(format);
-
-        va_start(ap, format);
-        r = status_vprintf(status, ellipse, ephemeral, format, ap);
-        va_end(ap);
-
-        return r;
-}
-
 bool tty_is_vc(const char *tty) {
         assert(tty);
 
index ee0b68b433abd4428d995b77d730bbf1c43f0d84..f2185c1c117d876c7d3ff4287bae8928ef553b5c 100644 (file)
@@ -71,9 +71,6 @@ int make_stdio(int fd);
 int make_null_stdio(void);
 int make_console_stdio(void);
 
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
-
 int fd_columns(int fd);
 unsigned columns(void);
 int fd_lines(int fd);
index 531931f6e1434e6474c3708e3577b51ccdc213de..b36fbe4f09cb05c758803958a03bf1c51219ed0f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <time.h>
 #include <string.h>
-#include <sys/timex.h>
 #include <sys/timerfd.h>
+#include <sys/timex.h>
 
-#include "util.h"
-#include "time-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
+#include "util.h"
 
 usec_t now(clockid_t clock_id) {
         struct timespec ts;
@@ -205,11 +209,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
                 return NULL;
 
         sec = (time_t) (t / USEC_PER_SEC);
+        localtime_or_gmtime_r(&sec, &tm, utc);
 
-        if (utc)
-                gmtime_r(&sec, &tm);
-        else
-                localtime_r(&sec, &tm);
         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
                 return NULL;
 
@@ -235,10 +236,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
                 return NULL;
 
         sec = (time_t) (t / USEC_PER_SEC);
-        if (utc)
-                gmtime_r(&sec, &tm);
-        else
-                localtime_r(&sec, &tm);
+        localtime_or_gmtime_r(&sec, &tm, utc);
 
         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
                 return NULL;
@@ -484,9 +482,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
         };
 
         const char *k;
+        const char *utc;
         struct tm tm, copy;
         time_t x;
-        usec_t plus = 0, minus = 0, ret;
+        usec_t x_usec, plus = 0, minus = 0, ret;
         int r, weekday = -1;
         unsigned i;
 
@@ -511,28 +510,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
         assert(t);
         assert(usec);
 
-        x = time(NULL);
-        assert_se(localtime_r(&x, &tm));
-        tm.tm_isdst = -1;
-
-        if (streq(t, "now"))
-                goto finish;
-
-        else if (streq(t, "today")) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+        if (t[0] == '@')
+                return parse_sec(t + 1, usec);
 
-        } else if (streq(t, "yesterday")) {
-                tm.tm_mday --;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+        ret = now(CLOCK_REALTIME);
 
-        } else if (streq(t, "tomorrow")) {
-                tm.tm_mday ++;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+        if (streq(t, "now"))
                 goto finish;
 
-        else if (t[0] == '+') {
+        else if (t[0] == '+') {
                 r = parse_sec(t+1, &plus);
                 if (r < 0)
                         return r;
@@ -546,35 +532,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
 
                 goto finish;
 
-        } else if (t[0] == '@')
-                return parse_sec(t + 1, usec);
-
-        else if (endswith(t, " ago")) {
-                _cleanup_free_ char *z;
+        } else if ((k = endswith(t, " ago"))) {
+                t = strndupa(t, k - t);
 
-                z = strndup(t, strlen(t) - 4);
-                if (!z)
-                        return -ENOMEM;
-
-                r = parse_sec(z, &minus);
+                r = parse_sec(t, &minus);
                 if (r < 0)
                         return r;
 
                 goto finish;
-        } else if (endswith(t, " left")) {
-                _cleanup_free_ char *z;
 
-                z = strndup(t, strlen(t) - 4);
-                if (!z)
-                        return -ENOMEM;
+        } else if ((k = endswith(t, " left"))) {
+                t = strndupa(t, k - t);
 
-                r = parse_sec(z, &plus);
+                r = parse_sec(t, &plus);
                 if (r < 0)
                         return r;
 
                 goto finish;
         }
 
+        utc = endswith_no_case(t, " UTC");
+        if (utc)
+                t = strndupa(t, utc - t);
+
+        x = ret / USEC_PER_SEC;
+        x_usec = 0;
+
+        assert_se(localtime_or_gmtime_r(&x, &tm, utc));
+        tm.tm_isdst = -1;
+
+        if (streq(t, "today")) {
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+
+        } else if (streq(t, "yesterday")) {
+                tm.tm_mday --;
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+
+        } else if (streq(t, "tomorrow")) {
+                tm.tm_mday ++;
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+        }
+
+
         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                 size_t skip;
 
@@ -592,66 +594,106 @@ int parse_timestamp(const char *t, usec_t *usec) {
 
         copy = tm;
         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%y-%m-%d %H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%y-%m-%d", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         return -EINVAL;
 
-finish:
-        x = mktime(&tm);
+parse_usec:
+        {
+                char *end;
+                unsigned long long val;
+                size_t l;
+
+                k++;
+                if (*k < '0' || *k > '9')
+                        return -EINVAL;
+
+                /* base 10 instead of base 0, .09 is not base 8 */
+                errno = 0;
+                val = strtoull(k, &end, 10);
+                if (*end || errno)
+                        return -EINVAL;
+
+                l = end-k;
+
+                /* val has l digits, make them 6 */
+                for (; l < 6; l++)
+                        val *= 10;
+                for (; l > 6; l--)
+                        val /= 10;
+
+                x_usec = val;
+        }
+
+from_tm:
+        x = mktime_or_timegm(&tm, utc);
         if (x == (time_t) -1)
                 return -EINVAL;
 
         if (weekday >= 0 && tm.tm_wday != weekday)
                 return -EINVAL;
 
-        ret = (usec_t) x * USEC_PER_SEC;
+        ret = (usec_t) x * USEC_PER_SEC + x_usec;
 
+finish:
         ret += plus;
         if (ret > minus)
                 ret -= minus;
@@ -663,7 +705,8 @@ finish:
         return 0;
 }
 
-int parse_sec(const char *t, usec_t *usec) {
+int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
+
         static const struct {
                 const char *suffix;
                 usec_t usec;
@@ -695,7 +738,6 @@ int parse_sec(const char *t, usec_t *usec) {
                 { "y", USEC_PER_YEAR },
                 { "usec", 1ULL },
                 { "us", 1ULL },
-                { "", USEC_PER_SEC }, /* default is sec */
         };
 
         const char *p, *s;
@@ -704,6 +746,7 @@ int parse_sec(const char *t, usec_t *usec) {
 
         assert(t);
         assert(usec);
+        assert(default_unit > 0);
 
         p = t;
 
@@ -722,6 +765,7 @@ int parse_sec(const char *t, usec_t *usec) {
                 long long l, z = 0;
                 char *e;
                 unsigned i, n = 0;
+                usec_t multiplier, k;
 
                 p += strspn(p, WHITESPACE);
 
@@ -764,21 +808,24 @@ int parse_sec(const char *t, usec_t *usec) {
 
                 for (i = 0; i < ELEMENTSOF(table); i++)
                         if (startswith(e, table[i].suffix)) {
-                                usec_t k = (usec_t) z * table[i].usec;
-
-                                for (; n > 0; n--)
-                                        k /= 10;
-
-                                r += (usec_t) l * table[i].usec + k;
+                                multiplier = table[i].usec;
                                 p = e + strlen(table[i].suffix);
-
-                                something = true;
                                 break;
                         }
 
-                if (i >= ELEMENTSOF(table))
-                        return -EINVAL;
+                if (i >= ELEMENTSOF(table)) {
+                        multiplier = default_unit;
+                        p = e;
+                }
+
+                something = true;
 
+                k = (usec_t) z * multiplier;
+
+                for (; n > 0; n--)
+                        k /= 10;
+
+                r += (usec_t) l * multiplier + k;
         }
 
         *usec = r;
@@ -786,6 +833,10 @@ int parse_sec(const char *t, usec_t *usec) {
         return 0;
 }
 
+int parse_sec(const char *t, usec_t *usec) {
+        return parse_time(t, usec, USEC_PER_SEC);
+}
+
 int parse_nsec(const char *t, nsec_t *nsec) {
         static const struct {
                 const char *suffix;
@@ -1072,3 +1123,25 @@ int get_timezone(char **tz) {
         *tz = z;
         return 0;
 }
+
+time_t mktime_or_timegm(struct tm *tm, bool utc) {
+        return utc ? timegm(tm) : mktime(tm);
+}
+
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
+        return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
+}
+
+unsigned long usec_to_jiffies(usec_t u) {
+        static thread_local unsigned long hz = 0;
+        long r;
+
+        if (hz == 0) {
+                r = sysconf(_SC_CLK_TCK);
+
+                assert(r > 0);
+                hz = (unsigned long) r;
+        }
+
+        return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
+}
index 1af01541fc23dc85426b86430c52b7ee41e4b4c8..0417c29cddbe4b5506745a190e42f9fc1f0b5bcb 100644 (file)
@@ -21,8 +21,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <inttypes.h>
+#include <stdio.h>
+#include <time.h>
 
 typedef uint64_t usec_t;
 typedef uint64_t nsec_t;
@@ -103,6 +104,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
 int parse_timestamp(const char *t, usec_t *usec);
 
 int parse_sec(const char *t, usec_t *usec);
+int parse_time(const char *t, usec_t *usec, usec_t default_unit);
 int parse_nsec(const char *t, nsec_t *nsec);
 
 bool ntp_synced(void);
@@ -117,3 +119,8 @@ clockid_t clock_boottime_or_monotonic(void);
                           "xstrftime: " #buf "[] must be big enough")
 
 int get_timezone(char **timezone);
+
+time_t mktime_or_timegm(struct tm *tm, bool utc);
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
+
+unsigned long usec_to_jiffies(usec_t usec);
diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h
new file mode 100644 (file)
index 0000000..8ed3465
--- /dev/null
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+static inline void umaskp(mode_t *u) {
+        umask(*u);
+}
+
+#define _cleanup_umask_ _cleanup_(umaskp)
+
+struct _umask_struct_ {
+        mode_t mask;
+        bool quit;
+};
+
+static inline void _reset_umask_(struct _umask_struct_ *s) {
+        umask(s->mask);
+};
+
+#define RUN_WITH_UMASK(mask)                                            \
+        for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
+             !_saved_umask_.quit ;                                      \
+             _saved_umask_.quit = true)
index a8b6b6dacea00040a529b3eb1f4d9ac61fcc3f18..9a55eacbfb51e3204bb966ad250c12613fda77c3 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "path-util.h"
+#include "alloc-util.h"
 #include "bus-label.h"
-#include "util.h"
-#include "unit-name.h"
 #include "def.h"
+#include "hexdecoct.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
+#include "unit-name.h"
+#include "util.h"
 
 #define VALID_CHARS                             \
         DIGITS LETTERS                          \
@@ -593,7 +597,6 @@ const char* unit_dbus_interface_from_type(UnitType t) {
                 [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
                 [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
                 [UNIT_TARGET] = "org.freedesktop.systemd1.Target",
-                [UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot",
                 [UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
                 [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
                 [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount",
@@ -651,7 +654,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t
  *  /blah/blah is converted to blah-blah.mount, anything else is left alone,
  *  except that @suffix is appended if a valid unit suffix is not present.
  *
- *  If @allow_globs, globs characters are preserved. Otherwise they are escaped.
+ *  If @allow_globs, globs characters are preserved. Otherwise, they are escaped.
  */
 int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
         char *s, *t;
@@ -815,7 +818,6 @@ static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SOCKET] = "socket",
         [UNIT_BUSNAME] = "busname",
         [UNIT_TARGET] = "target",
-        [UNIT_SNAPSHOT] = "snapshot",
         [UNIT_DEVICE] = "device",
         [UNIT_MOUNT] = "mount",
         [UNIT_AUTOMOUNT] = "automount",
@@ -946,13 +948,6 @@ static const char* const slice_state_table[_SLICE_STATE_MAX] = {
 
 DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
 
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
-        [SNAPSHOT_DEAD] = "dead",
-        [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
 static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = "dead",
         [SOCKET_START_PRE] = "start-pre",
@@ -1005,16 +1000,12 @@ DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
 
 static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
         [UNIT_REQUIRES] = "Requires",
-        [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
         [UNIT_REQUISITE] = "Requisite",
-        [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
         [UNIT_WANTS] = "Wants",
         [UNIT_BINDS_TO] = "BindsTo",
         [UNIT_PART_OF] = "PartOf",
         [UNIT_REQUIRED_BY] = "RequiredBy",
-        [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
         [UNIT_REQUISITE_OF] = "RequisiteOf",
-        [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable",
         [UNIT_WANTED_BY] = "WantedBy",
         [UNIT_BOUND_BY] = "BoundBy",
         [UNIT_CONSISTS_OF] = "ConsistsOf",
index 65b55d955464e47ab97992c80fbb419563f98706..03c1a6e4acd7dbe8c5ce0351421befb42df9ea32 100644 (file)
@@ -32,7 +32,6 @@ typedef enum UnitType {
         UNIT_SOCKET,
         UNIT_BUSNAME,
         UNIT_TARGET,
-        UNIT_SNAPSHOT,
         UNIT_DEVICE,
         UNIT_MOUNT,
         UNIT_AUTOMOUNT,
@@ -165,13 +164,6 @@ typedef enum SliceState {
         _SLICE_STATE_INVALID = -1
 } SliceState;
 
-typedef enum SnapshotState {
-        SNAPSHOT_DEAD,
-        SNAPSHOT_ACTIVE,
-        _SNAPSHOT_STATE_MAX,
-        _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
-
 typedef enum SocketState {
         SOCKET_DEAD,
         SOCKET_START_PRE,
@@ -226,18 +218,14 @@ typedef enum TimerState {
 typedef enum UnitDependency {
         /* Positive dependencies */
         UNIT_REQUIRES,
-        UNIT_REQUIRES_OVERRIDABLE,
         UNIT_REQUISITE,
-        UNIT_REQUISITE_OVERRIDABLE,
         UNIT_WANTS,
         UNIT_BINDS_TO,
         UNIT_PART_OF,
 
         /* Inverse of the above */
         UNIT_REQUIRED_BY,             /* inverse of 'requires' is 'required_by' */
-        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' is 'required_by_overridable' */
         UNIT_REQUISITE_OF,            /* inverse of 'requisite' is 'requisite_of' */
-        UNIT_REQUISITE_OF_OVERRIDABLE,/* inverse of 'requisite_overridable' is 'requisite_of_overridable' */
         UNIT_WANTED_BY,               /* inverse of 'wants' */
         UNIT_BOUND_BY,                /* inverse of 'binds_to' */
         UNIT_CONSISTS_OF,             /* inverse of 'part_of' */
@@ -366,9 +354,6 @@ ServiceState service_state_from_string(const char *s) _pure_;
 const char* slice_state_to_string(SliceState i) _const_;
 SliceState slice_state_from_string(const char *s) _pure_;
 
-const char* snapshot_state_to_string(SnapshotState i) _const_;
-SnapshotState snapshot_state_from_string(const char *s) _pure_;
-
 const char* socket_state_to_string(SocketState i) _const_;
 SocketState socket_state_from_string(const char *s) _pure_;
 
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
new file mode 100644 (file)
index 0000000..d6c936d
--- /dev/null
@@ -0,0 +1,472 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <pwd.h>
+#include <grp.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+bool uid_is_valid(uid_t uid) {
+
+        /* Some libc APIs use UID_INVALID as special placeholder */
+        if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
+                return false;
+
+        /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
+        if (uid == (uid_t) UINT32_C(0xFFFF))
+                return false;
+
+        return true;
+}
+
+int parse_uid(const char *s, uid_t *ret) {
+        uint32_t uid = 0;
+        int r;
+
+        assert(s);
+
+        assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+        r = safe_atou32(s, &uid);
+        if (r < 0)
+                return r;
+
+        if (!uid_is_valid(uid))
+                return -ENXIO; /* we return ENXIO instead of EINVAL
+                                * here, to make it easy to distuingish
+                                * invalid numeric uids invalid
+                                * strings. */
+
+        if (ret)
+                *ret = uid;
+
+        return 0;
+}
+
+char* getlogname_malloc(void) {
+        uid_t uid;
+        struct stat st;
+
+        if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
+                uid = st.st_uid;
+        else
+                uid = getuid();
+
+        return uid_to_name(uid);
+}
+
+char *getusername_malloc(void) {
+        const char *e;
+
+        e = getenv("USER");
+        if (e)
+                return strdup(e);
+
+        return uid_to_name(getuid());
+}
+
+int get_user_creds(
+                const char **username,
+                uid_t *uid, gid_t *gid,
+                const char **home,
+                const char **shell) {
+
+        struct passwd *p;
+        uid_t u;
+
+        assert(username);
+        assert(*username);
+
+        /* We enforce some special rules for uid=0: in order to avoid
+         * NSS lookups for root we hardcode its data. */
+
+        if (streq(*username, "root") || streq(*username, "0")) {
+                *username = "root";
+
+                if (uid)
+                        *uid = 0;
+
+                if (gid)
+                        *gid = 0;
+
+                if (home)
+                        *home = "/root";
+
+                if (shell)
+                        *shell = "/bin/sh";
+
+                return 0;
+        }
+
+        if (parse_uid(*username, &u) >= 0) {
+                errno = 0;
+                p = getpwuid(u);
+
+                /* If there are multiple users with the same id, make
+                 * sure to leave $USER to the configured value instead
+                 * of the first occurrence in the database. However if
+                 * the uid was configured by a numeric uid, then let's
+                 * pick the real username from /etc/passwd. */
+                if (p)
+                        *username = p->pw_name;
+        } else {
+                errno = 0;
+                p = getpwnam(*username);
+        }
+
+        if (!p)
+                return errno > 0 ? -errno : -ESRCH;
+
+        if (uid) {
+                if (!uid_is_valid(p->pw_uid))
+                        return -EBADMSG;
+
+                *uid = p->pw_uid;
+        }
+
+        if (gid) {
+                if (!gid_is_valid(p->pw_gid))
+                        return -EBADMSG;
+
+                *gid = p->pw_gid;
+        }
+
+        if (home)
+                *home = p->pw_dir;
+
+        if (shell)
+                *shell = p->pw_shell;
+
+        return 0;
+}
+
+int get_group_creds(const char **groupname, gid_t *gid) {
+        struct group *g;
+        gid_t id;
+
+        assert(groupname);
+
+        /* We enforce some special rules for gid=0: in order to avoid
+         * NSS lookups for root we hardcode its data. */
+
+        if (streq(*groupname, "root") || streq(*groupname, "0")) {
+                *groupname = "root";
+
+                if (gid)
+                        *gid = 0;
+
+                return 0;
+        }
+
+        if (parse_gid(*groupname, &id) >= 0) {
+                errno = 0;
+                g = getgrgid(id);
+
+                if (g)
+                        *groupname = g->gr_name;
+        } else {
+                errno = 0;
+                g = getgrnam(*groupname);
+        }
+
+        if (!g)
+                return errno > 0 ? -errno : -ESRCH;
+
+        if (gid) {
+                if (!gid_is_valid(g->gr_gid))
+                        return -EBADMSG;
+
+                *gid = g->gr_gid;
+        }
+
+        return 0;
+}
+
+char* uid_to_name(uid_t uid) {
+        char *ret;
+        int r;
+
+        /* Shortcut things to avoid NSS lookups */
+        if (uid == 0)
+                return strdup("root");
+
+        if (uid_is_valid(uid)) {
+                long bufsize;
+
+                bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+                if (bufsize <= 0)
+                        bufsize = 4096;
+
+                for (;;) {
+                        struct passwd pwbuf, *pw = NULL;
+                        _cleanup_free_ char *buf = NULL;
+
+                        buf = malloc(bufsize);
+                        if (!buf)
+                                return NULL;
+
+                        r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
+                        if (r == 0 && pw)
+                                return strdup(pw->pw_name);
+                        if (r != ERANGE)
+                                break;
+
+                        bufsize *= 2;
+                }
+        }
+
+        if (asprintf(&ret, UID_FMT, uid) < 0)
+                return NULL;
+
+        return ret;
+}
+
+char* gid_to_name(gid_t gid) {
+        char *ret;
+        int r;
+
+        if (gid == 0)
+                return strdup("root");
+
+        if (gid_is_valid(gid)) {
+                long bufsize;
+
+                bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+                if (bufsize <= 0)
+                        bufsize = 4096;
+
+                for (;;) {
+                        struct group grbuf, *gr = NULL;
+                        _cleanup_free_ char *buf = NULL;
+
+                        buf = malloc(bufsize);
+                        if (!buf)
+                                return NULL;
+
+                        r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
+                        if (r == 0 && gr)
+                                return strdup(gr->gr_name);
+                        if (r != ERANGE)
+                                break;
+
+                        bufsize *= 2;
+                }
+        }
+
+        if (asprintf(&ret, GID_FMT, gid) < 0)
+                return NULL;
+
+        return ret;
+}
+
+int in_gid(gid_t gid) {
+        gid_t *gids;
+        int ngroups_max, r, i;
+
+        if (getgid() == gid)
+                return 1;
+
+        if (getegid() == gid)
+                return 1;
+
+        if (!gid_is_valid(gid))
+                return -EINVAL;
+
+        ngroups_max = sysconf(_SC_NGROUPS_MAX);
+        assert(ngroups_max > 0);
+
+        gids = alloca(sizeof(gid_t) * ngroups_max);
+
+        r = getgroups(ngroups_max, gids);
+        if (r < 0)
+                return -errno;
+
+        for (i = 0; i < r; i++)
+                if (gids[i] == gid)
+                        return 1;
+
+        return 0;
+}
+
+int in_group(const char *name) {
+        int r;
+        gid_t gid;
+
+        r = get_group_creds(&name, &gid);
+        if (r < 0)
+                return r;
+
+        return in_gid(gid);
+}
+
+int get_home_dir(char **_h) {
+        struct passwd *p;
+        const char *e;
+        char *h;
+        uid_t u;
+
+        assert(_h);
+
+        /* Take the user specified one */
+        e = secure_getenv("HOME");
+        if (e && path_is_absolute(e)) {
+                h = strdup(e);
+                if (!h)
+                        return -ENOMEM;
+
+                *_h = h;
+                return 0;
+        }
+
+        /* Hardcode home directory for root to avoid NSS */
+        u = getuid();
+        if (u == 0) {
+                h = strdup("/root");
+                if (!h)
+                        return -ENOMEM;
+
+                *_h = h;
+                return 0;
+        }
+
+        /* Check the database... */
+        errno = 0;
+        p = getpwuid(u);
+        if (!p)
+                return errno > 0 ? -errno : -ESRCH;
+
+        if (!path_is_absolute(p->pw_dir))
+                return -EINVAL;
+
+        h = strdup(p->pw_dir);
+        if (!h)
+                return -ENOMEM;
+
+        *_h = h;
+        return 0;
+}
+
+int get_shell(char **_s) {
+        struct passwd *p;
+        const char *e;
+        char *s;
+        uid_t u;
+
+        assert(_s);
+
+        /* Take the user specified one */
+        e = getenv("SHELL");
+        if (e) {
+                s = strdup(e);
+                if (!s)
+                        return -ENOMEM;
+
+                *_s = s;
+                return 0;
+        }
+
+        /* Hardcode home directory for root to avoid NSS */
+        u = getuid();
+        if (u == 0) {
+                s = strdup("/bin/sh");
+                if (!s)
+                        return -ENOMEM;
+
+                *_s = s;
+                return 0;
+        }
+
+        /* Check the database... */
+        errno = 0;
+        p = getpwuid(u);
+        if (!p)
+                return errno > 0 ? -errno : -ESRCH;
+
+        if (!path_is_absolute(p->pw_shell))
+                return -EINVAL;
+
+        s = strdup(p->pw_shell);
+        if (!s)
+                return -ENOMEM;
+
+        *_s = s;
+        return 0;
+}
+
+int reset_uid_gid(void) {
+
+        if (setgroups(0, NULL) < 0)
+                return -errno;
+
+        if (setresgid(0, 0, 0) < 0)
+                return -errno;
+
+        if (setresuid(0, 0, 0) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int take_etc_passwd_lock(const char *root) {
+
+        struct flock flock = {
+                .l_type = F_WRLCK,
+                .l_whence = SEEK_SET,
+                .l_start = 0,
+                .l_len = 0,
+        };
+
+        const char *path;
+        int fd, r;
+
+        /* This is roughly the same as lckpwdf(), but not as awful. We
+         * don't want to use alarm() and signals, hence we implement
+         * our own trivial version of this.
+         *
+         * Note that shadow-utils also takes per-database locks in
+         * addition to lckpwdf(). However, we don't given that they
+         * are redundant as they they invoke lckpwdf() first and keep
+         * it during everything they do. The per-database locks are
+         * awfully racy, and thus we just won't do them. */
+
+        if (root)
+                path = prefix_roota(root, "/etc/.pwd.lock");
+        else
+                path = "/etc/.pwd.lock";
+
+        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
+        if (fd < 0)
+                return -errno;
+
+        r = fcntl(fd, F_SETLKW, &flock);
+        if (r < 0) {
+                safe_close(fd);
+                return -errno;
+        }
+
+        return fd;
+}
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
new file mode 100644 (file)
index 0000000..11ff667
--- /dev/null
@@ -0,0 +1,67 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+
+bool uid_is_valid(uid_t uid);
+
+static inline bool gid_is_valid(gid_t gid) {
+        return uid_is_valid((uid_t) gid);
+}
+
+int parse_uid(const char *s, uid_t* ret_uid);
+
+static inline int parse_gid(const char *s, gid_t *ret_gid) {
+        return parse_uid(s, (uid_t*) ret_gid);
+}
+
+char* getlogname_malloc(void);
+char* getusername_malloc(void);
+
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
+int get_group_creds(const char **groupname, gid_t *gid);
+
+char* uid_to_name(uid_t uid);
+char* gid_to_name(gid_t gid);
+
+int in_gid(gid_t gid);
+int in_group(const char *name);
+
+int get_home_dir(char **ret);
+int get_shell(char **_ret);
+
+int reset_uid_gid(void);
+
+int take_etc_passwd_lock(const char *root);
+
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+
+/* The following macros add 1 when converting things, since UID 0 is a
+ * valid UID, while the pointer NULL is special */
+#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
+#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
+#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
index 800884ffee99c77b36c6c16f35015a70442409fa..7600d9990322149202df847b712a537e76963599 100644 (file)
@@ -49,6 +49,8 @@
 #include <string.h>
 #include <stdbool.h>
 
+#include "alloc-util.h"
+#include "hexdecoct.h"
 #include "utf8.h"
 #include "util.h"
 
index ca5e4befa06587628d66496713b4cd850e3a71ef..08bdcd28f256abc52323d62c9290da7a4765fcbf 100644 (file)
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <glob.h>
 #include <grp.h>
 #include <langinfo.h>
 #include <libintl.h>
 #include <limits.h>
 #include <linux/magic.h>
+#include <linux/oom.h>
 #include <linux/sched.h>
 #include <locale.h>
-#include <netinet/ip.h>
 #include <poll.h>
 #include <pwd.h>
 #include <sched.h>
@@ -46,7 +45,6 @@
 #include <sys/mount.h>
 #include <sys/personality.h>
 #include <sys/prctl.h>
-#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/time.h>
@@ -54,7 +52,6 @@
 #include <sys/utsname.h>
 #include <sys/vfs.h>
 #include <sys/wait.h>
-#include <sys/xattr.h>
 #include <syslog.h>
 #include <unistd.h>
 
  * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
 #include <linux/fs.h>
 
+#include "alloc-util.h"
 #include "build.h"
 #include "def.h"
 #include "device-nodes.h"
 #include "env-util.h"
+#include "escape.h"
 #include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
 #include "gunicode.h"
 #include "macro.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "signal-util.h"
 #include "sparse-endian.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "user-util.h"
 #include "utf8.h"
 #include "util.h"
 #include "virt.h"
+#include "dirent-util.h"
+#include "stat-util.h"
 
 /* Put this test here for a lack of better place */
 assert_cc(EAGAIN == EWOULDBLOCK);
@@ -118,6646 +125,712 @@ size_t page_size(void) {
         return pgsz;
 }
 
-int strcmp_ptr(const char *a, const char *b) {
-
-        /* Like strcmp(), but tries to make sense of NULL pointers */
-        if (a && b)
-                return strcmp(a, b);
-
-        if (!a && b)
-                return -1;
-
-        if (a && !b)
-                return 1;
-
-        return 0;
-}
-
-bool streq_ptr(const char *a, const char *b) {
-        return strcmp_ptr(a, b) == 0;
-}
-
-char* endswith(const char *s, const char *postfix) {
-        size_t sl, pl;
-
-        assert(s);
-        assert(postfix);
+static int do_execute(char **directories, usec_t timeout, char *argv[]) {
+        _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
+        _cleanup_set_free_free_ Set *seen = NULL;
+        char **directory;
 
-        sl = strlen(s);
-        pl = strlen(postfix);
+        /* We fork this all off from a child process so that we can
+         * somewhat cleanly make use of SIGALRM to set a time limit */
 
-        if (pl == 0)
-                return (char*) s + sl;
+        (void) reset_all_signal_handlers();
+        (void) reset_signal_mask();
 
-        if (sl < pl)
-                return NULL;
+        assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
 
-        if (memcmp(s + sl - pl, postfix, pl) != 0)
-                return NULL;
+        pids = hashmap_new(NULL);
+        if (!pids)
+                return log_oom();
 
-        return (char*) s + sl - pl;
-}
+        seen = set_new(&string_hash_ops);
+        if (!seen)
+                return log_oom();
 
-char* endswith_no_case(const char *s, const char *postfix) {
-        size_t sl, pl;
+        STRV_FOREACH(directory, directories) {
+                _cleanup_closedir_ DIR *d;
+                struct dirent *de;
 
-        assert(s);
-        assert(postfix);
+                d = opendir(*directory);
+                if (!d) {
+                        if (errno == ENOENT)
+                                continue;
 
-        sl = strlen(s);
-        pl = strlen(postfix);
+                        return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
+                }
 
-        if (pl == 0)
-                return (char*) s + sl;
+                FOREACH_DIRENT(de, d, break) {
+                        _cleanup_free_ char *path = NULL;
+                        pid_t pid;
+                        int r;
 
-        if (sl < pl)
-                return NULL;
+                        if (!dirent_is_file(de))
+                                continue;
 
-        if (strcasecmp(s + sl - pl, postfix) != 0)
-                return NULL;
+                        if (set_contains(seen, de->d_name)) {
+                                log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
+                                continue;
+                        }
 
-        return (char*) s + sl - pl;
-}
+                        r = set_put_strdup(seen, de->d_name);
+                        if (r < 0)
+                                return log_oom();
 
-char* first_word(const char *s, const char *word) {
-        size_t sl, wl;
-        const char *p;
+                        path = strjoin(*directory, "/", de->d_name, NULL);
+                        if (!path)
+                                return log_oom();
 
-        assert(s);
-        assert(word);
+                        if (null_or_empty_path(path)) {
+                                log_debug("%s is empty (a mask).", path);
+                                continue;
+                        }
 
-        /* Checks if the string starts with the specified word, either
-         * followed by NUL or by whitespace. Returns a pointer to the
-         * NUL or the first character after the whitespace. */
+                        pid = fork();
+                        if (pid < 0) {
+                                log_error_errno(errno, "Failed to fork: %m");
+                                continue;
+                        } else if (pid == 0) {
+                                char *_argv[2];
 
-        sl = strlen(s);
-        wl = strlen(word);
+                                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
 
-        if (sl < wl)
-                return NULL;
+                                if (!argv) {
+                                        _argv[0] = path;
+                                        _argv[1] = NULL;
+                                        argv = _argv;
+                                } else
+                                        argv[0] = path;
 
-        if (wl == 0)
-                return (char*) s;
+                                execv(path, argv);
+                                return log_error_errno(errno, "Failed to execute %s: %m", path);
+                        }
 
-        if (memcmp(s, word, wl) != 0)
-                return NULL;
+                        log_debug("Spawned %s as " PID_FMT ".", path, pid);
 
-        p = s + wl;
-        if (*p == 0)
-                return (char*) p;
+                        r = hashmap_put(pids, UINT_TO_PTR(pid), path);
+                        if (r < 0)
+                                return log_oom();
+                        path = NULL;
+                }
+        }
 
-        if (!strchr(WHITESPACE, *p))
-                return NULL;
+        /* Abort execution of this process after the timout. We simply
+         * rely on SIGALRM as default action terminating the process,
+         * and turn on alarm(). */
 
-        p += strspn(p, WHITESPACE);
-        return (char*) p;
-}
+        if (timeout != USEC_INFINITY)
+                alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
 
-size_t cescape_char(char c, char *buf) {
-        char * buf_old = buf;
+        while (!hashmap_isempty(pids)) {
+                _cleanup_free_ char *path = NULL;
+                pid_t pid;
 
-        switch (c) {
+                pid = PTR_TO_UINT(hashmap_first_key(pids));
+                assert(pid > 0);
 
-                case '\a':
-                        *(buf++) = '\\';
-                        *(buf++) = 'a';
-                        break;
-                case '\b':
-                        *(buf++) = '\\';
-                        *(buf++) = 'b';
-                        break;
-                case '\f':
-                        *(buf++) = '\\';
-                        *(buf++) = 'f';
-                        break;
-                case '\n':
-                        *(buf++) = '\\';
-                        *(buf++) = 'n';
-                        break;
-                case '\r':
-                        *(buf++) = '\\';
-                        *(buf++) = 'r';
-                        break;
-                case '\t':
-                        *(buf++) = '\\';
-                        *(buf++) = 't';
-                        break;
-                case '\v':
-                        *(buf++) = '\\';
-                        *(buf++) = 'v';
-                        break;
-                case '\\':
-                        *(buf++) = '\\';
-                        *(buf++) = '\\';
-                        break;
-                case '"':
-                        *(buf++) = '\\';
-                        *(buf++) = '"';
-                        break;
-                case '\'':
-                        *(buf++) = '\\';
-                        *(buf++) = '\'';
-                        break;
+                path = hashmap_remove(pids, UINT_TO_PTR(pid));
+                assert(path);
 
-                default:
-                        /* For special chars we prefer octal over
-                         * hexadecimal encoding, simply because glib's
-                         * g_strescape() does the same */
-                        if ((c < ' ') || (c >= 127)) {
-                                *(buf++) = '\\';
-                                *(buf++) = octchar((unsigned char) c >> 6);
-                                *(buf++) = octchar((unsigned char) c >> 3);
-                                *(buf++) = octchar((unsigned char) c);
-                        } else
-                                *(buf++) = c;
-                        break;
+                wait_for_terminate_and_warn(path, pid, true);
         }
 
-        return buf - buf_old;
+        return 0;
 }
 
-int close_nointr(int fd) {
-        assert(fd >= 0);
-
-        if (close(fd) >= 0)
-                return 0;
-
-        /*
-         * Just ignore EINTR; a retry loop is the wrong thing to do on
-         * Linux.
-         *
-         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
-         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
-         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
-         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
-         */
-        if (errno == EINTR)
-                return 0;
-
-        return -errno;
-}
+void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
+        pid_t executor_pid;
+        int r;
+        char *name;
+        char **dirs = (char**) directories;
 
-int safe_close(int fd) {
+        assert(!strv_isempty(dirs));
 
-        /*
-         * Like close_nointr() but cannot fail. Guarantees errno is
-         * unchanged. Is a NOP with negative fds passed, and returns
-         * -1, so that it can be used in this syntax:
-         *
-         * fd = safe_close(fd);
-         */
+        name = basename(dirs[0]);
+        assert(!isempty(name));
 
-        if (fd >= 0) {
-                PROTECT_ERRNO;
+        /* Executes all binaries in the directories in parallel and waits
+         * for them to finish. Optionally a timeout is applied. If a file
+         * with the same name exists in more than one directory, the
+         * earliest one wins. */
 
-                /* The kernel might return pretty much any error code
-                 * via close(), but the fd will be closed anyway. The
-                 * only condition we want to check for here is whether
-                 * the fd was invalid at all... */
+        executor_pid = fork();
+        if (executor_pid < 0) {
+                log_error_errno(errno, "Failed to fork: %m");
+                return;
 
-                assert_se(close_nointr(fd) != -EBADF);
+        } else if (executor_pid == 0) {
+                r = do_execute(dirs, timeout, argv);
+                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
         }
 
-        return -1;
+        wait_for_terminate_and_warn(name, executor_pid, true);
 }
 
-void close_many(const int fds[], unsigned n_fd) {
-        unsigned i;
-
-        assert(fds || n_fd <= 0);
-
-        for (i = 0; i < n_fd; i++)
-                safe_close(fds[i]);
+bool plymouth_running(void) {
+        return access("/run/plymouth/pid", F_OK) >= 0;
 }
 
-int fclose_nointr(FILE *f) {
-        assert(f);
-
-        /* Same as close_nointr(), but for fclose() */
-
-        if (fclose(f) == 0)
-                return 0;
-
-        if (errno == EINTR)
-                return 0;
+bool display_is_local(const char *display) {
+        assert(display);
 
-        return -errno;
+        return
+                display[0] == ':' &&
+                display[1] >= '0' &&
+                display[1] <= '9';
 }
 
-FILE* safe_fclose(FILE *f) {
-
-        /* Same as safe_close(), but for fclose() */
+int socket_from_display(const char *display, char **path) {
+        size_t k;
+        char *f, *c;
 
-        if (f) {
-                PROTECT_ERRNO;
+        assert(display);
+        assert(path);
 
-                assert_se(fclose_nointr(f) != EBADF);
-        }
+        if (!display_is_local(display))
+                return -EINVAL;
 
-        return NULL;
-}
+        k = strspn(display+1, "0123456789");
 
-DIR* safe_closedir(DIR *d) {
+        f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
+        if (!f)
+                return -ENOMEM;
 
-        if (d) {
-                PROTECT_ERRNO;
+        c = stpcpy(f, "/tmp/.X11-unix/X");
+        memcpy(c, display+1, k);
+        c[k] = 0;
 
-                assert_se(closedir(d) >= 0 || errno != EBADF);
-        }
+        *path = f;
 
-        return NULL;
+        return 0;
 }
 
-int unlink_noerrno(const char *path) {
-        PROTECT_ERRNO;
+int block_get_whole_disk(dev_t d, dev_t *ret) {
+        char *p, *s;
         int r;
+        unsigned n, m;
 
-        r = unlink(path);
-        if (r < 0)
-                return -errno;
+        assert(ret);
 
-        return 0;
-}
+        /* If it has a queue this is good enough for us */
+        if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
+                return -ENOMEM;
 
-int parse_boolean(const char *v) {
-        assert(v);
+        r = access(p, F_OK);
+        free(p);
 
-        if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
-                return 1;
-        else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
+        if (r >= 0) {
+                *ret = d;
                 return 0;
+        }
 
-        return -EINVAL;
-}
-
-int parse_pid(const char *s, pid_t* ret_pid) {
-        unsigned long ul = 0;
-        pid_t pid;
-        int r;
+        /* If it is a partition find the originating device */
+        if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
+                return -ENOMEM;
 
-        assert(s);
-        assert(ret_pid);
+        r = access(p, F_OK);
+        free(p);
 
-        r = safe_atolu(s, &ul);
         if (r < 0)
-                return r;
-
-        pid = (pid_t) ul;
-
-        if ((unsigned long) pid != ul)
-                return -ERANGE;
-
-        if (pid <= 0)
-                return -ERANGE;
-
-        *ret_pid = pid;
-        return 0;
-}
-
-bool uid_is_valid(uid_t uid) {
-
-        /* Some libc APIs use UID_INVALID as special placeholder */
-        if (uid == (uid_t) 0xFFFFFFFF)
-                return false;
-
-        /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
-        if (uid == (uid_t) 0xFFFF)
-                return false;
-
-        return true;
-}
+                return -ENOENT;
 
-int parse_uid(const char *s, uid_t* ret_uid) {
-        unsigned long ul = 0;
-        uid_t uid;
-        int r;
+        /* Get parent dev_t */
+        if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
+                return -ENOMEM;
 
-        assert(s);
+        r = read_one_line_file(p, &s);
+        free(p);
 
-        r = safe_atolu(s, &ul);
         if (r < 0)
                 return r;
 
-        uid = (uid_t) ul;
-
-        if ((unsigned long) uid != ul)
-                return -ERANGE;
-
-        if (!uid_is_valid(uid))
-                return -ENXIO; /* we return ENXIO instead of EINVAL
-                                * here, to make it easy to distuingish
-                                * invalid numeric uids invalid
-                                * strings. */
-
-        if (ret_uid)
-                *ret_uid = uid;
+        r = sscanf(s, "%u:%u", &m, &n);
+        free(s);
 
-        return 0;
-}
+        if (r != 2)
+                return -EINVAL;
 
-int safe_atou(const char *s, unsigned *ret_u) {
-        char *x = NULL;
-        unsigned long l;
+        /* Only return this if it is really good enough for us. */
+        if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
+                return -ENOMEM;
 
-        assert(s);
-        assert(ret_u);
+        r = access(p, F_OK);
+        free(p);
 
-        errno = 0;
-        l = strtoul(s, &x, 0);
+        if (r >= 0) {
+                *ret = makedev(m, n);
+                return 0;
+        }
 
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
+        return -ENOENT;
+}
 
-        if ((unsigned long) (unsigned) l != l)
-                return -ERANGE;
+bool kexec_loaded(void) {
+       bool loaded = false;
+       char *s;
 
-        *ret_u = (unsigned) l;
-        return 0;
+       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
+               if (s[0] == '1')
+                       loaded = true;
+               free(s);
+       }
+       return loaded;
 }
 
-int safe_atoi(const char *s, int *ret_i) {
-        char *x = NULL;
-        long l;
-
-        assert(s);
-        assert(ret_i);
+int prot_from_flags(int flags) {
 
-        errno = 0;
-        l = strtol(s, &x, 0);
+        switch (flags & O_ACCMODE) {
 
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
+        case O_RDONLY:
+                return PROT_READ;
 
-        if ((long) (int) l != l)
-                return -ERANGE;
+        case O_WRONLY:
+                return PROT_WRITE;
 
-        *ret_i = (int) l;
-        return 0;
-}
-
-int safe_atou8(const char *s, uint8_t *ret) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(ret);
-
-        errno = 0;
-        l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
-        if ((unsigned long) (uint8_t) l != l)
-                return -ERANGE;
-
-        *ret = (uint8_t) l;
-        return 0;
-}
-
-int safe_atou16(const char *s, uint16_t *ret) {
-        char *x = NULL;
-        unsigned long l;
-
-        assert(s);
-        assert(ret);
-
-        errno = 0;
-        l = strtoul(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
-        if ((unsigned long) (uint16_t) l != l)
-                return -ERANGE;
-
-        *ret = (uint16_t) l;
-        return 0;
-}
-
-int safe_atoi16(const char *s, int16_t *ret) {
-        char *x = NULL;
-        long l;
-
-        assert(s);
-        assert(ret);
-
-        errno = 0;
-        l = strtol(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno > 0 ? -errno : -EINVAL;
-
-        if ((long) (int16_t) l != l)
-                return -ERANGE;
-
-        *ret = (int16_t) l;
-        return 0;
-}
-
-int safe_atollu(const char *s, long long unsigned *ret_llu) {
-        char *x = NULL;
-        unsigned long long l;
-
-        assert(s);
-        assert(ret_llu);
-
-        errno = 0;
-        l = strtoull(s, &x, 0);
-
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        case O_RDWR:
+                return PROT_READ|PROT_WRITE;
 
-        *ret_llu = l;
-        return 0;
+        default:
+                return -EINVAL;
+        }
 }
 
-int safe_atolli(const char *s, long long int *ret_lli) {
-        char *x = NULL;
-        long long l;
-
-        assert(s);
-        assert(ret_lli);
-
-        errno = 0;
-        l = strtoll(s, &x, 0);
+int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
+        bool stdout_is_tty, stderr_is_tty;
+        pid_t parent_pid, agent_pid;
+        sigset_t ss, saved_ss;
+        unsigned n, i;
+        va_list ap;
+        char **l;
 
-        if (!x || x == s || *x || errno)
-                return errno ? -errno : -EINVAL;
+        assert(pid);
+        assert(path);
 
-        *ret_lli = l;
-        return 0;
-}
+        /* Spawns a temporary TTY agent, making sure it goes away when
+         * we go away */
 
-int safe_atod(const char *s, double *ret_d) {
-        char *x = NULL;
-        double d = 0;
-        locale_t loc;
+        parent_pid = getpid();
 
-        assert(s);
-        assert(ret_d);
+        /* First we temporarily block all signals, so that the new
+         * child has them blocked initially. This way, we can be sure
+         * that SIGTERMs are not lost we might send to the agent. */
+        assert_se(sigfillset(&ss) >= 0);
+        assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
 
-        loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
-        if (loc == (locale_t) 0)
+        agent_pid = fork();
+        if (agent_pid < 0) {
+                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
                 return -errno;
-
-        errno = 0;
-        d = strtod_l(s, &x, loc);
-
-        if (!x || x == s || *x || errno) {
-                freelocale(loc);
-                return errno ? -errno : -EINVAL;
         }
 
-        freelocale(loc);
-        *ret_d = (double) d;
-        return 0;
-}
-
-static size_t strcspn_escaped(const char *s, const char *reject) {
-        bool escaped = false;
-        int n;
-
-        for (n=0; s[n]; n++) {
-                if (escaped)
-                        escaped = false;
-                else if (s[n] == '\\')
-                        escaped = true;
-                else if (strchr(reject, s[n]))
-                        break;
+        if (agent_pid != 0) {
+                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
+                *pid = agent_pid;
+                return 0;
         }
 
-        /* if s ends in \, return index of previous char */
-        return n - escaped;
-}
+        /* In the child:
+         *
+         * Make sure the agent goes away when the parent dies */
+        if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+                _exit(EXIT_FAILURE);
 
-/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
-        const char *current;
+        /* Make sure we actually can kill the agent, if we need to, in
+         * case somebody invoked us from a shell script that trapped
+         * SIGTERM or so... */
+        (void) reset_all_signal_handlers();
+        (void) reset_signal_mask();
 
-        current = *state;
+        /* Check whether our parent died before we were able
+         * to set the death signal and unblock the signals */
+        if (getppid() != parent_pid)
+                _exit(EXIT_SUCCESS);
 
-        if (!*current) {
-                assert(**state == '\0');
-                return NULL;
-        }
+        /* Don't leak fds to the agent */
+        close_all_fds(except, n_except);
 
-        current += strspn(current, separator);
-        if (!*current) {
-                *state = current;
-                return NULL;
-        }
+        stdout_is_tty = isatty(STDOUT_FILENO);
+        stderr_is_tty = isatty(STDERR_FILENO);
 
-        if (quoted && strchr("\'\"", *current)) {
-                char quotechars[2] = {*current, '\0'};
+        if (!stdout_is_tty || !stderr_is_tty) {
+                int fd;
 
-                *l = strcspn_escaped(current + 1, quotechars);
-                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
-                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
-                        /* right quote missing or garbage at the end */
-                        *state = current;
-                        return NULL;
-                }
-                *state = current++ + *l + 2;
-        } else if (quoted) {
-                *l = strcspn_escaped(current, separator);
-                if (current[*l] && !strchr(separator, current[*l])) {
-                        /* unfinished escape */
-                        *state = current;
-                        return NULL;
+                /* Detach from stdout/stderr. and reopen
+                 * /dev/tty for them. This is important to
+                 * ensure that when systemctl is started via
+                 * popen() or a similar call that expects to
+                 * read EOF we actually do generate EOF and
+                 * not delay this indefinitely by because we
+                 * keep an unused copy of stdin around. */
+                fd = open("/dev/tty", O_WRONLY);
+                if (fd < 0) {
+                        log_error_errno(errno, "Failed to open /dev/tty: %m");
+                        _exit(EXIT_FAILURE);
                 }
-                *state = current + *l;
-        } else {
-                *l = strcspn(current, separator);
-                *state = current + *l;
-        }
-
-        return current;
-}
-
-int fchmod_umask(int fd, mode_t m) {
-        mode_t u;
-        int r;
-
-        u = umask(0777);
-        r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
-        umask(u);
-
-        return r;
-}
-
-char *truncate_nl(char *s) {
-        assert(s);
-
-        s[strcspn(s, NEWLINE)] = 0;
-        return s;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
-        size_t a;
-        char *r;
-
-        if (!s && !suffix)
-                return strdup("");
-
-        if (!s)
-                return strndup(suffix, b);
-
-        if (!suffix)
-                return strdup(s);
-
-        assert(s);
-        assert(suffix);
-
-        a = strlen(s);
-        if (b > ((size_t) -1) - a)
-                return NULL;
-
-        r = new(char, a+b+1);
-        if (!r)
-                return NULL;
 
-        memcpy(r, s, a);
-        memcpy(r+a, suffix, b);
-        r[a+b] = 0;
-
-        return r;
-}
-
-char *strappend(const char *s, const char *suffix) {
-        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
-}
-
-int readlinkat_malloc(int fd, const char *p, char **ret) {
-        size_t l = 100;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        for (;;) {
-                char *c;
-                ssize_t n;
-
-                c = new(char, l);
-                if (!c)
-                        return -ENOMEM;
-
-                n = readlinkat(fd, p, c, l-1);
-                if (n < 0) {
-                        r = -errno;
-                        free(c);
-                        return r;
-                }
+                if (!stdout_is_tty)
+                        dup2(fd, STDOUT_FILENO);
 
-                if ((size_t) n < l-1) {
-                        c[n] = 0;
-                        *ret = c;
-                        return 0;
-                }
+                if (!stderr_is_tty)
+                        dup2(fd, STDERR_FILENO);
 
-                free(c);
-                l *= 2;
+                if (fd > 2)
+                        close(fd);
         }
-}
 
-int readlink_malloc(const char *p, char **ret) {
-        return readlinkat_malloc(AT_FDCWD, p, ret);
-}
-
-int readlink_value(const char *p, char **ret) {
-        _cleanup_free_ char *link = NULL;
-        char *value;
-        int r;
-
-        r = readlink_malloc(p, &link);
-        if (r < 0)
-                return r;
-
-        value = basename(link);
-        if (!value)
-                return -ENOENT;
+        /* Count arguments */
+        va_start(ap, path);
+        for (n = 0; va_arg(ap, char*); n++)
+                ;
+        va_end(ap);
 
-        value = strdup(value);
-        if (!value)
-                return -ENOMEM;
+        /* Allocate strv */
+        l = alloca(sizeof(char *) * (n + 1));
 
-        *ret = value;
+        /* Fill in arguments */
+        va_start(ap, path);
+        for (i = 0; i <= n; i++)
+                l[i] = va_arg(ap, char*);
+        va_end(ap);
 
-        return 0;
+        execv(path, l);
+        _exit(EXIT_FAILURE);
 }
 
-int readlink_and_make_absolute(const char *p, char **r) {
-        _cleanup_free_ char *target = NULL;
-        char *k;
-        int j;
+bool in_initrd(void) {
+        static int saved = -1;
+        struct statfs s;
 
-        assert(p);
-        assert(r);
+        if (saved >= 0)
+                return saved;
 
-        j = readlink_malloc(p, &target);
-        if (j < 0)
-                return j;
+        /* We make two checks here:
+         *
+         * 1. the flag file /etc/initrd-release must exist
+         * 2. the root file system must be a memory file system
+         *
+         * The second check is extra paranoia, since misdetecting an
+         * initrd can have bad bad consequences due the initrd
+         * emptying when transititioning to the main systemd.
+         */
 
-        k = file_in_same_dir(p, target);
-        if (!k)
-                return -ENOMEM;
+        saved = access("/etc/initrd-release", F_OK) >= 0 &&
+                statfs("/", &s) >= 0 &&
+                is_temporary_fs(&s);
 
-        *r = k;
-        return 0;
+        return saved;
 }
 
-int readlink_and_canonicalize(const char *p, char **r) {
-        char *t, *s;
-        int j;
-
-        assert(p);
-        assert(r);
-
-        j = readlink_and_make_absolute(p, &t);
-        if (j < 0)
-                return j;
-
-        s = canonicalize_file_name(t);
-        if (s) {
-                free(t);
-                *r = s;
-        } else
-                *r = t;
-
-        path_kill_slashes(*r);
+/* hey glibc, APIs with callbacks without a user pointer are so useless */
+void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
+                 int (*compar) (const void *, const void *, void *), void *arg) {
+        size_t l, u, idx;
+        const void *p;
+        int comparison;
 
-        return 0;
+        l = 0;
+        u = nmemb;
+        while (l < u) {
+                idx = (l + u) / 2;
+                p = (void *)(((const char *) base) + (idx * size));
+                comparison = compar(key, p, arg);
+                if (comparison < 0)
+                        u = idx;
+                else if (comparison > 0)
+                        l = idx + 1;
+                else
+                        return (void *)p;
+        }
+        return NULL;
 }
 
-char *strstrip(char *s) {
-        char *e;
-
-        /* Drops trailing whitespace. Modifies the string in
-         * place. Returns pointer to first non-space character */
-
-        s += strspn(s, WHITESPACE);
-
-        for (e = strchr(s, 0); e > s; e --)
-                if (!strchr(WHITESPACE, e[-1]))
-                        break;
+int on_ac_power(void) {
+        bool found_offline = false, found_online = false;
+        _cleanup_closedir_ DIR *d = NULL;
 
-        *e = 0;
+        d = opendir("/sys/class/power_supply");
+        if (!d)
+                return errno == ENOENT ? true : -errno;
 
-        return s;
-}
+        for (;;) {
+                struct dirent *de;
+                _cleanup_close_ int fd = -1, device = -1;
+                char contents[6];
+                ssize_t n;
 
-char *delete_chars(char *s, const char *bad) {
-        char *f, *t;
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return -errno;
 
-        /* Drops all whitespace, regardless where in the string */
+                if (!de)
+                        break;
 
-        for (f = s, t = s; *f; f++) {
-                if (strchr(bad, *f))
+                if (hidden_file(de->d_name))
                         continue;
 
-                *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return s;
-}
-
-char *file_in_same_dir(const char *path, const char *filename) {
-        char *e, *ret;
-        size_t k;
-
-        assert(path);
-        assert(filename);
-
-        /* This removes the last component of path and appends
-         * filename, unless the latter is absolute anyway or the
-         * former isn't */
-
-        if (path_is_absolute(filename))
-                return strdup(filename);
-
-        e = strrchr(path, '/');
-        if (!e)
-                return strdup(filename);
-
-        k = strlen(filename);
-        ret = new(char, (e + 1 - path) + k + 1);
-        if (!ret)
-                return NULL;
-
-        memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
-        return ret;
-}
-
-int rmdir_parents(const char *path, const char *stop) {
-        size_t l;
-        int r = 0;
-
-        assert(path);
-        assert(stop);
-
-        l = strlen(path);
-
-        /* Skip trailing slashes */
-        while (l > 0 && path[l-1] == '/')
-                l--;
-
-        while (l > 0) {
-                char *t;
-
-                /* Skip last component */
-                while (l > 0 && path[l-1] != '/')
-                        l--;
-
-                /* Skip trailing slashes */
-                while (l > 0 && path[l-1] == '/')
-                        l--;
-
-                if (l <= 0)
-                        break;
-
-                if (!(t = strndup(path, l)))
-                        return -ENOMEM;
-
-                if (path_startswith(stop, t)) {
-                        free(t);
-                        return 0;
-                }
-
-                r = rmdir(t);
-                free(t);
-
-                if (r < 0)
-                        if (errno != ENOENT)
-                                return -errno;
-        }
-
-        return 0;
-}
-
-char hexchar(int x) {
-        static const char table[16] = "0123456789abcdef";
-
-        return table[x & 15];
-}
-
-int unhexchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        if (c >= 'a' && c <= 'f')
-                return c - 'a' + 10;
-
-        if (c >= 'A' && c <= 'F')
-                return c - 'A' + 10;
-
-        return -EINVAL;
-}
-
-char *hexmem(const void *p, size_t l) {
-        char *r, *z;
-        const uint8_t *x;
-
-        z = r = malloc(l * 2 + 1);
-        if (!r)
-                return NULL;
-
-        for (x = p; x < (const uint8_t*) p + l; x++) {
-                *(z++) = hexchar(*x >> 4);
-                *(z++) = hexchar(*x & 15);
-        }
-
-        *z = 0;
-        return r;
-}
-
-int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
-        _cleanup_free_ uint8_t *r = NULL;
-        uint8_t *z;
-        const char *x;
-
-        assert(mem);
-        assert(len);
-        assert(p);
-
-        z = r = malloc((l + 1) / 2 + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (x = p; x < p + l; x += 2) {
-                int a, b;
-
-                a = unhexchar(x[0]);
-                if (a < 0)
-                        return a;
-                else if (x+1 < p + l) {
-                        b = unhexchar(x[1]);
-                        if (b < 0)
-                                return b;
-                } else
-                        b = 0;
-
-                *(z++) = (uint8_t) a << 4 | (uint8_t) b;
-        }
-
-        *z = 0;
-
-        *mem = r;
-        r = NULL;
-        *len = (l + 1) / 2;
-
-        return 0;
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-6
- * Notice that base32hex differs from base32 in the alphabet it uses.
- * The distinction is that the base32hex representation preserves the
- * order of the underlying data when compared as bytestrings, this is
- * useful when representing NSEC3 hashes, as one can then verify the
- * order of hashes directly from their representation. */
-char base32hexchar(int x) {
-        static const char table[32] = "0123456789"
-                                      "ABCDEFGHIJKLMNOPQRSTUV";
-
-        return table[x & 31];
-}
-
-int unbase32hexchar(char c) {
-        unsigned offset;
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        offset = '9' - '0' + 1;
-
-        if (c >= 'A' && c <= 'V')
-                return c - 'A' + offset;
-
-        return -EINVAL;
-}
-
-char *base32hexmem(const void *p, size_t l, bool padding) {
-        char *r, *z;
-        const uint8_t *x;
-        size_t len;
-
-        if (padding)
-                /* five input bytes makes eight output bytes, padding is added so we must round up */
-                len = 8 * (l + 4) / 5;
-        else {
-                /* same, but round down as there is no padding */
-                len = 8 * l / 5;
-
-                switch (l % 5) {
-                case 4:
-                        len += 7;
-                        break;
-                case 3:
-                        len += 5;
-                        break;
-                case 2:
-                        len += 4;
-                        break;
-                case 1:
-                        len += 2;
-                        break;
-                }
-        }
-
-        z = r = malloc(len + 1);
-        if (!r)
-                return NULL;
-
-        for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
-                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
-                   x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
-                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);  /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
-                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
-                *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5);  /* 000QQWWW */
-                *(z++) = base32hexchar((x[4] & 31));                  /* 000WWWWW */
-        }
-
-        switch (l % 5) {
-        case 4:
-                *(z++) = base32hexchar(x[0] >> 3);                    /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6);  /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);             /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4);   /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
-                *(z++) = base32hexchar((x[3] & 127) >> 2);            /* 000QQQQQ */
-                *(z++) = base32hexchar((x[3] & 3) << 3);              /* 000QQ000 */
-                if (padding)
-                        *(z++) = '=';
-
-                break;
-
-        case 3:
-                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
-                *(z++) = base32hexchar((x[2] & 15) << 1);            /* 000ZZZZ0 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-
-        case 2:
-                *(z++) = base32hexchar(x[0] >> 3);                   /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
-                *(z++) = base32hexchar((x[1] & 63) >> 1);            /* 000YYYYY */
-                *(z++) = base32hexchar((x[1] & 1) << 4);             /* 000Y0000 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-
-        case 1:
-                *(z++) = base32hexchar(x[0] >> 3);       /* 000XXXXX */
-                *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
-                if (padding) {
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                        *(z++) = '=';
-                }
-
-                break;
-        }
-
-        *z = 0;
-        return r;
-}
-
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
-        _cleanup_free_ uint8_t *r = NULL;
-        int a, b, c, d, e, f, g, h;
-        uint8_t *z;
-        const char *x;
-        size_t len;
-        unsigned pad = 0;
-
-        assert(p);
-
-        /* padding ensures any base32hex input has input divisible by 8 */
-        if (padding && l % 8 != 0)
-                return -EINVAL;
-
-        if (padding) {
-                /* strip the padding */
-                while (l > 0 && p[l - 1] == '=' && pad < 7) {
-                        pad ++;
-                        l --;
-                }
-        }
-
-        /* a group of eight input bytes needs five output bytes, in case of
-           padding we need to add some extra bytes */
-        len = (l / 8) * 5;
-
-        switch (l % 8) {
-        case 7:
-                len += 4;
-                break;
-        case 5:
-                len += 3;
-                break;
-        case 4:
-                len += 2;
-                break;
-        case 2:
-                len += 1;
-                break;
-        case 0:
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        z = r = malloc(len + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (x = p; x < p + (l / 8) * 8; x += 8) {
-                /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
-                   e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                f = unbase32hexchar(x[5]);
-                if (f < 0)
-                        return -EINVAL;
-
-                g = unbase32hexchar(x[6]);
-                if (g < 0)
-                        return -EINVAL;
-
-                h = unbase32hexchar(x[7]);
-                if (h < 0)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
-                *(z++) = (uint8_t) g << 5 | (uint8_t) h;                         /* VVVRRRRR */
-        }
-
-        switch (l % 8) {
-        case 7:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                f = unbase32hexchar(x[5]);
-                if (f < 0)
-                        return -EINVAL;
-
-                g = unbase32hexchar(x[6]);
-                if (g < 0)
-                        return -EINVAL;
-
-                /* g == 000VV000 */
-                if (g & 7)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-                *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
-
-                break;
-        case 5:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                e = unbase32hexchar(x[4]);
-                if (e < 0)
-                        return -EINVAL;
-
-                /* e == 000SSSS0 */
-                if (e & 1)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-                *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1;                    /* WWWWSSSS */
-
-                break;
-        case 4:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase32hexchar(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase32hexchar(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                /* d == 000W0000 */
-                if (d & 15)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2;                    /* XXXXXYYY */
-                *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-
-                break;
-        case 2:
-                a = unbase32hexchar(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase32hexchar(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* b == 000YYY00 */
-                if (b & 3)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
-
-                break;
-        case 0:
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        *z = 0;
-
-        *mem = r;
-        r = NULL;
-        *_len = len;
-
-        return 0;
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-4 */
-char base64char(int x) {
-        static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                                      "abcdefghijklmnopqrstuvwxyz"
-                                      "0123456789+/";
-        return table[x & 63];
-}
-
-int unbase64char(char c) {
-        unsigned offset;
-
-        if (c >= 'A' && c <= 'Z')
-                return c - 'A';
-
-        offset = 'Z' - 'A' + 1;
-
-        if (c >= 'a' && c <= 'z')
-                return c - 'a' + offset;
-
-        offset += 'z' - 'a' + 1;
-
-        if (c >= '0' && c <= '9')
-                return c - '0' + offset;
-
-        offset += '9' - '0' + 1;
-
-        if (c == '+')
-                return offset;
-
-        offset ++;
-
-        if (c == '/')
-                return offset;
-
-        return -EINVAL;
-}
-
-char *base64mem(const void *p, size_t l) {
-        char *r, *z;
-        const uint8_t *x;
-
-        /* three input bytes makes four output bytes, padding is added so we must round up */
-        z = r = malloc(4 * (l + 2) / 3 + 1);
-        if (!r)
-                return NULL;
-
-        for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
-                /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
-                *(z++) = base64char(x[0] >> 2);                    /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4);  /* 00XXYYYY */
-                *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
-                *(z++) = base64char(x[2] & 63);                    /* 00ZZZZZZ */
-        }
-
-        switch (l % 3) {
-        case 2:
-                *(z++) = base64char(x[0] >> 2);                   /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
-                *(z++) = base64char((x[1] & 15) << 2);            /* 00YYYY00 */
-                *(z++) = '=';
-
-                break;
-        case 1:
-                *(z++) = base64char(x[0] >> 2);        /* 00XXXXXX */
-                *(z++) = base64char((x[0] & 3) << 4);  /* 00XX0000 */
-                *(z++) = '=';
-                *(z++) = '=';
-
-                break;
-        }
-
-        *z = 0;
-        return r;
-}
-
-int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
-        _cleanup_free_ uint8_t *r = NULL;
-        int a, b, c, d;
-        uint8_t *z;
-        const char *x;
-        size_t len;
-
-        assert(p);
-
-        /* padding ensures any base63 input has input divisible by 4 */
-        if (l % 4 != 0)
-                return -EINVAL;
-
-        /* strip the padding */
-        if (l > 0 && p[l - 1] == '=')
-                l --;
-        if (l > 0 && p[l - 1] == '=')
-                l --;
-
-        /* a group of four input bytes needs three output bytes, in case of
-           padding we need to add two or three extra bytes */
-        len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
-
-        z = r = malloc(len + 1);
-        if (!r)
-                return -ENOMEM;
-
-        for (x = p; x < p + (l / 4) * 4; x += 4) {
-                /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
-                a = unbase64char(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase64char(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase64char(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                d = unbase64char(x[3]);
-                if (d < 0)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-                *(z++) = (uint8_t) c << 6 | (uint8_t) d;      /* ZZWWWWWW */
-        }
-
-        switch (l % 4) {
-        case 3:
-                a = unbase64char(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase64char(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unbase64char(x[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                /* c == 00ZZZZ00 */
-                if (c & 3)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
-                *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-
-                break;
-        case 2:
-                a = unbase64char(x[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unbase64char(x[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* b == 00YY0000 */
-                if (b & 15)
-                        return -EINVAL;
-
-                *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
-
-                break;
-        case 0:
-
-                break;
-        default:
-                return -EINVAL;
-        }
-
-        *z = 0;
-
-        *mem = r;
-        r = NULL;
-        *_len = len;
-
-        return 0;
-}
-
-char octchar(int x) {
-        return '0' + (x & 7);
-}
-
-int unoctchar(char c) {
-
-        if (c >= '0' && c <= '7')
-                return c - '0';
-
-        return -EINVAL;
-}
-
-char decchar(int x) {
-        return '0' + (x % 10);
-}
-
-int undecchar(char c) {
-
-        if (c >= '0' && c <= '9')
-                return c - '0';
-
-        return -EINVAL;
-}
-
-char *cescape(const char *s) {
-        char *r, *t;
-        const char *f;
-
-        assert(s);
-
-        /* Does C style string escaping. May be reversed with
-         * cunescape(). */
-
-        r = new(char, strlen(s)*4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; *f; f++)
-                t += cescape_char(*f, t);
-
-        *t = 0;
-
-        return r;
-}
-
-static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
-        int r = 1;
-
-        assert(p);
-        assert(*p);
-        assert(ret);
-
-        /* Unescapes C style. Returns the unescaped character in ret,
-         * unless we encountered a \u sequence in which case the full
-         * unicode character is returned in ret_unicode, instead. */
-
-        if (length != (size_t) -1 && length < 1)
-                return -EINVAL;
-
-        switch (p[0]) {
-
-        case 'a':
-                *ret = '\a';
-                break;
-        case 'b':
-                *ret = '\b';
-                break;
-        case 'f':
-                *ret = '\f';
-                break;
-        case 'n':
-                *ret = '\n';
-                break;
-        case 'r':
-                *ret = '\r';
-                break;
-        case 't':
-                *ret = '\t';
-                break;
-        case 'v':
-                *ret = '\v';
-                break;
-        case '\\':
-                *ret = '\\';
-                break;
-        case '"':
-                *ret = '"';
-                break;
-        case '\'':
-                *ret = '\'';
-                break;
-
-        case 's':
-                /* This is an extension of the XDG syntax files */
-                *ret = ' ';
-                break;
-
-        case 'x': {
-                /* hexadecimal encoding */
-                int a, b;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unhexchar(p[1]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unhexchar(p[2]);
-                if (b < 0)
-                        return -EINVAL;
-
-                /* Don't allow NUL bytes */
-                if (a == 0 && b == 0)
-                        return -EINVAL;
-
-                *ret = (char) ((a << 4U) | b);
-                r = 3;
-                break;
-        }
-
-        case 'u': {
-                /* C++11 style 16bit unicode */
-
-                int a[4];
-                unsigned i;
-                uint32_t c;
-
-                if (length != (size_t) -1 && length < 5)
-                        return -EINVAL;
-
-                for (i = 0; i < 4; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
-
-                /* Don't allow 0 chars */
-                if (c == 0)
-                        return -EINVAL;
-
-                if (c < 128)
-                        *ret = c;
-                else {
-                        if (!ret_unicode)
-                                return -EINVAL;
-
-                        *ret = 0;
-                        *ret_unicode = c;
-                }
-
-                r = 5;
-                break;
-        }
-
-        case 'U': {
-                /* C++11 style 32bit unicode */
-
-                int a[8];
-                unsigned i;
-                uint32_t c;
-
-                if (length != (size_t) -1 && length < 9)
-                        return -EINVAL;
-
-                for (i = 0; i < 8; i++) {
-                        a[i] = unhexchar(p[1 + i]);
-                        if (a[i] < 0)
-                                return a[i];
-                }
-
-                c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
-                    ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] <<  8U) | ((uint32_t) a[6] <<  4U) |  (uint32_t) a[7];
-
-                /* Don't allow 0 chars */
-                if (c == 0)
-                        return -EINVAL;
-
-                /* Don't allow invalid code points */
-                if (!unichar_is_valid(c))
-                        return -EINVAL;
-
-                if (c < 128)
-                        *ret = c;
-                else {
-                        if (!ret_unicode)
-                                return -EINVAL;
-
-                        *ret = 0;
-                        *ret_unicode = c;
-                }
-
-                r = 9;
-                break;
-        }
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7': {
-                /* octal encoding */
-                int a, b, c;
-                uint32_t m;
-
-                if (length != (size_t) -1 && length < 3)
-                        return -EINVAL;
-
-                a = unoctchar(p[0]);
-                if (a < 0)
-                        return -EINVAL;
-
-                b = unoctchar(p[1]);
-                if (b < 0)
-                        return -EINVAL;
-
-                c = unoctchar(p[2]);
-                if (c < 0)
-                        return -EINVAL;
-
-                /* don't allow NUL bytes */
-                if (a == 0 && b == 0 && c == 0)
-                        return -EINVAL;
-
-                /* Don't allow bytes above 255 */
-                m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
-                if (m > 255)
-                        return -EINVAL;
-
-                *ret = m;
-                r = 3;
-                break;
-        }
-
-        default:
-                return -EINVAL;
-        }
-
-        return r;
-}
-
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
-        char *r, *t;
-        const char *f;
-        size_t pl;
-
-        assert(s);
-        assert(ret);
-
-        /* Undoes C style string escaping, and optionally prefixes it. */
-
-        pl = prefix ? strlen(prefix) : 0;
-
-        r = new(char, pl+length+1);
-        if (!r)
-                return -ENOMEM;
-
-        if (prefix)
-                memcpy(r, prefix, pl);
-
-        for (f = s, t = r + pl; f < s + length; f++) {
-                size_t remaining;
-                uint32_t u;
-                char c;
-                int k;
-
-                remaining = s + length - f;
-                assert(remaining > 0);
-
-                if (*f != '\\') {
-                        /* A literal literal, copy verbatim */
-                        *(t++) = *f;
-                        continue;
-                }
-
-                if (remaining == 1) {
-                        if (flags & UNESCAPE_RELAX) {
-                                /* A trailing backslash, copy verbatim */
-                                *(t++) = *f;
-                                continue;
-                        }
-
-                        free(r);
-                        return -EINVAL;
-                }
-
-                k = cunescape_one(f + 1, remaining - 1, &c, &u);
-                if (k < 0) {
-                        if (flags & UNESCAPE_RELAX) {
-                                /* Invalid escape code, let's take it literal then */
-                                *(t++) = '\\';
-                                continue;
-                        }
-
-                        free(r);
-                        return k;
-                }
-
-                if (c != 0)
-                        /* Non-Unicode? Let's encode this directly */
-                        *(t++) = c;
-                else
-                        /* Unicode? Then let's encode this in UTF-8 */
-                        t += utf8_encode_unichar(t, u);
-
-                f += k;
-        }
-
-        *t = 0;
-
-        *ret = r;
-        return t - r;
-}
-
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
-        return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret) {
-        return cunescape_length(s, strlen(s), flags, ret);
-}
-
-char *xescape(const char *s, const char *bad) {
-        char *r, *t;
-        const char *f;
-
-        /* Escapes all chars in bad, in addition to \ and all special
-         * chars, in \xFF style escaping. May be reversed with
-         * cunescape(). */
-
-        r = new(char, strlen(s) * 4 + 1);
-        if (!r)
-                return NULL;
-
-        for (f = s, t = r; *f; f++) {
-
-                if ((*f < ' ') || (*f >= 127) ||
-                    (*f == '\\') || strchr(bad, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f >> 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        *t = 0;
-
-        return r;
-}
-
-char *ascii_strlower(char *t) {
-        char *p;
-
-        assert(t);
-
-        for (p = t; *p; p++)
-                if (*p >= 'A' && *p <= 'Z')
-                        *p = *p - 'A' + 'a';
-
-        return t;
-}
-
-_pure_ static 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_file(const char *filename) {
-        assert(filename);
-
-        if (endswith(filename, "~"))
-                return true;
-
-        return hidden_file_allow_backup(filename);
-}
-
-int fd_nonblock(int fd, bool nonblock) {
-        int flags, nflags;
-
-        assert(fd >= 0);
-
-        flags = fcntl(fd, F_GETFL, 0);
-        if (flags < 0)
-                return -errno;
-
-        if (nonblock)
-                nflags = flags | O_NONBLOCK;
-        else
-                nflags = flags & ~O_NONBLOCK;
-
-        if (nflags == flags)
-                return 0;
-
-        if (fcntl(fd, F_SETFL, nflags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int fd_cloexec(int fd, bool cloexec) {
-        int flags, nflags;
-
-        assert(fd >= 0);
-
-        flags = fcntl(fd, F_GETFD, 0);
-        if (flags < 0)
-                return -errno;
-
-        if (cloexec)
-                nflags = flags | FD_CLOEXEC;
-        else
-                nflags = flags & ~FD_CLOEXEC;
-
-        if (nflags == flags)
-                return 0;
-
-        if (fcntl(fd, F_SETFD, nflags) < 0)
-                return -errno;
-
-        return 0;
-}
-
-_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
-        unsigned i;
-
-        assert(n_fdset == 0 || fdset);
-
-        for (i = 0; i < n_fdset; i++)
-                if (fdset[i] == fd)
-                        return true;
-
-        return false;
-}
-
-int close_all_fds(const int except[], unsigned n_except) {
-        _cleanup_closedir_ DIR *d = NULL;
-        struct dirent *de;
-        int r = 0;
-
-        assert(n_except == 0 || except);
-
-        d = opendir("/proc/self/fd");
-        if (!d) {
-                int fd;
-                struct rlimit rl;
-
-                /* When /proc isn't available (for example in chroots)
-                 * the fallback is brute forcing through the fd
-                 * table */
-
-                assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
-                for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
-
-                        if (fd_in_set(fd, except, n_except))
-                                continue;
-
-                        if (close_nointr(fd) < 0)
-                                if (errno != EBADF && r == 0)
-                                        r = -errno;
-                }
-
-                return r;
-        }
-
-        while ((de = readdir(d))) {
-                int fd = -1;
-
-                if (hidden_file(de->d_name))
-                        continue;
-
-                if (safe_atoi(de->d_name, &fd) < 0)
-                        /* Let's better ignore this, just in case */
-                        continue;
-
-                if (fd < 3)
-                        continue;
-
-                if (fd == dirfd(d))
-                        continue;
-
-                if (fd_in_set(fd, except, n_except))
-                        continue;
-
-                if (close_nointr(fd) < 0) {
-                        /* Valgrind has its own FD and doesn't want to have it closed */
-                        if (errno != EBADF && r == 0)
-                                r = -errno;
-                }
-        }
-
-        return r;
-}
-
-bool chars_intersect(const char *a, const char *b) {
-        const char *p;
-
-        /* Returns true if any of the chars in a are in b. */
-        for (p = a; *p; p++)
-                if (strchr(b, *p))
-                        return true;
-
-        return false;
-}
-
-bool fstype_is_network(const char *fstype) {
-        static const char table[] =
-                "afs\0"
-                "cifs\0"
-                "smbfs\0"
-                "sshfs\0"
-                "ncpfs\0"
-                "ncp\0"
-                "nfs\0"
-                "nfs4\0"
-                "gfs\0"
-                "gfs2\0"
-                "glusterfs\0";
-
-        const char *x;
-
-        x = startswith(fstype, "fuse.");
-        if (x)
-                fstype = x;
-
-        return nulstr_contains(table, fstype);
-}
-
-int flush_fd(int fd) {
-        struct pollfd pollfd = {
-                .fd = fd,
-                .events = POLLIN,
-        };
-
-        for (;;) {
-                char buf[LINE_MAX];
-                ssize_t l;
-                int r;
-
-                r = poll(&pollfd, 1, 0);
-                if (r < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-
-                } else if (r == 0)
-                        return 0;
-
-                l = read(fd, buf, sizeof(buf));
-                if (l < 0) {
-
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN)
-                                return 0;
-
-                        return -errno;
-                } else if (l == 0)
-                        return 0;
-        }
-}
-
-void safe_close_pair(int p[]) {
-        assert(p);
-
-        if (p[0] == p[1]) {
-                /* Special case pairs which use the same fd in both
-                 * directions... */
-                p[0] = p[1] = safe_close(p[0]);
-                return;
-        }
-
-        p[0] = safe_close(p[0]);
-        p[1] = safe_close(p[1]);
-}
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
-        uint8_t *p = buf;
-        ssize_t n = 0;
-
-        assert(fd >= 0);
-        assert(buf);
-
-        /* If called with nbytes == 0, let's call read() at least
-         * once, to validate the operation */
-
-        if (nbytes > (size_t) SSIZE_MAX)
-                return -EINVAL;
-
-        do {
-                ssize_t k;
-
-                k = read(fd, p, nbytes);
-                if (k < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN && do_poll) {
-
-                                /* We knowingly ignore any return value here,
-                                 * and expect that any error/EOF is reported
-                                 * via read() */
-
-                                (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
-                                continue;
-                        }
-
-                        return n > 0 ? n : -errno;
-                }
-
-                if (k == 0)
-                        return n;
-
-                assert((size_t) k <= nbytes);
-
-                p += k;
-                nbytes -= k;
-                n += k;
-        } while (nbytes > 0);
-
-        return n;
-}
-
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
-        ssize_t n;
-
-        n = loop_read(fd, buf, nbytes, do_poll);
-        if (n < 0)
-                return (int) n;
-        if ((size_t) n != nbytes)
-                return -EIO;
-
-        return 0;
-}
-
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
-        const uint8_t *p = buf;
-
-        assert(fd >= 0);
-        assert(buf);
-
-        if (nbytes > (size_t) SSIZE_MAX)
-                return -EINVAL;
-
-        do {
-                ssize_t k;
-
-                k = write(fd, p, nbytes);
-                if (k < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        if (errno == EAGAIN && do_poll) {
-                                /* We knowingly ignore any return value here,
-                                 * and expect that any error/EOF is reported
-                                 * via write() */
-
-                                (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
-                                continue;
-                        }
-
-                        return -errno;
-                }
-
-                if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
-                        return -EIO;
-
-                assert((size_t) k <= nbytes);
-
-                p += k;
-                nbytes -= k;
-        } while (nbytes > 0);
-
-        return 0;
-}
-
-int parse_size(const char *t, uint64_t base, uint64_t *size) {
-
-        /* Soo, sometimes we want to parse IEC binary suffixes, and
-         * sometimes SI decimal suffixes. This function can parse
-         * both. Which one is the right way depends on the
-         * context. Wikipedia suggests that SI is customary for
-         * hardware metrics and network speeds, while IEC is
-         * customary for most data sizes used by software and volatile
-         * (RAM) memory. Hence be careful which one you pick!
-         *
-         * In either case we use just K, M, G as suffix, and not Ki,
-         * Mi, Gi or so (as IEC would suggest). That's because that's
-         * frickin' ugly. But this means you really need to make sure
-         * to document which base you are parsing when you use this
-         * call. */
-
-        struct table {
-                const char *suffix;
-                unsigned long long factor;
-        };
-
-        static const struct table iec[] = {
-                { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
-                { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
-                { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
-                { "G", 1024ULL*1024ULL*1024ULL },
-                { "M", 1024ULL*1024ULL },
-                { "K", 1024ULL },
-                { "B", 1ULL },
-                { "",  1ULL },
-        };
-
-        static const struct table si[] = {
-                { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
-                { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
-                { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
-                { "G", 1000ULL*1000ULL*1000ULL },
-                { "M", 1000ULL*1000ULL },
-                { "K", 1000ULL },
-                { "B", 1ULL },
-                { "",  1ULL },
-        };
-
-        const struct table *table;
-        const char *p;
-        unsigned long long r = 0;
-        unsigned n_entries, start_pos = 0;
-
-        assert(t);
-        assert(base == 1000 || base == 1024);
-        assert(size);
-
-        if (base == 1000) {
-                table = si;
-                n_entries = ELEMENTSOF(si);
-        } else {
-                table = iec;
-                n_entries = ELEMENTSOF(iec);
-        }
-
-        p = t;
-        do {
-                unsigned long long l, tmp;
-                double frac = 0;
-                char *e;
-                unsigned i;
-
-                p += strspn(p, WHITESPACE);
-                if (*p == '-')
-                        return -ERANGE;
-
-                errno = 0;
-                l = strtoull(p, &e, 10);
-                if (errno > 0)
-                        return -errno;
-                if (e == p)
-                        return -EINVAL;
-
-                if (*e == '.') {
-                        e++;
-
-                        /* strtoull() itself would accept space/+/- */
-                        if (*e >= '0' && *e <= '9') {
-                                unsigned long long l2;
-                                char *e2;
-
-                                l2 = strtoull(e, &e2, 10);
-                                if (errno > 0)
-                                        return -errno;
-
-                                /* Ignore failure. E.g. 10.M is valid */
-                                frac = l2;
-                                for (; e < e2; e++)
-                                        frac /= 10;
-                        }
-                }
-
-                e += strspn(e, WHITESPACE);
-
-                for (i = start_pos; i < n_entries; i++)
-                        if (startswith(e, table[i].suffix))
-                                break;
-
-                if (i >= n_entries)
-                        return -EINVAL;
-
-                if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
-                        return -ERANGE;
-
-                tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
-                if (tmp > ULLONG_MAX - r)
-                        return -ERANGE;
-
-                r += tmp;
-                if ((unsigned long long) (uint64_t) r != r)
-                        return -ERANGE;
-
-                p = e + strlen(table[i].suffix);
-
-                start_pos = i + 1;
-
-        } while (*p);
-
-        *size = r;
-
-        return 0;
-}
-
-bool is_device_path(const char *path) {
-
-        /* Returns true on paths that refer to a device, either in
-         * sysfs or in /dev */
-
-        return
-                path_startswith(path, "/dev/") ||
-                path_startswith(path, "/sys/");
-}
-
-int dir_is_empty(const char *path) {
-        _cleanup_closedir_ DIR *d;
-
-        d = opendir(path);
-        if (!d)
-                return -errno;
-
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-
-                if (!de)
-                        return 1;
-
-                if (!hidden_file(de->d_name))
-                        return 0;
-        }
-}
-
-char* dirname_malloc(const char *path) {
-        char *d, *dir, *dir2;
-
-        d = strdup(path);
-        if (!d)
-                return NULL;
-        dir = dirname(d);
-        assert(dir);
-
-        if (dir != d) {
-                dir2 = strdup(dir);
-                free(d);
-                return dir2;
-        }
-
-        return dir;
-}
-
-void rename_process(const char name[8]) {
-        assert(name);
-
-        /* This is a like a poor man's setproctitle(). It changes the
-         * comm field, argv[0], and also the glibc's internally used
-         * name of the process. For the first one a limit of 16 chars
-         * applies, to the second one usually one of 10 (i.e. length
-         * of "/sbin/init"), to the third one one of 7 (i.e. length of
-         * "systemd"). If you pass a longer string it will be
-         * truncated */
-
-        prctl(PR_SET_NAME, name);
-
-        if (program_invocation_name)
-                strncpy(program_invocation_name, name, strlen(program_invocation_name));
-
-        if (saved_argc > 0) {
-                int i;
-
-                if (saved_argv[0])
-                        strncpy(saved_argv[0], name, strlen(saved_argv[0]));
-
-                for (i = 1; i < saved_argc; i++) {
-                        if (!saved_argv[i])
-                                break;
-
-                        memzero(saved_argv[i], strlen(saved_argv[i]));
-                }
-        }
-}
-
-char *lookup_uid(uid_t uid) {
-        long bufsize;
-        char *name;
-        _cleanup_free_ char *buf = NULL;
-        struct passwd pwbuf, *pw = NULL;
-
-        /* Shortcut things to avoid NSS lookups */
-        if (uid == 0)
-                return strdup("root");
-
-        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
-        if (bufsize <= 0)
-                bufsize = 4096;
-
-        buf = malloc(bufsize);
-        if (!buf)
-                return NULL;
-
-        if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
-                return strdup(pw->pw_name);
-
-        if (asprintf(&name, UID_FMT, uid) < 0)
-                return NULL;
-
-        return name;
-}
-
-char* getlogname_malloc(void) {
-        uid_t uid;
-        struct stat st;
-
-        if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
-                uid = st.st_uid;
-        else
-                uid = getuid();
-
-        return lookup_uid(uid);
-}
-
-char *getusername_malloc(void) {
-        const char *e;
-
-        e = getenv("USER");
-        if (e)
-                return strdup(e);
-
-        return lookup_uid(getuid());
-}
-
-bool is_temporary_fs(const struct statfs *s) {
-        assert(s);
-
-        return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
-               F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
-}
-
-int fd_is_temporary_fs(int fd) {
-        struct statfs s;
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        return is_temporary_fs(&s);
-}
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
-        assert(path);
-
-        /* Under the assumption that we are running privileged we
-         * first change the access mode and only then hand out
-         * ownership to avoid a window where access is too open. */
-
-        if (mode != MODE_INVALID)
-                if (chmod(path, mode) < 0)
-                        return -errno;
-
-        if (uid != UID_INVALID || gid != GID_INVALID)
-                if (chown(path, uid, gid) < 0)
-                        return -errno;
-
-        return 0;
-}
-
-int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
-        assert(fd >= 0);
-
-        /* Under the assumption that we are running privileged we
-         * first change the access mode and only then hand out
-         * ownership to avoid a window where access is too open. */
-
-        if (mode != MODE_INVALID)
-                if (fchmod(fd, mode) < 0)
-                        return -errno;
-
-        if (uid != UID_INVALID || gid != GID_INVALID)
-                if (fchown(fd, uid, gid) < 0)
-                        return -errno;
-
-        return 0;
-}
-
-int files_same(const char *filea, const char *fileb) {
-        struct stat a, b;
-
-        if (stat(filea, &a) < 0)
-                return -errno;
-
-        if (stat(fileb, &b) < 0)
-                return -errno;
-
-        return a.st_dev == b.st_dev &&
-               a.st_ino == b.st_ino;
-}
-
-int running_in_chroot(void) {
-        int ret;
-
-        ret = files_same("/proc/1/root", "/");
-        if (ret < 0)
-                return ret;
-
-        return ret == 0;
-}
-
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x;
-        char *r;
-
-        assert(s);
-        assert(percent <= 100);
-        assert(new_length >= 3);
-
-        if (old_length <= 3 || old_length <= new_length)
-                return strndup(s, old_length);
-
-        r = new0(char, new_length+1);
-        if (!r)
-                return NULL;
-
-        x = (new_length * percent) / 100;
-
-        if (x > new_length - 3)
-                x = new_length - 3;
-
-        memcpy(r, s, x);
-        r[x] = '.';
-        r[x+1] = '.';
-        r[x+2] = '.';
-        memcpy(r + x + 3,
-               s + old_length - (new_length - x - 3),
-               new_length - x - 3);
-
-        return r;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
-        size_t x;
-        char *e;
-        const char *i, *j;
-        unsigned k, len, len2;
-
-        assert(s);
-        assert(percent <= 100);
-        assert(new_length >= 3);
-
-        /* if no multibyte characters use ascii_ellipsize_mem for speed */
-        if (ascii_is_valid(s))
-                return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
-        if (old_length <= 3 || old_length <= new_length)
-                return strndup(s, old_length);
-
-        x = (new_length * percent) / 100;
-
-        if (x > new_length - 3)
-                x = new_length - 3;
-
-        k = 0;
-        for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
-                int c;
-
-                c = utf8_encoded_to_unichar(i);
-                if (c < 0)
-                        return NULL;
-                k += unichar_iswide(c) ? 2 : 1;
-        }
-
-        if (k > x) /* last character was wide and went over quota */
-                x ++;
-
-        for (j = s + old_length; k < new_length && j > i; ) {
-                int c;
-
-                j = utf8_prev_char(j);
-                c = utf8_encoded_to_unichar(j);
-                if (c < 0)
-                        return NULL;
-                k += unichar_iswide(c) ? 2 : 1;
-        }
-        assert(i <= j);
-
-        /* we don't actually need to ellipsize */
-        if (i == j)
-                return memdup(s, old_length + 1);
-
-        /* make space for ellipsis */
-        j = utf8_next_char(j);
-
-        len = i - s;
-        len2 = s + old_length - j;
-        e = new(char, len + 3 + len2 + 1);
-        if (!e)
-                return NULL;
-
-        /*
-        printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
-               old_length, new_length, x, len, len2, k);
-        */
-
-        memcpy(e, s, len);
-        e[len]   = 0xe2; /* tri-dot ellipsis: … */
-        e[len + 1] = 0x80;
-        e[len + 2] = 0xa6;
-
-        memcpy(e + len + 3, j, len2 + 1);
-
-        return e;
-}
-
-char *ellipsize(const char *s, size_t length, unsigned percent) {
-        return ellipsize_mem(s, strlen(s), length, percent);
-}
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
-        _cleanup_close_ int fd;
-        int r;
-
-        assert(path);
-
-        if (parents)
-                mkdir_parents(path, 0755);
-
-        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
-        if (fd < 0)
-                return -errno;
-
-        if (mode > 0) {
-                r = fchmod(fd, mode);
-                if (r < 0)
-                        return -errno;
-        }
-
-        if (uid != UID_INVALID || gid != GID_INVALID) {
-                r = fchown(fd, uid, gid);
-                if (r < 0)
-                        return -errno;
-        }
-
-        if (stamp != USEC_INFINITY) {
-                struct timespec ts[2];
-
-                timespec_store(&ts[0], stamp);
-                ts[1] = ts[0];
-                r = futimens(fd, ts);
-        } else
-                r = futimens(fd, NULL);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-int touch(const char *path) {
-        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
-}
-
-static char *unquote(const char *s, const char* quotes) {
-        size_t l;
-        assert(s);
-
-        /* This is rather stupid, simply removes the heading and
-         * trailing quotes if there is one. Doesn't care about
-         * escaping or anything.
-         *
-         * DON'T USE THIS FOR NEW CODE ANYMORE!*/
-
-        l = strlen(s);
-        if (l < 2)
-                return strdup(s);
-
-        if (strchr(quotes, s[0]) && s[l-1] == s[0])
-                return strndup(s+1, l-2);
-
-        return strdup(s);
-}
-
-noreturn void freeze(void) {
-
-        /* Make sure nobody waits for us on a socket anymore */
-        close_all_fds(NULL, 0);
-
-        sync();
-
-        for (;;)
-                pause();
-}
-
-bool null_or_empty(struct stat *st) {
-        assert(st);
-
-        if (S_ISREG(st->st_mode) && st->st_size <= 0)
-                return true;
-
-        if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
-                return true;
-
-        return false;
-}
-
-int null_or_empty_path(const char *fn) {
-        struct stat st;
-
-        assert(fn);
-
-        if (stat(fn, &st) < 0)
-                return -errno;
-
-        return null_or_empty(&st);
-}
-
-int null_or_empty_fd(int fd) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        return null_or_empty(&st);
-}
-
-DIR *xopendirat(int fd, const char *name, int flags) {
-        int nfd;
-        DIR *d;
-
-        assert(!(flags & O_CREAT));
-
-        nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
-        if (nfd < 0)
-                return NULL;
-
-        d = fdopendir(nfd);
-        if (!d) {
-                safe_close(nfd);
-                return NULL;
-        }
-
-        return d;
-}
-
-static char *tag_to_udev_node(const char *tagvalue, const char *by) {
-        _cleanup_free_ char *t = NULL, *u = NULL;
-        size_t enc_len;
-
-        u = unquote(tagvalue, QUOTES);
-        if (!u)
-                return NULL;
-
-        enc_len = strlen(u) * 4 + 1;
-        t = new(char, enc_len);
-        if (!t)
-                return NULL;
-
-        if (encode_devnode_name(u, t, enc_len) < 0)
-                return NULL;
-
-        return strjoin("/dev/disk/by-", by, "/", t, NULL);
-}
-
-char *fstab_node_to_udev_node(const char *p) {
-        assert(p);
-
-        if (startswith(p, "LABEL="))
-                return tag_to_udev_node(p+6, "label");
-
-        if (startswith(p, "UUID="))
-                return tag_to_udev_node(p+5, "uuid");
-
-        if (startswith(p, "PARTUUID="))
-                return tag_to_udev_node(p+9, "partuuid");
-
-        if (startswith(p, "PARTLABEL="))
-                return tag_to_udev_node(p+10, "partlabel");
-
-        return strdup(p);
-}
-
-bool dirent_is_file(const struct dirent *de) {
-        assert(de);
-
-        if (hidden_file(de->d_name))
-                return false;
-
-        if (de->d_type != DT_REG &&
-            de->d_type != DT_LNK &&
-            de->d_type != DT_UNKNOWN)
-                return false;
-
-        return true;
-}
-
-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)
-                return false;
-
-        if (hidden_file_allow_backup(de->d_name))
-                return false;
-
-        return endswith(de->d_name, suffix);
-}
-
-static int do_execute(char **directories, usec_t timeout, char *argv[]) {
-        _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
-        _cleanup_set_free_free_ Set *seen = NULL;
-        char **directory;
-
-        /* We fork this all off from a child process so that we can
-         * somewhat cleanly make use of SIGALRM to set a time limit */
-
-        (void) reset_all_signal_handlers();
-        (void) reset_signal_mask();
-
-        assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
-        pids = hashmap_new(NULL);
-        if (!pids)
-                return log_oom();
-
-        seen = set_new(&string_hash_ops);
-        if (!seen)
-                return log_oom();
-
-        STRV_FOREACH(directory, directories) {
-                _cleanup_closedir_ DIR *d;
-                struct dirent *de;
-
-                d = opendir(*directory);
-                if (!d) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        return log_error_errno(errno, "Failed to open directory %s: %m", *directory);
-                }
-
-                FOREACH_DIRENT(de, d, break) {
-                        _cleanup_free_ char *path = NULL;
-                        pid_t pid;
-                        int r;
-
-                        if (!dirent_is_file(de))
-                                continue;
-
-                        if (set_contains(seen, de->d_name)) {
-                                log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name);
-                                continue;
-                        }
-
-                        r = set_put_strdup(seen, de->d_name);
-                        if (r < 0)
-                                return log_oom();
-
-                        path = strjoin(*directory, "/", de->d_name, NULL);
-                        if (!path)
-                                return log_oom();
-
-                        if (null_or_empty_path(path)) {
-                                log_debug("%s is empty (a mask).", path);
-                                continue;
-                        }
-
-                        pid = fork();
-                        if (pid < 0) {
-                                log_error_errno(errno, "Failed to fork: %m");
-                                continue;
-                        } else if (pid == 0) {
-                                char *_argv[2];
-
-                                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
-                                if (!argv) {
-                                        _argv[0] = path;
-                                        _argv[1] = NULL;
-                                        argv = _argv;
-                                } else
-                                        argv[0] = path;
-
-                                execv(path, argv);
-                                return log_error_errno(errno, "Failed to execute %s: %m", path);
-                        }
-
-                        log_debug("Spawned %s as " PID_FMT ".", path, pid);
-
-                        r = hashmap_put(pids, UINT_TO_PTR(pid), path);
-                        if (r < 0)
-                                return log_oom();
-                        path = NULL;
-                }
-        }
-
-        /* Abort execution of this process after the timout. We simply
-         * rely on SIGALRM as default action terminating the process,
-         * and turn on alarm(). */
-
-        if (timeout != USEC_INFINITY)
-                alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
-
-        while (!hashmap_isempty(pids)) {
-                _cleanup_free_ char *path = NULL;
-                pid_t pid;
-
-                pid = PTR_TO_UINT(hashmap_first_key(pids));
-                assert(pid > 0);
-
-                path = hashmap_remove(pids, UINT_TO_PTR(pid));
-                assert(path);
-
-                wait_for_terminate_and_warn(path, pid, true);
-        }
-
-        return 0;
-}
-
-void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) {
-        pid_t executor_pid;
-        int r;
-        char *name;
-        char **dirs = (char**) directories;
-
-        assert(!strv_isempty(dirs));
-
-        name = basename(dirs[0]);
-        assert(!isempty(name));
-
-        /* Executes all binaries in the directories in parallel and waits
-         * for them to finish. Optionally a timeout is applied. If a file
-         * with the same name exists in more than one directory, the
-         * earliest one wins. */
-
-        executor_pid = fork();
-        if (executor_pid < 0) {
-                log_error_errno(errno, "Failed to fork: %m");
-                return;
-
-        } else if (executor_pid == 0) {
-                r = do_execute(dirs, timeout, argv);
-                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
-        }
-
-        wait_for_terminate_and_warn(name, executor_pid, true);
-}
-
-bool nulstr_contains(const char*nulstr, const char *needle) {
-        const char *i;
-
-        if (!nulstr)
-                return false;
-
-        NULSTR_FOREACH(i, nulstr)
-                if (streq(i, needle))
-                        return true;
-
-        return false;
-}
-
-bool plymouth_running(void) {
-        return access("/run/plymouth/pid", F_OK) >= 0;
-}
-
-char* strshorten(char *s, size_t l) {
-        assert(s);
-
-        if (l < strlen(s))
-                s[l] = 0;
-
-        return s;
-}
-
-int pipe_eof(int fd) {
-        struct pollfd pollfd = {
-                .fd = fd,
-                .events = POLLIN|POLLHUP,
-        };
-
-        int r;
-
-        r = poll(&pollfd, 1, 0);
-        if (r < 0)
-                return -errno;
-
-        if (r == 0)
-                return 0;
-
-        return pollfd.revents & POLLHUP;
-}
-
-int fd_wait_for_event(int fd, int event, usec_t t) {
-
-        struct pollfd pollfd = {
-                .fd = fd,
-                .events = event,
-        };
-
-        struct timespec ts;
-        int r;
-
-        r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
-        if (r < 0)
-                return -errno;
-
-        if (r == 0)
-                return 0;
-
-        return pollfd.revents;
-}
-
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
-        FILE *f;
-        char *t;
-        int r, fd;
-
-        assert(path);
-        assert(_f);
-        assert(_temp_path);
-
-        r = tempfn_xxxxxx(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
-        if (fd < 0) {
-                free(t);
-                return -errno;
-        }
-
-        f = fdopen(fd, "we");
-        if (!f) {
-                unlink_noerrno(t);
-                free(t);
-                safe_close(fd);
-                return -errno;
-        }
-
-        *_f = f;
-        *_temp_path = t;
-
-        return 0;
-}
-
-int symlink_atomic(const char *from, const char *to) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(from);
-        assert(to);
-
-        r = tempfn_random(to, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (symlink(from, t) < 0)
-                return -errno;
-
-        if (rename(t, to) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int symlink_idempotent(const char *from, const char *to) {
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        assert(from);
-        assert(to);
-
-        if (symlink(from, to) < 0) {
-                if (errno != EEXIST)
-                        return -errno;
-
-                r = readlink_malloc(to, &p);
-                if (r < 0)
-                        return r;
-
-                if (!streq(p, from))
-                        return -EINVAL;
-        }
-
-        return 0;
-}
-
-int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(path);
-
-        r = tempfn_random(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (mknod(t, mode, dev) < 0)
-                return -errno;
-
-        if (rename(t, path) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-int mkfifo_atomic(const char *path, mode_t mode) {
-        _cleanup_free_ char *t = NULL;
-        int r;
-
-        assert(path);
-
-        r = tempfn_random(path, NULL, &t);
-        if (r < 0)
-                return r;
-
-        if (mkfifo(t, mode) < 0)
-                return -errno;
-
-        if (rename(t, path) < 0) {
-                unlink_noerrno(t);
-                return -errno;
-        }
-
-        return 0;
-}
-
-bool display_is_local(const char *display) {
-        assert(display);
-
-        return
-                display[0] == ':' &&
-                display[1] >= '0' &&
-                display[1] <= '9';
-}
-
-int socket_from_display(const char *display, char **path) {
-        size_t k;
-        char *f, *c;
-
-        assert(display);
-        assert(path);
-
-        if (!display_is_local(display))
-                return -EINVAL;
-
-        k = strspn(display+1, "0123456789");
-
-        f = new(char, strlen("/tmp/.X11-unix/X") + k + 1);
-        if (!f)
-                return -ENOMEM;
-
-        c = stpcpy(f, "/tmp/.X11-unix/X");
-        memcpy(c, display+1, k);
-        c[k] = 0;
-
-        *path = f;
-
-        return 0;
-}
-
-int get_user_creds(
-                const char **username,
-                uid_t *uid, gid_t *gid,
-                const char **home,
-                const char **shell) {
-
-        struct passwd *p;
-        uid_t u;
-
-        assert(username);
-        assert(*username);
-
-        /* We enforce some special rules for uid=0: in order to avoid
-         * NSS lookups for root we hardcode its data. */
-
-        if (streq(*username, "root") || streq(*username, "0")) {
-                *username = "root";
-
-                if (uid)
-                        *uid = 0;
-
-                if (gid)
-                        *gid = 0;
-
-                if (home)
-                        *home = "/root";
-
-                if (shell)
-                        *shell = "/bin/sh";
-
-                return 0;
-        }
-
-        if (parse_uid(*username, &u) >= 0) {
-                errno = 0;
-                p = getpwuid(u);
-
-                /* If there are multiple users with the same id, make
-                 * sure to leave $USER to the configured value instead
-                 * of the first occurrence in the database. However if
-                 * the uid was configured by a numeric uid, then let's
-                 * pick the real username from /etc/passwd. */
-                if (p)
-                        *username = p->pw_name;
-        } else {
-                errno = 0;
-                p = getpwnam(*username);
-        }
-
-        if (!p)
-                return errno > 0 ? -errno : -ESRCH;
-
-        if (uid)
-                *uid = p->pw_uid;
-
-        if (gid)
-                *gid = p->pw_gid;
-
-        if (home)
-                *home = p->pw_dir;
-
-        if (shell)
-                *shell = p->pw_shell;
-
-        return 0;
-}
-
-char* uid_to_name(uid_t uid) {
-        struct passwd *p;
-        char *r;
-
-        if (uid == 0)
-                return strdup("root");
-
-        p = getpwuid(uid);
-        if (p)
-                return strdup(p->pw_name);
-
-        if (asprintf(&r, UID_FMT, uid) < 0)
-                return NULL;
-
-        return r;
-}
-
-char* gid_to_name(gid_t gid) {
-        struct group *p;
-        char *r;
-
-        if (gid == 0)
-                return strdup("root");
-
-        p = getgrgid(gid);
-        if (p)
-                return strdup(p->gr_name);
-
-        if (asprintf(&r, GID_FMT, gid) < 0)
-                return NULL;
-
-        return r;
-}
-
-int get_group_creds(const char **groupname, gid_t *gid) {
-        struct group *g;
-        gid_t id;
-
-        assert(groupname);
-
-        /* We enforce some special rules for gid=0: in order to avoid
-         * NSS lookups for root we hardcode its data. */
-
-        if (streq(*groupname, "root") || streq(*groupname, "0")) {
-                *groupname = "root";
-
-                if (gid)
-                        *gid = 0;
-
-                return 0;
-        }
-
-        if (parse_gid(*groupname, &id) >= 0) {
-                errno = 0;
-                g = getgrgid(id);
-
-                if (g)
-                        *groupname = g->gr_name;
-        } else {
-                errno = 0;
-                g = getgrnam(*groupname);
-        }
-
-        if (!g)
-                return errno > 0 ? -errno : -ESRCH;
-
-        if (gid)
-                *gid = g->gr_gid;
-
-        return 0;
-}
-
-int in_gid(gid_t gid) {
-        gid_t *gids;
-        int ngroups_max, r, i;
-
-        if (getgid() == gid)
-                return 1;
-
-        if (getegid() == gid)
-                return 1;
-
-        ngroups_max = sysconf(_SC_NGROUPS_MAX);
-        assert(ngroups_max > 0);
-
-        gids = alloca(sizeof(gid_t) * ngroups_max);
-
-        r = getgroups(ngroups_max, gids);
-        if (r < 0)
-                return -errno;
-
-        for (i = 0; i < r; i++)
-                if (gids[i] == gid)
-                        return 1;
-
-        return 0;
-}
-
-int in_group(const char *name) {
-        int r;
-        gid_t gid;
-
-        r = get_group_creds(&name, &gid);
-        if (r < 0)
-                return r;
-
-        return in_gid(gid);
-}
-
-int glob_exists(const char *path) {
-        _cleanup_globfree_ glob_t g = {};
-        int k;
-
-        assert(path);
-
-        errno = 0;
-        k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
-
-        if (k == GLOB_NOMATCH)
-                return 0;
-        else if (k == GLOB_NOSPACE)
-                return -ENOMEM;
-        else if (k == 0)
-                return !strv_isempty(g.gl_pathv);
-        else
-                return errno ? -errno : -EIO;
-}
-
-int glob_extend(char ***strv, const char *path) {
-        _cleanup_globfree_ glob_t g = {};
-        int k;
-        char **p;
-
-        errno = 0;
-        k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
-
-        if (k == GLOB_NOMATCH)
-                return -ENOENT;
-        else if (k == GLOB_NOSPACE)
-                return -ENOMEM;
-        else if (k != 0 || strv_isempty(g.gl_pathv))
-                return errno ? -errno : -EIO;
-
-        STRV_FOREACH(p, g.gl_pathv) {
-                k = strv_extend(strv, *p);
-                if (k < 0)
-                        break;
-        }
-
-        return k;
-}
-
-int dirent_ensure_type(DIR *d, struct dirent *de) {
-        struct stat st;
-
-        assert(d);
-        assert(de);
-
-        if (de->d_type != DT_UNKNOWN)
-                return 0;
-
-        if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
-                return -errno;
-
-        de->d_type =
-                S_ISREG(st.st_mode)  ? DT_REG  :
-                S_ISDIR(st.st_mode)  ? DT_DIR  :
-                S_ISLNK(st.st_mode)  ? DT_LNK  :
-                S_ISFIFO(st.st_mode) ? DT_FIFO :
-                S_ISSOCK(st.st_mode) ? DT_SOCK :
-                S_ISCHR(st.st_mode)  ? DT_CHR  :
-                S_ISBLK(st.st_mode)  ? DT_BLK  :
-                                       DT_UNKNOWN;
-
-        return 0;
-}
-
-int get_files_in_directory(const char *path, char ***list) {
-        _cleanup_closedir_ DIR *d = NULL;
-        size_t bufsize = 0, n = 0;
-        _cleanup_strv_free_ char **l = NULL;
-
-        assert(path);
-
-        /* Returns all files in a directory in *list, and the number
-         * of files as return value. If list is NULL returns only the
-         * number. */
-
-        d = opendir(path);
-        if (!d)
-                return -errno;
-
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-                if (!de)
-                        break;
-
-                dirent_ensure_type(d, de);
-
-                if (!dirent_is_file(de))
-                        continue;
-
-                if (list) {
-                        /* one extra slot is needed for the terminating NULL */
-                        if (!GREEDY_REALLOC(l, bufsize, n + 2))
-                                return -ENOMEM;
-
-                        l[n] = strdup(de->d_name);
-                        if (!l[n])
-                                return -ENOMEM;
-
-                        l[++n] = NULL;
-                } else
-                        n++;
-        }
-
-        if (list) {
-                *list = l;
-                l = NULL; /* avoid freeing */
-        }
-
-        return n;
-}
-
-char *strjoin(const char *x, ...) {
-        va_list ap;
-        size_t l;
-        char *r, *p;
-
-        va_start(ap, x);
-
-        if (x) {
-                l = strlen(x);
-
-                for (;;) {
-                        const char *t;
-                        size_t n;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        n = strlen(t);
-                        if (n > ((size_t) -1) - l) {
-                                va_end(ap);
-                                return NULL;
-                        }
-
-                        l += n;
-                }
-        } else
-                l = 0;
-
-        va_end(ap);
-
-        r = new(char, l+1);
-        if (!r)
-                return NULL;
-
-        if (x) {
-                p = stpcpy(r, x);
-
-                va_start(ap, x);
-
-                for (;;) {
-                        const char *t;
-
-                        t = va_arg(ap, const char *);
-                        if (!t)
-                                break;
-
-                        p = stpcpy(p, t);
-                }
-
-                va_end(ap);
-        } else
-                r[0] = 0;
-
-        return r;
-}
-
-bool is_main_thread(void) {
-        static thread_local int cached = 0;
-
-        if (_unlikely_(cached == 0))
-                cached = getpid() == gettid() ? 1 : -1;
-
-        return cached > 0;
-}
-
-int block_get_whole_disk(dev_t d, dev_t *ret) {
-        char *p, *s;
-        int r;
-        unsigned n, m;
-
-        assert(ret);
-
-        /* If it has a queue this is good enough for us */
-        if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
-                return -ENOMEM;
-
-        r = access(p, F_OK);
-        free(p);
-
-        if (r >= 0) {
-                *ret = d;
-                return 0;
-        }
-
-        /* If it is a partition find the originating device */
-        if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
-                return -ENOMEM;
-
-        r = access(p, F_OK);
-        free(p);
-
-        if (r < 0)
-                return -ENOENT;
-
-        /* Get parent dev_t */
-        if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
-                return -ENOMEM;
-
-        r = read_one_line_file(p, &s);
-        free(p);
-
-        if (r < 0)
-                return r;
-
-        r = sscanf(s, "%u:%u", &m, &n);
-        free(s);
-
-        if (r != 2)
-                return -EINVAL;
-
-        /* Only return this if it is really good enough for us. */
-        if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
-                return -ENOMEM;
-
-        r = access(p, F_OK);
-        free(p);
-
-        if (r >= 0) {
-                *ret = makedev(m, n);
-                return 0;
-        }
-
-        return -ENOENT;
-}
-
-static const char *const ioprio_class_table[] = {
-        [IOPRIO_CLASS_NONE] = "none",
-        [IOPRIO_CLASS_RT] = "realtime",
-        [IOPRIO_CLASS_BE] = "best-effort",
-        [IOPRIO_CLASS_IDLE] = "idle"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
-
-static const char *const sigchld_code_table[] = {
-        [CLD_EXITED] = "exited",
-        [CLD_KILLED] = "killed",
-        [CLD_DUMPED] = "dumped",
-        [CLD_TRAPPED] = "trapped",
-        [CLD_STOPPED] = "stopped",
-        [CLD_CONTINUED] = "continued",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-
-static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
-        [LOG_FAC(LOG_KERN)] = "kern",
-        [LOG_FAC(LOG_USER)] = "user",
-        [LOG_FAC(LOG_MAIL)] = "mail",
-        [LOG_FAC(LOG_DAEMON)] = "daemon",
-        [LOG_FAC(LOG_AUTH)] = "auth",
-        [LOG_FAC(LOG_SYSLOG)] = "syslog",
-        [LOG_FAC(LOG_LPR)] = "lpr",
-        [LOG_FAC(LOG_NEWS)] = "news",
-        [LOG_FAC(LOG_UUCP)] = "uucp",
-        [LOG_FAC(LOG_CRON)] = "cron",
-        [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
-        [LOG_FAC(LOG_FTP)] = "ftp",
-        [LOG_FAC(LOG_LOCAL0)] = "local0",
-        [LOG_FAC(LOG_LOCAL1)] = "local1",
-        [LOG_FAC(LOG_LOCAL2)] = "local2",
-        [LOG_FAC(LOG_LOCAL3)] = "local3",
-        [LOG_FAC(LOG_LOCAL4)] = "local4",
-        [LOG_FAC(LOG_LOCAL5)] = "local5",
-        [LOG_FAC(LOG_LOCAL6)] = "local6",
-        [LOG_FAC(LOG_LOCAL7)] = "local7"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
-
-static const char *const log_level_table[] = {
-        [LOG_EMERG] = "emerg",
-        [LOG_ALERT] = "alert",
-        [LOG_CRIT] = "crit",
-        [LOG_ERR] = "err",
-        [LOG_WARNING] = "warning",
-        [LOG_NOTICE] = "notice",
-        [LOG_INFO] = "info",
-        [LOG_DEBUG] = "debug"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
-
-static const char* const sched_policy_table[] = {
-        [SCHED_OTHER] = "other",
-        [SCHED_BATCH] = "batch",
-        [SCHED_IDLE] = "idle",
-        [SCHED_FIFO] = "fifo",
-        [SCHED_RR] = "rr"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
-
-static const char* const rlimit_table[_RLIMIT_MAX] = {
-        [RLIMIT_CPU] = "LimitCPU",
-        [RLIMIT_FSIZE] = "LimitFSIZE",
-        [RLIMIT_DATA] = "LimitDATA",
-        [RLIMIT_STACK] = "LimitSTACK",
-        [RLIMIT_CORE] = "LimitCORE",
-        [RLIMIT_RSS] = "LimitRSS",
-        [RLIMIT_NOFILE] = "LimitNOFILE",
-        [RLIMIT_AS] = "LimitAS",
-        [RLIMIT_NPROC] = "LimitNPROC",
-        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
-        [RLIMIT_LOCKS] = "LimitLOCKS",
-        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
-        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
-        [RLIMIT_NICE] = "LimitNICE",
-        [RLIMIT_RTPRIO] = "LimitRTPRIO",
-        [RLIMIT_RTTIME] = "LimitRTTIME"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
-
-static const char* const ip_tos_table[] = {
-        [IPTOS_LOWDELAY] = "low-delay",
-        [IPTOS_THROUGHPUT] = "throughput",
-        [IPTOS_RELIABILITY] = "reliability",
-        [IPTOS_LOWCOST] = "low-cost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-
-bool kexec_loaded(void) {
-       bool loaded = false;
-       char *s;
-
-       if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
-               if (s[0] == '1')
-                       loaded = true;
-               free(s);
-       }
-       return loaded;
-}
-
-int prot_from_flags(int flags) {
-
-        switch (flags & O_ACCMODE) {
-
-        case O_RDONLY:
-                return PROT_READ;
-
-        case O_WRONLY:
-                return PROT_WRITE;
-
-        case O_RDWR:
-                return PROT_READ|PROT_WRITE;
-
-        default:
-                return -EINVAL;
-        }
-}
-
-char *format_bytes(char *buf, size_t l, uint64_t t) {
-        unsigned i;
-
-        static const struct {
-                const char *suffix;
-                uint64_t factor;
-        } table[] = {
-                { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
-                { "M", UINT64_C(1024)*UINT64_C(1024) },
-                { "K", UINT64_C(1024) },
-        };
-
-        if (t == (uint64_t) -1)
-                return NULL;
-
-        for (i = 0; i < ELEMENTSOF(table); i++) {
-
-                if (t >= table[i].factor) {
-                        snprintf(buf, l,
-                                 "%" PRIu64 ".%" PRIu64 "%s",
-                                 t / table[i].factor,
-                                 ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
-                                 table[i].suffix);
-
-                        goto finish;
-                }
-        }
-
-        snprintf(buf, l, "%" PRIu64 "B", t);
-
-finish:
-        buf[l-1] = 0;
-        return buf;
-
-}
-
-void* memdup(const void *p, size_t l) {
-        void *r;
-
-        assert(p);
-
-        r = malloc(l);
-        if (!r)
-                return NULL;
-
-        memcpy(r, p, l);
-        return r;
-}
-
-int fd_inc_sndbuf(int fd, size_t n) {
-        int r, value;
-        socklen_t l = sizeof(value);
-
-        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
-                return 0;
-
-        /* If we have the privileges we will ignore the kernel limit. */
-
-        value = (int) n;
-        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
-                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
-                        return -errno;
-
-        return 1;
-}
-
-int fd_inc_rcvbuf(int fd, size_t n) {
-        int r, value;
-        socklen_t l = sizeof(value);
-
-        r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
-        if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
-                return 0;
-
-        /* If we have the privileges we will ignore the kernel limit. */
-
-        value = (int) n;
-        if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
-                if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
-                        return -errno;
-        return 1;
-}
-
-int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
-        bool stdout_is_tty, stderr_is_tty;
-        pid_t parent_pid, agent_pid;
-        sigset_t ss, saved_ss;
-        unsigned n, i;
-        va_list ap;
-        char **l;
-
-        assert(pid);
-        assert(path);
-
-        /* Spawns a temporary TTY agent, making sure it goes away when
-         * we go away */
-
-        parent_pid = getpid();
-
-        /* First we temporarily block all signals, so that the new
-         * child has them blocked initially. This way, we can be sure
-         * that SIGTERMs are not lost we might send to the agent. */
-        assert_se(sigfillset(&ss) >= 0);
-        assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
-
-        agent_pid = fork();
-        if (agent_pid < 0) {
-                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
-                return -errno;
-        }
-
-        if (agent_pid != 0) {
-                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
-                *pid = agent_pid;
-                return 0;
-        }
-
-        /* In the child:
-         *
-         * Make sure the agent goes away when the parent dies */
-        if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                _exit(EXIT_FAILURE);
-
-        /* Make sure we actually can kill the agent, if we need to, in
-         * case somebody invoked us from a shell script that trapped
-         * SIGTERM or so... */
-        (void) reset_all_signal_handlers();
-        (void) reset_signal_mask();
-
-        /* Check whether our parent died before we were able
-         * to set the death signal and unblock the signals */
-        if (getppid() != parent_pid)
-                _exit(EXIT_SUCCESS);
-
-        /* Don't leak fds to the agent */
-        close_all_fds(except, n_except);
-
-        stdout_is_tty = isatty(STDOUT_FILENO);
-        stderr_is_tty = isatty(STDERR_FILENO);
-
-        if (!stdout_is_tty || !stderr_is_tty) {
-                int fd;
-
-                /* Detach from stdout/stderr. and reopen
-                 * /dev/tty for them. This is important to
-                 * ensure that when systemctl is started via
-                 * popen() or a similar call that expects to
-                 * read EOF we actually do generate EOF and
-                 * not delay this indefinitely by because we
-                 * keep an unused copy of stdin around. */
-                fd = open("/dev/tty", O_WRONLY);
-                if (fd < 0) {
-                        log_error_errno(errno, "Failed to open /dev/tty: %m");
-                        _exit(EXIT_FAILURE);
-                }
-
-                if (!stdout_is_tty)
-                        dup2(fd, STDOUT_FILENO);
-
-                if (!stderr_is_tty)
-                        dup2(fd, STDERR_FILENO);
-
-                if (fd > 2)
-                        close(fd);
-        }
-
-        /* Count arguments */
-        va_start(ap, path);
-        for (n = 0; va_arg(ap, char*); n++)
-                ;
-        va_end(ap);
-
-        /* Allocate strv */
-        l = alloca(sizeof(char *) * (n + 1));
-
-        /* Fill in arguments */
-        va_start(ap, path);
-        for (i = 0; i <= n; i++)
-                l[i] = va_arg(ap, char*);
-        va_end(ap);
-
-        execv(path, l);
-        _exit(EXIT_FAILURE);
-}
-
-int setrlimit_closest(int resource, const struct rlimit *rlim) {
-        struct rlimit highest, fixed;
-
-        assert(rlim);
-
-        if (setrlimit(resource, rlim) >= 0)
-                return 0;
-
-        if (errno != EPERM)
-                return -errno;
-
-        /* So we failed to set the desired setrlimit, then let's try
-         * to get as close as we can */
-        assert_se(getrlimit(resource, &highest) == 0);
-
-        fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
-        fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
-
-        if (setrlimit(resource, &fixed) < 0)
-                return -errno;
-
-        return 0;
-}
-
-bool http_etag_is_valid(const char *etag) {
-        if (isempty(etag))
-                return false;
-
-        if (!endswith(etag, "\""))
-                return false;
-
-        if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
-                return false;
-
-        return true;
-}
-
-bool http_url_is_valid(const char *url) {
-        const char *p;
-
-        if (isempty(url))
-                return false;
-
-        p = startswith(url, "http://");
-        if (!p)
-                p = startswith(url, "https://");
-        if (!p)
-                return false;
-
-        if (isempty(p))
-                return false;
-
-        return ascii_is_valid(p);
-}
-
-bool documentation_url_is_valid(const char *url) {
-        const char *p;
-
-        if (isempty(url))
-                return false;
-
-        if (http_url_is_valid(url))
-                return true;
-
-        p = startswith(url, "file:/");
-        if (!p)
-                p = startswith(url, "info:");
-        if (!p)
-                p = startswith(url, "man:");
-
-        if (isempty(p))
-                return false;
-
-        return ascii_is_valid(p);
-}
-
-bool in_initrd(void) {
-        static int saved = -1;
-        struct statfs s;
-
-        if (saved >= 0)
-                return saved;
-
-        /* We make two checks here:
-         *
-         * 1. the flag file /etc/initrd-release must exist
-         * 2. the root file system must be a memory file system
-         *
-         * The second check is extra paranoia, since misdetecting an
-         * initrd can have bad bad consequences due the initrd
-         * emptying when transititioning to the main systemd.
-         */
-
-        saved = access("/etc/initrd-release", F_OK) >= 0 &&
-                statfs("/", &s) >= 0 &&
-                is_temporary_fs(&s);
-
-        return saved;
-}
-
-int get_home_dir(char **_h) {
-        struct passwd *p;
-        const char *e;
-        char *h;
-        uid_t u;
-
-        assert(_h);
-
-        /* Take the user specified one */
-        e = secure_getenv("HOME");
-        if (e && path_is_absolute(e)) {
-                h = strdup(e);
-                if (!h)
-                        return -ENOMEM;
-
-                *_h = h;
-                return 0;
-        }
-
-        /* Hardcode home directory for root to avoid NSS */
-        u = getuid();
-        if (u == 0) {
-                h = strdup("/root");
-                if (!h)
-                        return -ENOMEM;
-
-                *_h = h;
-                return 0;
-        }
-
-        /* Check the database... */
-        errno = 0;
-        p = getpwuid(u);
-        if (!p)
-                return errno > 0 ? -errno : -ESRCH;
-
-        if (!path_is_absolute(p->pw_dir))
-                return -EINVAL;
-
-        h = strdup(p->pw_dir);
-        if (!h)
-                return -ENOMEM;
-
-        *_h = h;
-        return 0;
-}
-
-int get_shell(char **_s) {
-        struct passwd *p;
-        const char *e;
-        char *s;
-        uid_t u;
-
-        assert(_s);
-
-        /* Take the user specified one */
-        e = getenv("SHELL");
-        if (e) {
-                s = strdup(e);
-                if (!s)
-                        return -ENOMEM;
-
-                *_s = s;
-                return 0;
-        }
-
-        /* Hardcode home directory for root to avoid NSS */
-        u = getuid();
-        if (u == 0) {
-                s = strdup("/bin/sh");
-                if (!s)
-                        return -ENOMEM;
-
-                *_s = s;
-                return 0;
-        }
-
-        /* Check the database... */
-        errno = 0;
-        p = getpwuid(u);
-        if (!p)
-                return errno > 0 ? -errno : -ESRCH;
-
-        if (!path_is_absolute(p->pw_shell))
-                return -EINVAL;
-
-        s = strdup(p->pw_shell);
-        if (!s)
-                return -ENOMEM;
-
-        *_s = s;
-        return 0;
-}
-
-bool filename_is_valid(const char *p) {
-
-        if (isempty(p))
-                return false;
-
-        if (strchr(p, '/'))
-                return false;
-
-        if (streq(p, "."))
-                return false;
-
-        if (streq(p, ".."))
-                return false;
-
-        if (strlen(p) > FILENAME_MAX)
-                return false;
-
-        return true;
-}
-
-bool string_is_safe(const char *p) {
-        const char *t;
-
-        if (!p)
-                return false;
-
-        for (t = p; *t; t++) {
-                if (*t > 0 && *t < ' ')
-                        return false;
-
-                if (strchr("\\\"\'\x7f", *t))
-                        return false;
-        }
-
-        return true;
-}
-
-/**
- * Check if a string contains control characters. If 'ok' is non-NULL
- * it may be a string containing additional CCs to be considered OK.
- */
-bool string_has_cc(const char *p, const char *ok) {
-        const char *t;
-
-        assert(p);
-
-        for (t = p; *t; t++) {
-                if (ok && strchr(ok, *t))
-                        continue;
-
-                if (*t > 0 && *t < ' ')
-                        return true;
-
-                if (*t == 127)
-                        return true;
-        }
-
-        return false;
-}
-
-bool path_is_safe(const char *p) {
-
-        if (isempty(p))
-                return false;
-
-        if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
-                return false;
-
-        if (strlen(p)+1 > PATH_MAX)
-                return false;
-
-        /* The following two checks are not really dangerous, but hey, they still are confusing */
-        if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
-                return false;
-
-        if (strstr(p, "//"))
-                return false;
-
-        return true;
-}
-
-/* hey glibc, APIs with callbacks without a user pointer are so useless */
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 int (*compar) (const void *, const void *, void *), void *arg) {
-        size_t l, u, idx;
-        const void *p;
-        int comparison;
-
-        l = 0;
-        u = nmemb;
-        while (l < u) {
-                idx = (l + u) / 2;
-                p = (void *)(((const char *) base) + (idx * size));
-                comparison = compar(key, p, arg);
-                if (comparison < 0)
-                        u = idx;
-                else if (comparison > 0)
-                        l = idx + 1;
-                else
-                        return (void *)p;
-        }
-        return NULL;
-}
-
-void init_gettext(void) {
-        setlocale(LC_ALL, "");
-        textdomain(GETTEXT_PACKAGE);
-}
-
-bool is_locale_utf8(void) {
-        const char *set;
-        static int cached_answer = -1;
-
-        if (cached_answer >= 0)
-                goto out;
-
-        if (!setlocale(LC_ALL, "")) {
-                cached_answer = true;
-                goto out;
-        }
-
-        set = nl_langinfo(CODESET);
-        if (!set) {
-                cached_answer = true;
-                goto out;
-        }
-
-        if (streq(set, "UTF-8")) {
-                cached_answer = true;
-                goto out;
-        }
-
-        /* For LC_CTYPE=="C" return true, because CTYPE is effectly
-         * unset and everything can do to UTF-8 nowadays. */
-        set = setlocale(LC_CTYPE, NULL);
-        if (!set) {
-                cached_answer = true;
-                goto out;
-        }
-
-        /* Check result, but ignore the result if C was set
-         * explicitly. */
-        cached_answer =
-                STR_IN_SET(set, "C", "POSIX") &&
-                !getenv("LC_ALL") &&
-                !getenv("LC_CTYPE") &&
-                !getenv("LANG");
-
-out:
-        return (bool) cached_answer;
-}
-
-const char *draw_special_char(DrawSpecialChar ch) {
-        static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
-
-                /* UTF-8 */ {
-                        [DRAW_TREE_VERTICAL]      = "\342\224\202 ",            /* │  */
-                        [DRAW_TREE_BRANCH]        = "\342\224\234\342\224\200", /* ├─ */
-                        [DRAW_TREE_RIGHT]         = "\342\224\224\342\224\200", /* └─ */
-                        [DRAW_TREE_SPACE]         = "  ",                       /*    */
-                        [DRAW_TRIANGULAR_BULLET]  = "\342\200\243",             /* ‣ */
-                        [DRAW_BLACK_CIRCLE]       = "\342\227\217",             /* ● */
-                        [DRAW_ARROW]              = "\342\206\222",             /* → */
-                        [DRAW_DASH]               = "\342\200\223",             /* – */
-                },
-
-                /* ASCII fallback */ {
-                        [DRAW_TREE_VERTICAL]      = "| ",
-                        [DRAW_TREE_BRANCH]        = "|-",
-                        [DRAW_TREE_RIGHT]         = "`-",
-                        [DRAW_TREE_SPACE]         = "  ",
-                        [DRAW_TRIANGULAR_BULLET]  = ">",
-                        [DRAW_BLACK_CIRCLE]       = "*",
-                        [DRAW_ARROW]              = "->",
-                        [DRAW_DASH]               = "-",
-                }
-        };
-
-        return draw_table[!is_locale_utf8()][ch];
-}
-
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
-        const char *f;
-        char *t, *r;
-        size_t l, old_len, new_len;
-
-        assert(text);
-        assert(old_string);
-        assert(new_string);
-
-        old_len = strlen(old_string);
-        new_len = strlen(new_string);
-
-        l = strlen(text);
-        r = new(char, l+1);
-        if (!r)
-                return NULL;
-
-        f = text;
-        t = r;
-        while (*f) {
-                char *a;
-                size_t d, nl;
-
-                if (!startswith(f, old_string)) {
-                        *(t++) = *(f++);
-                        continue;
-                }
-
-                d = t - r;
-                nl = l - old_len + new_len;
-                a = realloc(r, nl + 1);
-                if (!a)
-                        goto oom;
-
-                l = nl;
-                r = a;
-                t = r + d;
-
-                t = stpcpy(t, new_string);
-                f += old_len;
-        }
-
-        *t = 0;
-        return r;
-
-oom:
-        free(r);
-        return NULL;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
-        const char *i, *begin = NULL;
-        enum {
-                STATE_OTHER,
-                STATE_ESCAPE,
-                STATE_BRACKET
-        } state = STATE_OTHER;
-        char *obuf = NULL;
-        size_t osz = 0, isz;
-        FILE *f;
-
-        assert(ibuf);
-        assert(*ibuf);
-
-        /* Strips ANSI color and replaces TABs by 8 spaces */
-
-        isz = _isz ? *_isz : strlen(*ibuf);
-
-        f = open_memstream(&obuf, &osz);
-        if (!f)
-                return NULL;
-
-        for (i = *ibuf; i < *ibuf + isz + 1; i++) {
-
-                switch (state) {
-
-                case STATE_OTHER:
-                        if (i >= *ibuf + isz) /* EOT */
-                                break;
-                        else if (*i == '\x1B')
-                                state = STATE_ESCAPE;
-                        else if (*i == '\t')
-                                fputs("        ", f);
-                        else
-                                fputc(*i, f);
-                        break;
-
-                case STATE_ESCAPE:
-                        if (i >= *ibuf + isz) { /* EOT */
-                                fputc('\x1B', f);
-                                break;
-                        } else if (*i == '[') {
-                                state = STATE_BRACKET;
-                                begin = i + 1;
-                        } else {
-                                fputc('\x1B', f);
-                                fputc(*i, f);
-                                state = STATE_OTHER;
-                        }
-
-                        break;
-
-                case STATE_BRACKET:
-
-                        if (i >= *ibuf + isz || /* EOT */
-                            (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
-                                fputc('\x1B', f);
-                                fputc('[', f);
-                                state = STATE_OTHER;
-                                i = begin-1;
-                        } else if (*i == 'm')
-                                state = STATE_OTHER;
-                        break;
-                }
-        }
-
-        if (ferror(f)) {
-                fclose(f);
-                free(obuf);
-                return NULL;
-        }
-
-        fclose(f);
-
-        free(*ibuf);
-        *ibuf = obuf;
-
-        if (_isz)
-                *_isz = osz;
-
-        return obuf;
-}
-
-int on_ac_power(void) {
-        bool found_offline = false, found_online = false;
-        _cleanup_closedir_ DIR *d = NULL;
-
-        d = opendir("/sys/class/power_supply");
-        if (!d)
-                return errno == ENOENT ? true : -errno;
-
-        for (;;) {
-                struct dirent *de;
-                _cleanup_close_ int fd = -1, device = -1;
-                char contents[6];
-                ssize_t n;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-
-                if (!de)
-                        break;
-
-                if (hidden_file(de->d_name))
-                        continue;
-
-                device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (device < 0) {
-                        if (errno == ENOENT || errno == ENOTDIR)
-                                continue;
-
-                        return -errno;
-                }
-
-                fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        return -errno;
-                }
-
-                n = read(fd, contents, sizeof(contents));
-                if (n < 0)
-                        return -errno;
-
-                if (n != 6 || memcmp(contents, "Mains\n", 6))
-                        continue;
-
-                safe_close(fd);
-                fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
-                if (fd < 0) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        return -errno;
-                }
-
-                n = read(fd, contents, sizeof(contents));
-                if (n < 0)
-                        return -errno;
-
-                if (n != 2 || contents[1] != '\n')
-                        return -EIO;
-
-                if (contents[0] == '1') {
-                        found_online = true;
-                        break;
-                } else if (contents[0] == '0')
-                        found_offline = true;
-                else
-                        return -EIO;
-        }
-
-        return found_online || !found_offline;
-}
-
-static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
-        char **i;
-
-        assert(path);
-        assert(mode);
-        assert(_f);
-
-        if (!path_strv_resolve_uniq(search, root))
-                return -ENOMEM;
-
-        STRV_FOREACH(i, search) {
-                _cleanup_free_ char *p = NULL;
-                FILE *f;
-
-                if (root)
-                        p = strjoin(root, *i, "/", path, NULL);
-                else
-                        p = strjoin(*i, "/", path, NULL);
-                if (!p)
-                        return -ENOMEM;
-
-                f = fopen(p, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                if (errno != ENOENT)
-                        return -errno;
-        }
-
-        return -ENOENT;
-}
-
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
-        _cleanup_strv_free_ char **copy = NULL;
-
-        assert(path);
-        assert(mode);
-        assert(_f);
-
-        if (path_is_absolute(path)) {
-                FILE *f;
-
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                return -errno;
-        }
-
-        copy = strv_copy((char**) search);
-        if (!copy)
-                return -ENOMEM;
-
-        return search_and_fopen_internal(path, mode, root, copy, _f);
-}
-
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
-        _cleanup_strv_free_ char **s = NULL;
-
-        if (path_is_absolute(path)) {
-                FILE *f;
-
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
-                }
-
-                return -errno;
-        }
-
-        s = strv_split_nulstr(search);
-        if (!s)
-                return -ENOMEM;
-
-        return search_and_fopen_internal(path, mode, root, s, _f);
-}
-
-char *strextend(char **x, ...) {
-        va_list ap;
-        size_t f, l;
-        char *r, *p;
-
-        assert(x);
-
-        l = f = *x ? strlen(*x) : 0;
-
-        va_start(ap, x);
-        for (;;) {
-                const char *t;
-                size_t n;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                n = strlen(t);
-                if (n > ((size_t) -1) - l) {
-                        va_end(ap);
-                        return NULL;
-                }
-
-                l += n;
-        }
-        va_end(ap);
-
-        r = realloc(*x, l+1);
-        if (!r)
-                return NULL;
-
-        p = r + f;
-
-        va_start(ap, x);
-        for (;;) {
-                const char *t;
-
-                t = va_arg(ap, const char *);
-                if (!t)
-                        break;
-
-                p = stpcpy(p, t);
-        }
-        va_end(ap);
-
-        *p = 0;
-        *x = r;
-
-        return r + l;
-}
-
-char *strrep(const char *s, unsigned n) {
-        size_t l;
-        char *r, *p;
-        unsigned i;
-
-        assert(s);
-
-        l = strlen(s);
-        p = r = malloc(l * n + 1);
-        if (!r)
-                return NULL;
-
-        for (i = 0; i < n; i++)
-                p = stpcpy(p, s);
-
-        *p = 0;
-        return r;
-}
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
-        size_t a, newalloc;
-        void *q;
-
-        assert(p);
-        assert(allocated);
-
-        if (*allocated >= need)
-                return *p;
-
-        newalloc = MAX(need * 2, 64u / size);
-        a = newalloc * size;
-
-        /* check for overflows */
-        if (a < size * need)
-                return NULL;
-
-        q = realloc(*p, a);
-        if (!q)
-                return NULL;
-
-        *p = q;
-        *allocated = newalloc;
-        return q;
-}
-
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
-        size_t prev;
-        uint8_t *q;
-
-        assert(p);
-        assert(allocated);
-
-        prev = *allocated;
-
-        q = greedy_realloc(p, allocated, need, size);
-        if (!q)
-                return NULL;
-
-        if (*allocated > prev)
-                memzero(q + prev * size, (*allocated - prev) * size);
-
-        return q;
-}
-
-bool id128_is_valid(const char *s) {
-        size_t i, l;
-
-        l = strlen(s);
-        if (l == 32) {
-
-                /* Simple formatted 128bit hex string */
-
-                for (i = 0; i < l; i++) {
-                        char c = s[i];
-
-                        if (!(c >= '0' && c <= '9') &&
-                            !(c >= 'a' && c <= 'z') &&
-                            !(c >= 'A' && c <= 'Z'))
-                                return false;
-                }
-
-        } else if (l == 36) {
-
-                /* Formatted UUID */
-
-                for (i = 0; i < l; i++) {
-                        char c = s[i];
-
-                        if ((i == 8 || i == 13 || i == 18 || i == 23)) {
-                                if (c != '-')
-                                        return false;
-                        } else {
-                                if (!(c >= '0' && c <= '9') &&
-                                    !(c >= 'a' && c <= 'z') &&
-                                    !(c >= 'A' && c <= 'Z'))
-                                        return false;
-                        }
-                }
-
-        } else
-                return false;
-
-        return true;
-}
-
-int split_pair(const char *s, const char *sep, char **l, char **r) {
-        char *x, *a, *b;
-
-        assert(s);
-        assert(sep);
-        assert(l);
-        assert(r);
-
-        if (isempty(sep))
-                return -EINVAL;
-
-        x = strstr(s, sep);
-        if (!x)
-                return -EINVAL;
-
-        a = strndup(s, x - s);
-        if (!a)
-                return -ENOMEM;
-
-        b = strdup(x + strlen(sep));
-        if (!b) {
-                free(a);
-                return -ENOMEM;
-        }
-
-        *l = a;
-        *r = b;
-
-        return 0;
-}
-
-int shall_restore_state(void) {
-        _cleanup_free_ char *value = NULL;
-        int r;
-
-        r = get_proc_cmdline_key("systemd.restore_state=", &value);
-        if (r < 0)
-                return r;
-        if (r == 0)
-                return true;
-
-        return parse_boolean(value) != 0;
-}
-
-int proc_cmdline(char **ret) {
-        assert(ret);
-
-        if (detect_container() > 0)
-                return get_process_cmdline(1, 0, false, ret);
-        else
-                return read_one_line_file("/proc/cmdline", ret);
-}
-
-int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
-        _cleanup_free_ char *line = NULL;
-        const char *p;
-        int r;
-
-        assert(parse_item);
-
-        r = proc_cmdline(&line);
-        if (r < 0)
-                return r;
-
-        p = line;
-        for (;;) {
-                _cleanup_free_ char *word = NULL;
-                char *value = NULL;
-
-                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                /* Filter out arguments that are intended only for the
-                 * initrd */
-                if (!in_initrd() && startswith(word, "rd."))
-                        continue;
-
-                value = strchr(word, '=');
-                if (value)
-                        *(value++) = 0;
-
-                r = parse_item(word, value);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
-}
-
-int get_proc_cmdline_key(const char *key, char **value) {
-        _cleanup_free_ char *line = NULL, *ret = NULL;
-        bool found = false;
-        const char *p;
-        int r;
-
-        assert(key);
-
-        r = proc_cmdline(&line);
-        if (r < 0)
-                return r;
-
-        p = line;
-        for (;;) {
-                _cleanup_free_ char *word = NULL;
-                const char *e;
-
-                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                /* Filter out arguments that are intended only for the
-                 * initrd */
-                if (!in_initrd() && startswith(word, "rd."))
-                        continue;
-
-                if (value) {
-                        e = startswith(word, key);
-                        if (!e)
-                                continue;
-
-                        r = free_and_strdup(&ret, e);
-                        if (r < 0)
-                                return r;
-
-                        found = true;
-                } else {
-                        if (streq(word, key))
-                                found = true;
-                }
-        }
-
-        if (value) {
-                *value = ret;
-                ret = NULL;
-        }
-
-        return found;
-
-}
-
-int container_get_leader(const char *machine, pid_t *pid) {
-        _cleanup_free_ char *s = NULL, *class = NULL;
-        const char *p;
-        pid_t leader;
-        int r;
-
-        assert(machine);
-        assert(pid);
-
-        if (!machine_name_is_valid(machine))
-                return -EINVAL;
-
-        p = strjoina("/run/systemd/machines/", machine);
-        r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
-        if (r == -ENOENT)
-                return -EHOSTDOWN;
-        if (r < 0)
-                return r;
-        if (!s)
-                return -EIO;
-
-        if (!streq_ptr(class, "container"))
-                return -EIO;
-
-        r = parse_pid(s, &leader);
-        if (r < 0)
-                return r;
-        if (leader <= 1)
-                return -EIO;
-
-        *pid = leader;
-        return 0;
-}
-
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
-        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
-        int rfd = -1;
-
-        assert(pid >= 0);
-
-        if (mntns_fd) {
-                const char *mntns;
-
-                mntns = procfs_file_alloca(pid, "ns/mnt");
-                mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (mntnsfd < 0)
-                        return -errno;
-        }
-
-        if (pidns_fd) {
-                const char *pidns;
-
-                pidns = procfs_file_alloca(pid, "ns/pid");
-                pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (pidnsfd < 0)
-                        return -errno;
-        }
-
-        if (netns_fd) {
-                const char *netns;
-
-                netns = procfs_file_alloca(pid, "ns/net");
-                netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (netnsfd < 0)
-                        return -errno;
-        }
-
-        if (userns_fd) {
-                const char *userns;
-
-                userns = procfs_file_alloca(pid, "ns/user");
-                usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (usernsfd < 0 && errno != ENOENT)
-                        return -errno;
-        }
-
-        if (root_fd) {
-                const char *root;
-
-                root = procfs_file_alloca(pid, "root");
-                rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-                if (rfd < 0)
-                        return -errno;
-        }
-
-        if (pidns_fd)
-                *pidns_fd = pidnsfd;
-
-        if (mntns_fd)
-                *mntns_fd = mntnsfd;
-
-        if (netns_fd)
-                *netns_fd = netnsfd;
-
-        if (userns_fd)
-                *userns_fd = usernsfd;
-
-        if (root_fd)
-                *root_fd = rfd;
-
-        pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
-
-        return 0;
-}
-
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
-        if (userns_fd >= 0) {
-                /* Can't setns to your own userns, since then you could
-                 * escalate from non-root to root in your own namespace, so
-                 * check if namespaces equal before attempting to enter. */
-                _cleanup_free_ char *userns_fd_path = NULL;
-                int r;
-                if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
-                        return -ENOMEM;
-
-                r = files_same(userns_fd_path, "/proc/self/ns/user");
-                if (r < 0)
-                        return r;
-                if (r)
-                        userns_fd = -1;
-        }
-
-        if (pidns_fd >= 0)
-                if (setns(pidns_fd, CLONE_NEWPID) < 0)
-                        return -errno;
-
-        if (mntns_fd >= 0)
-                if (setns(mntns_fd, CLONE_NEWNS) < 0)
-                        return -errno;
-
-        if (netns_fd >= 0)
-                if (setns(netns_fd, CLONE_NEWNET) < 0)
-                        return -errno;
-
-        if (userns_fd >= 0)
-                if (setns(userns_fd, CLONE_NEWUSER) < 0)
-                        return -errno;
-
-        if (root_fd >= 0) {
-                if (fchdir(root_fd) < 0)
-                        return -errno;
-
-                if (chroot(".") < 0)
-                        return -errno;
-        }
-
-        return reset_uid_gid();
-}
-
-int getpeercred(int fd, struct ucred *ucred) {
-        socklen_t n = sizeof(struct ucred);
-        struct ucred u;
-        int r;
-
-        assert(fd >= 0);
-        assert(ucred);
-
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
-        if (r < 0)
-                return -errno;
-
-        if (n != sizeof(struct ucred))
-                return -EIO;
-
-        /* Check if the data is actually useful and not suppressed due
-         * to namespacing issues */
-        if (u.pid <= 0)
-                return -ENODATA;
-        if (u.uid == UID_INVALID)
-                return -ENODATA;
-        if (u.gid == GID_INVALID)
-                return -ENODATA;
-
-        *ucred = u;
-        return 0;
-}
-
-int getpeersec(int fd, char **ret) {
-        socklen_t n = 64;
-        char *s;
-        int r;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        s = new0(char, n);
-        if (!s)
-                return -ENOMEM;
-
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-        if (r < 0) {
-                free(s);
-
-                if (errno != ERANGE)
-                        return -errno;
-
-                s = new0(char, n);
-                if (!s)
-                        return -ENOMEM;
-
-                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-                if (r < 0) {
-                        free(s);
-                        return -errno;
-                }
-        }
-
-        if (isempty(s)) {
-                free(s);
-                return -EOPNOTSUPP;
-        }
-
-        *ret = s;
-        return 0;
-}
-
-/* This is much like like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern, int flags) {
-        _cleanup_umask_ mode_t u;
-        int fd;
-
-        assert(pattern);
-
-        u = umask(077);
-
-        fd = mkostemp(pattern, flags);
-        if (fd < 0)
-                return -errno;
-
-        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 fd_warn_permissions(const char *path, int fd) {
-        struct stat st;
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        if (st.st_mode & 0111)
-                log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
-
-        if (st.st_mode & 0002)
-                log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
-
-        if (getpid() == 1 && (st.st_mode & 0044) != 0044)
-                log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
-
-        return 0;
-}
-
-unsigned long personality_from_string(const char *p) {
-
-        /* Parse a personality specifier. We introduce our own
-         * identifiers that indicate specific ABIs, rather than just
-         * hints regarding the register size, since we want to keep
-         * things open for multiple locally supported ABIs for the
-         * same register size. We try to reuse the ABI identifiers
-         * used by libseccomp. */
-
-#if defined(__x86_64__)
-
-        if (streq(p, "x86"))
-                return PER_LINUX32;
-
-        if (streq(p, "x86-64"))
-                return PER_LINUX;
-
-#elif defined(__i386__)
-
-        if (streq(p, "x86"))
-                return PER_LINUX;
-
-#elif defined(__s390x__)
-
-        if (streq(p, "s390"))
-                return PER_LINUX32;
-
-        if (streq(p, "s390x"))
-                return PER_LINUX;
-
-#elif defined(__s390__)
-
-        if (streq(p, "s390"))
-                return PER_LINUX;
-#endif
-
-        return PERSONALITY_INVALID;
-}
-
-const char* personality_to_string(unsigned long p) {
-
-#if defined(__x86_64__)
-
-        if (p == PER_LINUX32)
-                return "x86";
-
-        if (p == PER_LINUX)
-                return "x86-64";
-
-#elif defined(__i386__)
-
-        if (p == PER_LINUX)
-                return "x86";
-
-#elif defined(__s390x__)
-
-        if (p == PER_LINUX)
-                return "s390x";
-
-        if (p == PER_LINUX32)
-                return "s390";
-
-#elif defined(__s390__)
-
-        if (p == PER_LINUX)
-                return "s390";
-
-#endif
-
-        return NULL;
-}
-
-uint64_t physical_memory(void) {
-        long mem;
-
-        /* We return this as uint64_t in case we are running as 32bit
-         * process on a 64bit kernel with huge amounts of memory */
-
-        mem = sysconf(_SC_PHYS_PAGES);
-        assert(mem > 0);
-
-        return (uint64_t) mem * (uint64_t) page_size();
-}
-
-void hexdump(FILE *f, const void *p, size_t s) {
-        const uint8_t *b = p;
-        unsigned n = 0;
-
-        assert(s == 0 || b);
-
-        while (s > 0) {
-                size_t i;
-
-                fprintf(f, "%04x  ", n);
-
-                for (i = 0; i < 16; i++) {
-
-                        if (i >= s)
-                                fputs("   ", f);
-                        else
-                                fprintf(f, "%02x ", b[i]);
-
-                        if (i == 7)
-                                fputc(' ', f);
-                }
-
-                fputc(' ', f);
-
-                for (i = 0; i < 16; i++) {
-
-                        if (i >= s)
-                                fputc(' ', f);
-                        else
-                                fputc(isprint(b[i]) ? (char) b[i] : '.', f);
-                }
-
-                fputc('\n', f);
-
-                if (s < 16)
-                        break;
-
-                n += 16;
-                b += 16;
-                s -= 16;
-        }
-}
-
-int update_reboot_param_file(const char *param) {
-        int r = 0;
-
-        if (param) {
-                r = write_string_file(REBOOT_PARAM_FILE, 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 0;
-}
-
-int umount_recursive(const char *prefix, int flags) {
-        bool again;
-        int n = 0, r;
-
-        /* Try to umount everything recursively below a
-         * directory. Also, take care of stacked mounts, and keep
-         * unmounting them until they are gone. */
-
-        do {
-                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-
-                again = false;
-                r = 0;
-
-                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
-                if (!proc_self_mountinfo)
-                        return -errno;
-
-                for (;;) {
-                        _cleanup_free_ char *path = NULL, *p = NULL;
-                        int k;
-
-                        k = fscanf(proc_self_mountinfo,
-                                   "%*s "       /* (1) mount id */
-                                   "%*s "       /* (2) parent id */
-                                   "%*s "       /* (3) major:minor */
-                                   "%*s "       /* (4) root */
-                                   "%ms "       /* (5) mount point */
-                                   "%*s"        /* (6) mount options */
-                                   "%*[^-]"     /* (7) optional fields */
-                                   "- "         /* (8) separator */
-                                   "%*s "       /* (9) file system type */
-                                   "%*s"        /* (10) mount source */
-                                   "%*s"        /* (11) mount options 2 */
-                                   "%*[^\n]",   /* some rubbish at the end */
-                                   &path);
-                        if (k != 1) {
-                                if (k == EOF)
-                                        break;
-
-                                continue;
-                        }
-
-                        r = cunescape(path, UNESCAPE_RELAX, &p);
-                        if (r < 0)
-                                return r;
-
-                        if (!path_startswith(p, prefix))
-                                continue;
-
-                        if (umount2(p, flags) < 0) {
-                                r = -errno;
-                                continue;
-                        }
-
-                        again = true;
-                        n++;
-
-                        break;
-                }
-
-        } while (again);
-
-        return r ? r : n;
-}
-
-static int get_mount_flags(const char *path, unsigned long *flags) {
-        struct statvfs buf;
-
-        if (statvfs(path, &buf) < 0)
-                return -errno;
-        *flags = buf.f_flag;
-        return 0;
-}
-
-int bind_remount_recursive(const char *prefix, bool ro) {
-        _cleanup_set_free_free_ Set *done = NULL;
-        _cleanup_free_ char *cleaned = NULL;
-        int r;
-
-        /* Recursively remount a directory (and all its submounts)
-         * read-only or read-write. If the directory is already
-         * mounted, we reuse the mount and simply mark it
-         * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
-         * operation). If it isn't we first make it one. Afterwards we
-         * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
-         * submounts we can access, too. When mounts are stacked on
-         * the same mount point we only care for each individual
-         * "top-level" mount on each point, as we cannot
-         * influence/access the underlying mounts anyway. We do not
-         * have any effect on future submounts that might get
-         * propagated, they migt be writable. This includes future
-         * submounts that have been triggered via autofs. */
-
-        cleaned = strdup(prefix);
-        if (!cleaned)
-                return -ENOMEM;
-
-        path_kill_slashes(cleaned);
-
-        done = set_new(&string_hash_ops);
-        if (!done)
-                return -ENOMEM;
-
-        for (;;) {
-                _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-                _cleanup_set_free_free_ Set *todo = NULL;
-                bool top_autofs = false;
-                char *x;
-                unsigned long orig_flags;
-
-                todo = set_new(&string_hash_ops);
-                if (!todo)
-                        return -ENOMEM;
-
-                proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
-                if (!proc_self_mountinfo)
-                        return -errno;
-
-                for (;;) {
-                        _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
-                        int k;
-
-                        k = fscanf(proc_self_mountinfo,
-                                   "%*s "       /* (1) mount id */
-                                   "%*s "       /* (2) parent id */
-                                   "%*s "       /* (3) major:minor */
-                                   "%*s "       /* (4) root */
-                                   "%ms "       /* (5) mount point */
-                                   "%*s"        /* (6) mount options (superblock) */
-                                   "%*[^-]"     /* (7) optional fields */
-                                   "- "         /* (8) separator */
-                                   "%ms "       /* (9) file system type */
-                                   "%*s"        /* (10) mount source */
-                                   "%*s"        /* (11) mount options (bind mount) */
-                                   "%*[^\n]",   /* some rubbish at the end */
-                                   &path,
-                                   &type);
-                        if (k != 2) {
-                                if (k == EOF)
-                                        break;
-
-                                continue;
-                        }
-
-                        r = cunescape(path, UNESCAPE_RELAX, &p);
-                        if (r < 0)
-                                return r;
-
-                        /* Let's ignore autofs mounts.  If they aren't
-                         * triggered yet, we want to avoid triggering
-                         * them, as we don't make any guarantees for
-                         * future submounts anyway.  If they are
-                         * already triggered, then we will find
-                         * another entry for this. */
-                        if (streq(type, "autofs")) {
-                                top_autofs = top_autofs || path_equal(cleaned, p);
-                                continue;
-                        }
-
-                        if (path_startswith(p, cleaned) &&
-                            !set_contains(done, p)) {
-
-                                r = set_consume(todo, p);
-                                p = NULL;
-
-                                if (r == -EEXIST)
-                                        continue;
-                                if (r < 0)
-                                        return r;
-                        }
-                }
-
-                /* If we have no submounts to process anymore and if
-                 * the root is either already done, or an autofs, we
-                 * are done */
-                if (set_isempty(todo) &&
-                    (top_autofs || set_contains(done, cleaned)))
-                        return 0;
-
-                if (!set_contains(done, cleaned) &&
-                    !set_contains(todo, cleaned)) {
-                        /* The prefix directory itself is not yet a
-                         * mount, make it one. */
-                        if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
-                                return -errno;
-
-                        orig_flags = 0;
-                        (void) get_mount_flags(cleaned, &orig_flags);
-                        orig_flags &= ~MS_RDONLY;
-
-                        if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
-                                return -errno;
-
-                        x = strdup(cleaned);
-                        if (!x)
-                                return -ENOMEM;
-
-                        r = set_consume(done, x);
-                        if (r < 0)
-                                return r;
-                }
-
-                while ((x = set_steal_first(todo))) {
-
-                        r = set_consume(done, x);
-                        if (r == -EEXIST || r == 0)
-                                continue;
-                        if (r < 0)
-                                return r;
-
-                        /* Try to reuse the original flag set, but
-                         * don't care for errors, in case of
-                         * obstructed mounts */
-                        orig_flags = 0;
-                        (void) get_mount_flags(x, &orig_flags);
-                        orig_flags &= ~MS_RDONLY;
-
-                        if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
-
-                                /* Deal with mount points that are
-                                 * obstructed by a later mount */
-
-                                if (errno != ENOENT)
-                                        return -errno;
-                        }
-
-                }
-        }
-}
-
-int fflush_and_check(FILE *f) {
-        assert(f);
-
-        errno = 0;
-        fflush(f);
-
-        if (ferror(f))
-                return errno ? -errno : -EIO;
-
-        return 0;
-}
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t;
-
-        assert(p);
-        assert(ret);
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldoXXXXXX
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        if (extra == NULL)
-                extra = "";
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
-
-        *ret = path_kill_slashes(t);
-        return 0;
-}
-
-int tempfn_random(const char *p, const char *extra, char **ret) {
-        const char *fn;
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-
-        assert(p);
-        assert(ret);
-
-        /*
-         * Turns this:
-         *         /foo/bar/waldo
-         *
-         * Into this:
-         *         /foo/bar/.#<extra>waldobaa2a261115984a9
-         */
-
-        fn = basename(p);
-        if (!filename_is_valid(fn))
-                return -EINVAL;
-
-        if (!extra)
-                extra = "";
-
-        t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_kill_slashes(t);
-        return 0;
-}
-
-int tempfn_random_child(const char *p, const char *extra, char **ret) {
-        char *t, *x;
-        uint64_t u;
-        unsigned i;
-
-        assert(p);
-        assert(ret);
-
-        /* Turns this:
-         *         /foo/bar/waldo
-         * Into this:
-         *         /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
-         */
-
-        if (!extra)
-                extra = "";
-
-        t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
-        if (!t)
-                return -ENOMEM;
-
-        x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
-        u = random_u64();
-        for (i = 0; i < 16; i++) {
-                *(x++) = hexchar(u & 0xF);
-                u >>= 4;
-        }
-
-        *x = 0;
-
-        *ret = path_kill_slashes(t);
-        return 0;
-}
-
-int take_password_lock(const char *root) {
-
-        struct flock flock = {
-                .l_type = F_WRLCK,
-                .l_whence = SEEK_SET,
-                .l_start = 0,
-                .l_len = 0,
-        };
-
-        const char *path;
-        int fd, r;
-
-        /* This is roughly the same as lckpwdf(), but not as awful. We
-         * don't want to use alarm() and signals, hence we implement
-         * our own trivial version of this.
-         *
-         * Note that shadow-utils also takes per-database locks in
-         * addition to lckpwdf(). However, we don't given that they
-         * are redundant as they they invoke lckpwdf() first and keep
-         * it during everything they do. The per-database locks are
-         * awfully racy, and thus we just won't do them. */
-
-        if (root)
-                path = strjoina(root, "/etc/.pwd.lock");
-        else
-                path = "/etc/.pwd.lock";
-
-        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
-        if (fd < 0)
-                return -errno;
-
-        r = fcntl(fd, F_SETLKW, &flock);
-        if (r < 0) {
-                safe_close(fd);
-                return -errno;
-        }
-
-        return fd;
-}
-
-int is_symlink(const char *path) {
-        struct stat info;
-
-        if (lstat(path, &info) < 0)
-                return -errno;
-
-        return !!S_ISLNK(info.st_mode);
-}
-
-int is_dir(const char* path, bool follow) {
-        struct stat st;
-        int r;
-
-        if (follow)
-                r = stat(path, &st);
-        else
-                r = lstat(path, &st);
-        if (r < 0)
-                return -errno;
-
-        return !!S_ISDIR(st.st_mode);
-}
-
-int is_device_node(const char *path) {
-        struct stat info;
-
-        if (lstat(path, &info) < 0)
-                return -errno;
-
-        return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
-}
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
-        _cleanup_free_ char *s = NULL;
-        size_t allocated = 0, sz = 0;
-        int r;
-
-        enum {
-                START,
-                VALUE,
-                VALUE_ESCAPE,
-                SINGLE_QUOTE,
-                SINGLE_QUOTE_ESCAPE,
-                DOUBLE_QUOTE,
-                DOUBLE_QUOTE_ESCAPE,
-                SEPARATOR,
-        } state = START;
-
-        assert(p);
-        assert(ret);
-
-        if (!separators)
-                separators = WHITESPACE;
-
-        /* Bail early if called after last value or with no input */
-        if (!*p)
-                goto finish_force_terminate;
-
-        /* Parses the first word of a string, and returns it in
-         * *ret. Removes all quotes in the process. When parsing fails
-         * (because of an uneven number of quotes or similar), leaves
-         * the pointer *p at the first invalid character. */
-
-        for (;;) {
-                char c = **p;
-
-                switch (state) {
-
-                case START:
-                        if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
-                                if (!GREEDY_REALLOC(s, allocated, sz+1))
-                                        return -ENOMEM;
-
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        else if (strchr(separators, c)) {
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                        (*p) ++;
-                                        goto finish_force_next;
-                                }
-                                break;
-                        }
-
-                        /* We found a non-blank character, so we will always
-                         * want to return a string (even if it is empty),
-                         * allocate it here. */
-                        if (!GREEDY_REALLOC(s, allocated, sz+1))
-                                return -ENOMEM;
-
-                        state = VALUE;
-                        /* fallthrough */
-
-                case VALUE:
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        else if (c == '\'' && (flags & EXTRACT_QUOTES))
-                                state = SINGLE_QUOTE;
-                        else if (c == '\\')
-                                state = VALUE_ESCAPE;
-                        else if (c == '\"' && (flags & EXTRACT_QUOTES))
-                                state = DOUBLE_QUOTE;
-                        else if (strchr(separators, c)) {
-                                if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
-                                        (*p) ++;
-                                        goto finish_force_next;
-                                }
-                                state = SEPARATOR;
-                        } else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case SINGLE_QUOTE:
-                        if (c == 0) {
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        } else if (c == '\'')
-                                state = VALUE;
-                        else if (c == '\\')
-                                state = SINGLE_QUOTE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case DOUBLE_QUOTE:
-                        if (c == 0)
-                                return -EINVAL;
-                        else if (c == '\"')
-                                state = VALUE;
-                        else if (c == '\\')
-                                state = DOUBLE_QUOTE_ESCAPE;
-                        else {
-                                if (!GREEDY_REALLOC(s, allocated, sz+2))
-                                        return -ENOMEM;
-
-                                s[sz++] = c;
-                        }
-
-                        break;
-
-                case SINGLE_QUOTE_ESCAPE:
-                case DOUBLE_QUOTE_ESCAPE:
-                case VALUE_ESCAPE:
-                        if (!GREEDY_REALLOC(s, allocated, sz+7))
-                                return -ENOMEM;
-
-                        if (c == 0) {
-                                if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
-                                    (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
-                                        /* If we find an unquoted trailing backslash and we're in
-                                         * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
-                                         * output.
-                                         *
-                                         * Unbalanced quotes will only be allowed in EXTRACT_RELAX
-                                         * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
-                                         */
-                                        s[sz++] = '\\';
-                                        goto finish_force_terminate;
-                                }
-                                if (flags & EXTRACT_RELAX)
-                                        goto finish_force_terminate;
-                                return -EINVAL;
-                        }
-
-                        if (flags & EXTRACT_CUNESCAPE) {
-                                uint32_t u;
-
-                                r = cunescape_one(*p, (size_t) -1, &c, &u);
-                                if (r < 0) {
-                                        if (flags & EXTRACT_CUNESCAPE_RELAX) {
-                                                s[sz++] = '\\';
-                                                s[sz++] = c;
-                                                goto end_escape;
-                                        }
-                                        return -EINVAL;
-                                }
-
-                                (*p) += r - 1;
-
-                                if (c != 0)
-                                        s[sz++] = c; /* normal explicit char */
-                                else
-                                        sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
-                        } else
-                                s[sz++] = c;
-
-end_escape:
-                        state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
-                                (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
-                                VALUE;
-                        break;
-
-                case SEPARATOR:
-                        if (c == 0)
-                                goto finish_force_terminate;
-                        if (!strchr(separators, c))
-                                goto finish;
-                        break;
-                }
-
-                (*p) ++;
-        }
-
-finish_force_terminate:
-        *p = NULL;
-finish:
-        if (!s) {
-                *p = NULL;
-                *ret = NULL;
-                return 0;
-        }
-
-finish_force_next:
-        s[sz] = 0;
-        *ret = s;
-        s = NULL;
-
-        return 1;
-}
-
-int extract_first_word_and_warn(
-                const char **p,
-                char **ret,
-                const char *separators,
-                ExtractFlags flags,
-                const char *unit,
-                const char *filename,
-                unsigned line,
-                const char *rvalue) {
-
-        /* Try to unquote it, if it fails, warn about it and try again but this
-         * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
-         * in invalid escape sequences. */
-        const char *save;
-        int r;
-
-        save = *p;
-        r = extract_first_word(p, ret, separators, flags);
-        if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
-
-                /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
-                *p = save;
-                r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
-                else
-                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
-        }
-
-        return r;
-}
-
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
-        va_list ap;
-        char **l;
-        int n = 0, i, c, r;
-
-        /* Parses a number of words from a string, stripping any
-         * quotes if necessary. */
-
-        assert(p);
-
-        /* Count how many words are expected */
-        va_start(ap, flags);
-        for (;;) {
-                if (!va_arg(ap, char **))
-                        break;
-                n++;
-        }
-        va_end(ap);
-
-        if (n <= 0)
-                return 0;
-
-        /* Read all words into a temporary array */
-        l = newa0(char*, n);
-        for (c = 0; c < n; c++) {
-
-                r = extract_first_word(p, &l[c], separators, flags);
-                if (r < 0) {
-                        int j;
-
-                        for (j = 0; j < c; j++)
-                                free(l[j]);
-
-                        return r;
-                }
-
-                if (r == 0)
-                        break;
-        }
-
-        /* If we managed to parse all words, return them in the passed
-         * in parameters */
-        va_start(ap, flags);
-        for (i = 0; i < n; i++) {
-                char **v;
-
-                v = va_arg(ap, char **);
-                assert(v);
-
-                *v = l[i];
-        }
-        va_end(ap);
-
-        return c;
-}
-
-int free_and_strdup(char **p, const char *s) {
-        char *t;
-
-        assert(p);
-
-        /* Replaces a string pointer with an strdup()ed new string,
-         * possibly freeing the old one. */
-
-        if (streq_ptr(*p, s))
-                return 0;
-
-        if (s) {
-                t = strdup(s);
-                if (!t)
-                        return -ENOMEM;
-        } else
-                t = NULL;
-
-        free(*p);
-        *p = t;
-
-        return 1;
-}
-
-ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
-        char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
-        _cleanup_close_ int fd = -1;
-        ssize_t l;
-
-        /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
-
-        fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
-        if (fd < 0)
-                return -errno;
-
-        xsprintf(fn, "/proc/self/fd/%i", fd);
-
-        l = getxattr(fn, attribute, value, size);
-        if (l < 0)
-                return -errno;
-
-        return l;
-}
-
-static int parse_crtime(le64_t le, usec_t *usec) {
-        uint64_t u;
-
-        assert(usec);
-
-        u = le64toh(le);
-        if (u == 0 || u == (uint64_t) -1)
-                return -EIO;
-
-        *usec = (usec_t) u;
-        return 0;
-}
-
-int fd_getcrtime(int fd, usec_t *usec) {
-        le64_t le;
-        ssize_t n;
-
-        assert(fd >= 0);
-        assert(usec);
-
-        /* Until Linux gets a real concept of birthtime/creation time,
-         * let's fake one with xattrs */
-
-        n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
-        if (n < 0)
-                return -errno;
-        if (n != sizeof(le))
-                return -EIO;
-
-        return parse_crtime(le, usec);
-}
-
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
-        le64_t le;
-        ssize_t n;
-
-        n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
-        if (n < 0)
-                return -errno;
-        if (n != sizeof(le))
-                return -EIO;
-
-        return parse_crtime(le, usec);
-}
-
-int path_getcrtime(const char *p, usec_t *usec) {
-        le64_t le;
-        ssize_t n;
-
-        assert(p);
-        assert(usec);
-
-        n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
-        if (n < 0)
-                return -errno;
-        if (n != sizeof(le))
-                return -EIO;
-
-        return parse_crtime(le, usec);
-}
-
-int fd_setcrtime(int fd, usec_t usec) {
-        le64_t le;
-
-        assert(fd >= 0);
-
-        if (usec <= 0)
-                usec = now(CLOCK_REALTIME);
-
-        le = htole64((uint64_t) usec);
-        if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int same_fd(int a, int b) {
-        struct stat sta, stb;
-        pid_t pid;
-        int r, fa, fb;
-
-        assert(a >= 0);
-        assert(b >= 0);
-
-        /* Compares two file descriptors. Note that semantics are
-         * quite different depending on whether we have kcmp() or we
-         * don't. If we have kcmp() this will only return true for
-         * dup()ed file descriptors, but not otherwise. If we don't
-         * have kcmp() this will also return true for two fds of the same
-         * file, created by separate open() calls. Since we use this
-         * call mostly for filtering out duplicates in the fd store
-         * this difference hopefully doesn't matter too much. */
-
-        if (a == b)
-                return true;
-
-        /* Try to use kcmp() if we have it. */
-        pid = getpid();
-        r = kcmp(pid, pid, KCMP_FILE, a, b);
-        if (r == 0)
-                return true;
-        if (r > 0)
-                return false;
-        if (errno != ENOSYS)
-                return -errno;
-
-        /* We don't have kcmp(), use fstat() instead. */
-        if (fstat(a, &sta) < 0)
-                return -errno;
-
-        if (fstat(b, &stb) < 0)
-                return -errno;
-
-        if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
-                return false;
-
-        /* We consider all device fds different, since two device fds
-         * might refer to quite different device contexts even though
-         * they share the same inode and backing dev_t. */
-
-        if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
-                return false;
-
-        if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
-                return false;
-
-        /* The fds refer to the same inode on disk, let's also check
-         * if they have the same fd flags. This is useful to
-         * distinguish the read and write side of a pipe created with
-         * pipe(). */
-        fa = fcntl(a, F_GETFL);
-        if (fa < 0)
-                return -errno;
-
-        fb = fcntl(b, F_GETFL);
-        if (fb < 0)
-                return -errno;
-
-        return fa == fb;
-}
-
-int chattr_fd(int fd, unsigned value, unsigned mask) {
-        unsigned old_attr, new_attr;
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        /* Explicitly check whether this is a regular file or
-         * directory. If it is anything else (such as a device node or
-         * fifo), then the ioctl will not hit the file systems but
-         * possibly drivers, where the ioctl might have different
-         * effects. Notably, DRM is using the same ioctl() number. */
-
-        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
-                return -ENOTTY;
-
-        if (mask == 0)
-                return 0;
-
-        if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
-                return -errno;
-
-        new_attr = (old_attr & ~mask) | (value & mask);
-        if (new_attr == old_attr)
-                return 0;
-
-        if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
-                return -errno;
-
-        return 1;
-}
-
-int chattr_path(const char *p, unsigned value, unsigned mask) {
-        _cleanup_close_ int fd = -1;
-
-        assert(p);
-
-        if (mask == 0)
-                return 0;
-
-        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
-        if (fd < 0)
-                return -errno;
-
-        return chattr_fd(fd, value, mask);
-}
-
-int read_attr_fd(int fd, unsigned *ret) {
-        struct stat st;
-
-        assert(fd >= 0);
-
-        if (fstat(fd, &st) < 0)
-                return -errno;
-
-        if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
-                return -ENOTTY;
-
-        if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
-                return -errno;
-
-        return 0;
-}
-
-int read_attr_path(const char *p, unsigned *ret) {
-        _cleanup_close_ int fd = -1;
-
-        assert(p);
-        assert(ret);
-
-        fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
-        if (fd < 0)
-                return -errno;
-
-        return read_attr_fd(fd, ret);
-}
-
-static size_t nul_length(const uint8_t *p, size_t sz) {
-        size_t n = 0;
-
-        while (sz > 0) {
-                if (*p != 0)
-                        break;
-
-                n++;
-                p++;
-                sz--;
-        }
-
-        return n;
-}
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
-        const uint8_t *q, *w, *e;
-        ssize_t l;
-
-        q = w = p;
-        e = q + sz;
-        while (q < e) {
-                size_t n;
-
-                n = nul_length(q, e - q);
-
-                /* If there are more than the specified run length of
-                 * NUL bytes, or if this is the beginning or the end
-                 * of the buffer, then seek instead of write */
-                if ((n > run_length) ||
-                    (n > 0 && q == p) ||
-                    (n > 0 && q + n >= e)) {
-                        if (q > w) {
-                                l = write(fd, w, q - w);
-                                if (l < 0)
-                                        return -errno;
-                                if (l != q -w)
-                                        return -EIO;
-                        }
-
-                        if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
-                                return -errno;
-
-                        q += n;
-                        w = q;
-                } else if (n > 0)
-                        q += n;
-                else
-                        q ++;
-        }
-
-        if (q > w) {
-                l = write(fd, w, q - w);
-                if (l < 0)
-                        return -errno;
-                if (l != q - w)
-                        return -EIO;
-        }
-
-        return q - (const uint8_t*) p;
-}
-
-void sigkill_wait(pid_t *pid) {
-        if (!pid)
-                return;
-        if (*pid <= 1)
-                return;
-
-        if (kill(*pid, SIGKILL) > 0)
-                (void) wait_for_terminate(*pid, NULL);
-}
-
-int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
-        int a = 0, b = 0, c = 0;
-        int k;
-
-        assert(p);
-        assert(*p);
-        assert(priority);
-
-        if ((*p)[0] != '<')
-                return 0;
-
-        if (!strchr(*p, '>'))
-                return 0;
-
-        if ((*p)[2] == '>') {
-                c = undecchar((*p)[1]);
-                k = 3;
-        } else if ((*p)[3] == '>') {
-                b = undecchar((*p)[1]);
-                c = undecchar((*p)[2]);
-                k = 4;
-        } else if ((*p)[4] == '>') {
-                a = undecchar((*p)[1]);
-                b = undecchar((*p)[2]);
-                c = undecchar((*p)[3]);
-                k = 5;
-        } else
-                return 0;
-
-        if (a < 0 || b < 0 || c < 0 ||
-            (!with_facility && (a || b || c > 7)))
-                return 0;
-
-        if (with_facility)
-                *priority = a*100 + b*10 + c;
-        else
-                *priority = (*priority & LOG_FACMASK) | c;
-
-        *p += k;
-        return 1;
-}
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
-        size_t i;
+                device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (device < 0) {
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                continue;
 
-        if (!key)
-                return -1;
+                        return -errno;
+                }
 
-        for (i = 0; i < len; ++i)
-                if (streq_ptr(table[i], key))
-                        return (ssize_t) i;
+                fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
 
-        return -1;
-}
+                        return -errno;
+                }
 
-void cmsg_close_all(struct msghdr *mh) {
-        struct cmsghdr *cmsg;
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
 
-        assert(mh);
+                if (n != 6 || memcmp(contents, "Mains\n", 6))
+                        continue;
 
-        CMSG_FOREACH(cmsg, mh)
-                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
-                        close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
-}
+                safe_close(fd);
+                fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
 
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
-        struct stat buf;
-        int ret;
+                        return -errno;
+                }
 
-        ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
-        if (ret >= 0)
-                return 0;
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
 
-        /* renameat2() exists since Linux 3.15, btrfs added support for it later.
-         * If it is not implemented, fallback to another method. */
-        if (!IN_SET(errno, EINVAL, ENOSYS))
-                return -errno;
+                if (n != 2 || contents[1] != '\n')
+                        return -EIO;
 
-        /* The link()/unlink() fallback does not work on directories. But
-         * renameat() without RENAME_NOREPLACE gives the same semantics on
-         * directories, except when newpath is an *empty* directory. This is
-         * good enough. */
-        ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
-        if (ret >= 0 && S_ISDIR(buf.st_mode)) {
-                ret = renameat(olddirfd, oldpath, newdirfd, newpath);
-                return ret >= 0 ? 0 : -errno;
+                if (contents[0] == '1') {
+                        found_online = true;
+                        break;
+                } else if (contents[0] == '0')
+                        found_offline = true;
+                else
+                        return -EIO;
         }
 
-        /* If it is not a directory, use the link()/unlink() fallback. */
-        ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
-        if (ret < 0)
-                return -errno;
+        return found_online || !found_offline;
+}
 
-        ret = unlinkat(olddirfd, oldpath, 0);
-        if (ret < 0) {
-                /* backup errno before the following unlinkat() alters it */
-                ret = errno;
-                (void) unlinkat(newdirfd, newpath, 0);
-                errno = ret;
-                return -errno;
-        }
+bool id128_is_valid(const char *s) {
+        size_t i, l;
 
-        return 0;
-}
+        l = strlen(s);
+        if (l == 32) {
 
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
-        assert(bad);
+                /* Simple formatted 128bit hex string */
 
-        for (; *s; s++) {
-                if (*s == '\\' || strchr(bad, *s))
-                        *(t++) = '\\';
+                for (i = 0; i < l; i++) {
+                        char c = s[i];
 
-                *(t++) = *s;
-        }
+                        if (!(c >= '0' && c <= '9') &&
+                            !(c >= 'a' && c <= 'z') &&
+                            !(c >= 'A' && c <= 'Z'))
+                                return false;
+                }
 
-        return t;
-}
+        } else if (l == 36) {
+
+                /* Formatted UUID */
 
-char *shell_escape(const char *s, const char *bad) {
-        char *r, *t;
+                for (i = 0; i < l; i++) {
+                        char c = s[i];
 
-        r = new(char, strlen(s)*2+1);
-        if (!r)
-                return NULL;
+                        if ((i == 8 || i == 13 || i == 18 || i == 23)) {
+                                if (c != '-')
+                                        return false;
+                        } else {
+                                if (!(c >= '0' && c <= '9') &&
+                                    !(c >= 'a' && c <= 'z') &&
+                                    !(c >= 'A' && c <= 'Z'))
+                                        return false;
+                        }
+                }
 
-        t = strcpy_backslash_escaped(r, s, bad);
-        *t = 0;
+        } else
+                return false;
 
-        return r;
+        return true;
 }
 
-char *shell_maybe_quote(const char *s) {
+int container_get_leader(const char *machine, pid_t *pid) {
+        _cleanup_free_ char *s = NULL, *class = NULL;
         const char *p;
-        char *r, *t;
+        pid_t leader;
+        int r;
 
-        assert(s);
+        assert(machine);
+        assert(pid);
 
-        /* Encloses a string in double quotes if necessary to make it
-         * OK as shell string. */
+        if (!machine_name_is_valid(machine))
+                return -EINVAL;
 
-        for (p = s; *p; p++)
-                if (*p <= ' ' ||
-                    *p >= 127 ||
-                    strchr(SHELL_NEED_QUOTES, *p))
-                        break;
+        p = strjoina("/run/systemd/machines/", machine);
+        r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
+        if (r == -ENOENT)
+                return -EHOSTDOWN;
+        if (r < 0)
+                return r;
+        if (!s)
+                return -EIO;
 
-        if (!*p)
-                return strdup(s);
+        if (!streq_ptr(class, "container"))
+                return -EIO;
 
-        r = new(char, 1+strlen(s)*2+1+1);
-        if (!r)
-                return NULL;
+        r = parse_pid(s, &leader);
+        if (r < 0)
+                return r;
+        if (leader <= 1)
+                return -EIO;
 
-        t = r;
-        *(t++) = '"';
-        t = mempcpy(t, s, p - s);
+        *pid = leader;
+        return 0;
+}
 
-        t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
+        int rfd = -1;
 
-        *(t++)= '"';
-        *t = 0;
+        assert(pid >= 0);
 
-        return r;
-}
+        if (mntns_fd) {
+                const char *mntns;
 
-int parse_mode(const char *s, mode_t *ret) {
-        char *x;
-        long l;
+                mntns = procfs_file_alloca(pid, "ns/mnt");
+                mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (mntnsfd < 0)
+                        return -errno;
+        }
 
-        assert(s);
-        assert(ret);
+        if (pidns_fd) {
+                const char *pidns;
 
-        errno = 0;
-        l = strtol(s, &x, 8);
-        if (errno != 0)
-                return -errno;
+                pidns = procfs_file_alloca(pid, "ns/pid");
+                pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (pidnsfd < 0)
+                        return -errno;
+        }
 
-        if (!x || x == s || *x)
-                return -EINVAL;
-        if (l < 0 || l  > 07777)
-                return -ERANGE;
+        if (netns_fd) {
+                const char *netns;
 
-        *ret = (mode_t) l;
-        return 0;
-}
+                netns = procfs_file_alloca(pid, "ns/net");
+                netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (netnsfd < 0)
+                        return -errno;
+        }
 
-int mount_move_root(const char *path) {
-        assert(path);
+        if (userns_fd) {
+                const char *userns;
 
-        if (chdir(path) < 0)
-                return -errno;
+                userns = procfs_file_alloca(pid, "ns/user");
+                usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (usernsfd < 0 && errno != ENOENT)
+                        return -errno;
+        }
 
-        if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
-                return -errno;
+        if (root_fd) {
+                const char *root;
 
-        if (chroot(".") < 0)
-                return -errno;
+                root = procfs_file_alloca(pid, "root");
+                rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+                if (rfd < 0)
+                        return -errno;
+        }
 
-        if (chdir("/") < 0)
-                return -errno;
+        if (pidns_fd)
+                *pidns_fd = pidnsfd;
 
-        return 0;
-}
+        if (mntns_fd)
+                *mntns_fd = mntnsfd;
 
-int reset_uid_gid(void) {
+        if (netns_fd)
+                *netns_fd = netnsfd;
 
-        if (setgroups(0, NULL) < 0)
-                return -errno;
+        if (userns_fd)
+                *userns_fd = usernsfd;
 
-        if (setresgid(0, 0, 0) < 0)
-                return -errno;
+        if (root_fd)
+                *root_fd = rfd;
 
-        if (setresuid(0, 0, 0) < 0)
-                return -errno;
+        pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
 
         return 0;
 }
 
-int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
-        char *v;
-        size_t l;
-        ssize_t n;
-
-        assert(path);
-        assert(name);
-        assert(value);
-
-        for (l = 100; ; l = (size_t) n + 1) {
-                v = new0(char, l);
-                if (!v)
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
+        if (userns_fd >= 0) {
+                /* Can't setns to your own userns, since then you could
+                 * escalate from non-root to root in your own namespace, so
+                 * check if namespaces equal before attempting to enter. */
+                _cleanup_free_ char *userns_fd_path = NULL;
+                int r;
+                if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
                         return -ENOMEM;
 
-                if (allow_symlink)
-                        n = lgetxattr(path, name, v, l);
-                else
-                        n = getxattr(path, name, v, l);
-
-                if (n >= 0 && (size_t) n < l) {
-                        *value = v;
-                        return n;
-                }
-
-                free(v);
+                r = files_same(userns_fd_path, "/proc/self/ns/user");
+                if (r < 0)
+                        return r;
+                if (r)
+                        userns_fd = -1;
+        }
 
-                if (n < 0 && errno != ERANGE)
+        if (pidns_fd >= 0)
+                if (setns(pidns_fd, CLONE_NEWPID) < 0)
                         return -errno;
 
-                if (allow_symlink)
-                        n = lgetxattr(path, name, NULL, 0);
-                else
-                        n = getxattr(path, name, NULL, 0);
-                if (n < 0)
+        if (mntns_fd >= 0)
+                if (setns(mntns_fd, CLONE_NEWNS) < 0)
                         return -errno;
-        }
-}
-
-int fgetxattr_malloc(int fd, const char *name, char **value) {
-        char *v;
-        size_t l;
-        ssize_t n;
-
-        assert(fd >= 0);
-        assert(name);
-        assert(value);
 
-        for (l = 100; ; l = (size_t) n + 1) {
-                v = new0(char, l);
-                if (!v)
-                        return -ENOMEM;
-
-                n = fgetxattr(fd, name, v, l);
-
-                if (n >= 0 && (size_t) n < l) {
-                        *value = v;
-                        return n;
-                }
+        if (netns_fd >= 0)
+                if (setns(netns_fd, CLONE_NEWNET) < 0)
+                        return -errno;
 
-                free(v);
+        if (userns_fd >= 0)
+                if (setns(userns_fd, CLONE_NEWUSER) < 0)
+                        return -errno;
 
-                if (n < 0 && errno != ERANGE)
+        if (root_fd >= 0) {
+                if (fchdir(root_fd) < 0)
                         return -errno;
 
-                n = fgetxattr(fd, name, NULL, 0);
-                if (n < 0)
+                if (chroot(".") < 0)
                         return -errno;
         }
-}
-
-int send_one_fd(int transport_fd, int fd, int flags) {
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
-        struct msghdr mh = {
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-        struct cmsghdr *cmsg;
-
-        assert(transport_fd >= 0);
-        assert(fd >= 0);
-
-        cmsg = CMSG_FIRSTHDR(&mh);
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type = SCM_RIGHTS;
-        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-        memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
-        mh.msg_controllen = CMSG_SPACE(sizeof(int));
-        if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
-                return -errno;
 
-        return 0;
+        return reset_uid_gid();
 }
 
-int receive_one_fd(int transport_fd, int flags) {
-        union {
-                struct cmsghdr cmsghdr;
-                uint8_t buf[CMSG_SPACE(sizeof(int))];
-        } control = {};
-        struct msghdr mh = {
-                .msg_control = &control,
-                .msg_controllen = sizeof(control),
-        };
-        struct cmsghdr *cmsg, *found = NULL;
-
-        assert(transport_fd >= 0);
-
-        /*
-         * Receive a single FD via @transport_fd. We don't care for
-         * the transport-type. We retrieve a single FD at most, so for
-         * packet-based transports, the caller must ensure to send
-         * only a single FD per packet.  This is best used in
-         * combination with send_one_fd().
-         */
-
-        if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
-                return -errno;
+uint64_t physical_memory(void) {
+        long mem;
 
-        CMSG_FOREACH(cmsg, &mh) {
-                if (cmsg->cmsg_level == SOL_SOCKET &&
-                    cmsg->cmsg_type == SCM_RIGHTS &&
-                    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
-                        assert(!found);
-                        found = cmsg;
-                        break;
-                }
-        }
+        /* We return this as uint64_t in case we are running as 32bit
+         * process on a 64bit kernel with huge amounts of memory */
 
-        if (!found) {
-                cmsg_close_all(&mh);
-                return -EIO;
-        }
+        mem = sysconf(_SC_PHYS_PAGES);
+        assert(mem > 0);
 
-        return *(int*) CMSG_DATA(found);
+        return (uint64_t) mem * (uint64_t) page_size();
 }
 
-void nop_signal_handler(int sig) {
-        /* nothing here */
+int update_reboot_param_file(const char *param) {
+        int r = 0;
+
+        if (param) {
+                r = write_string_file(REBOOT_PARAM_FILE, 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 0;
 }
 
 int version(void) {
@@ -6765,30 +838,3 @@ int version(void) {
              SYSTEMD_FEATURES);
         return 0;
 }
-
-bool fdname_is_valid(const char *s) {
-        const char *p;
-
-        /* Validates a name for $LISTEN_FDNAMES. We basically allow
-         * everything ASCII that's not a control character. Also, as
-         * special exception the ":" character is not allowed, as we
-         * use that as field separator in $LISTEN_FDNAMES.
-         *
-         * Note that the empty string is explicitly allowed
-         * here. However, we limit the length of the names to 255
-         * characters. */
-
-        if (!s)
-                return false;
-
-        for (p = s; *p; p++) {
-                if (*p < ' ')
-                        return false;
-                if (*p >= 127)
-                        return false;
-                if (*p == ':')
-                        return false;
-        }
-
-        return p - s < 256;
-}
index 79c7ad1b39918967b60c5a8c63bf760b8b6bec57..d9d2f72b750314afda0a039576a007b54512afa0 100644 (file)
 ***/
 
 #include <alloca.h>
-#include <dirent.h>
 #include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
 #include <locale.h>
-#include <mntent.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include "missing.h"
 #include "time-util.h"
 
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n\r"
-#define NEWLINE    "\n\r"
-#define QUOTES     "\"\'"
-#define COMMENTS   "#;"
-#define GLOB_CHARS "*?["
-
-/* What characters are special in the shell? */
-/* must be escaped outside and inside double-quotes */
-#define SHELL_NEED_ESCAPE "\"\\`$"
-/* can be escaped or double-quoted */
-#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
-
-#define FORMAT_BYTES_MAX 8
-
 size_t page_size(void) _pure_;
 #define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
 
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
-#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
-#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
-
-bool streq_ptr(const char *a, const char *b) _pure_;
-int strcmp_ptr(const char *a, const char *b) _pure_;
-
-#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
-
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
-
-#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
-
-#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
-
-#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
-
-#define malloc0(n) (calloc(1, (n)))
-
-static inline void *mfree(void *memory) {
-        free(memory);
-        return NULL;
-}
-
 static inline const char* yes_no(bool b) {
         return b ? "yes" : "no";
 }
@@ -101,345 +59,13 @@ static inline const char* one_zero(bool b) {
         return b ? "1" : "0";
 }
 
-static inline const char* strempty(const char *s) {
-        return s ? s : "";
-}
-
-static inline const char* strnull(const char *s) {
-        return s ? s : "(null)";
-}
-
-static inline const char *strna(const char *s) {
-        return s ? s : "n/a";
-}
-
-static inline bool isempty(const char *p) {
-        return !p || !p[0];
-}
-
-static inline char *startswith(const char *s, const char *prefix) {
-        size_t l;
-
-        l = strlen(prefix);
-        if (strncmp(s, prefix, l) == 0)
-                return (char*) s + l;
-
-        return NULL;
-}
-
-static inline char *startswith_no_case(const char *s, const char *prefix) {
-        size_t l;
-
-        l = strlen(prefix);
-        if (strncasecmp(s, prefix, l) == 0)
-                return (char*) s + l;
-
-        return NULL;
-}
-
-char *endswith(const char *s, const char *postfix) _pure_;
-char *endswith_no_case(const char *s, const char *postfix) _pure_;
-
-char *first_word(const char *s, const char *word) _pure_;
-
-int close_nointr(int fd);
-int safe_close(int fd);
-void safe_close_pair(int p[]);
-
-void close_many(const int fds[], unsigned n_fd);
-
-int fclose_nointr(FILE *f);
-FILE* safe_fclose(FILE *f);
-DIR* safe_closedir(DIR *f);
-
-int parse_size(const char *t, uint64_t base, uint64_t *size);
-
-int parse_boolean(const char *v) _pure_;
-int parse_pid(const char *s, pid_t* ret_pid);
-int parse_uid(const char *s, uid_t* ret_uid);
-#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
-
-bool uid_is_valid(uid_t uid);
-
-static inline bool gid_is_valid(gid_t gid) {
-        return uid_is_valid((uid_t) gid);
-}
-
-int safe_atou(const char *s, unsigned *ret_u);
-int safe_atoi(const char *s, int *ret_i);
-
-int safe_atollu(const char *s, unsigned long long *ret_u);
-int safe_atolli(const char *s, long long int *ret_i);
-
-int safe_atod(const char *s, double *ret_d);
-
-int safe_atou8(const char *s, uint8_t *ret);
-
-#if LONG_MAX == INT_MAX
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
-        assert_cc(sizeof(unsigned long) == sizeof(unsigned));
-        return safe_atou(s, (unsigned*) ret_u);
-}
-static inline int safe_atoli(const char *s, long int *ret_u) {
-        assert_cc(sizeof(long int) == sizeof(int));
-        return safe_atoi(s, (int*) ret_u);
-}
-#else
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
-        assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
-        return safe_atollu(s, (unsigned long long*) ret_u);
-}
-static inline int safe_atoli(const char *s, long int *ret_u) {
-        assert_cc(sizeof(long int) == sizeof(long long int));
-        return safe_atolli(s, (long long int*) ret_u);
-}
-#endif
-
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
-        assert_cc(sizeof(uint32_t) == sizeof(unsigned));
-        return safe_atou(s, (unsigned*) ret_u);
-}
-
-static inline int safe_atoi32(const char *s, int32_t *ret_i) {
-        assert_cc(sizeof(int32_t) == sizeof(int));
-        return safe_atoi(s, (int*) ret_i);
-}
-
-static inline int safe_atou64(const char *s, uint64_t *ret_u) {
-        assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
-        return safe_atollu(s, (unsigned long long*) ret_u);
-}
-
-static inline int safe_atoi64(const char *s, int64_t *ret_i) {
-        assert_cc(sizeof(int64_t) == sizeof(long long int));
-        return safe_atolli(s, (long long int*) ret_i);
-}
-
-int safe_atou16(const char *s, uint16_t *ret);
-int safe_atoi16(const char *s, int16_t *ret);
-
-const char* split(const char **state, size_t *l, const char *separator, bool quoted);
-
-#define FOREACH_WORD(word, length, s, state)                            \
-        _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
-
-#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state)       \
-        _FOREACH_WORD(word, length, s, separator, false, state)
-
-#define FOREACH_WORD_QUOTED(word, length, s, state)                     \
-        _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
-
-#define _FOREACH_WORD(word, length, s, separator, quoted, state)        \
-        for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
-
-char *strappend(const char *s, const char *suffix);
-char *strnappend(const char *s, const char *suffix, size_t length);
-
-int readlinkat_malloc(int fd, const char *p, char **ret);
-int readlink_malloc(const char *p, char **r);
-int readlink_value(const char *p, char **ret);
-int readlink_and_make_absolute(const char *p, char **r);
-int readlink_and_canonicalize(const char *p, char **r);
-
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *truncate_nl(char *s);
-
-char *file_in_same_dir(const char *path, const char *filename);
-
-int rmdir_parents(const char *path, const char *stop);
-
-char hexchar(int x) _const_;
-int unhexchar(char c) _const_;
-char octchar(int x) _const_;
-int unoctchar(char c) _const_;
-char decchar(int x) _const_;
-int undecchar(char c) _const_;
-char base32hexchar(int x) _const_;
-int unbase32hexchar(char c) _const_;
-char base64char(int x) _const_;
-int unbase64char(char c) _const_;
-
-char *cescape(const char *s);
-size_t cescape_char(char c, char *buf);
-
-typedef enum UnescapeFlags {
-        UNESCAPE_RELAX = 1,
-} UnescapeFlags;
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret);
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-
-char *xescape(const char *s, const char *bad);
-
-char *ascii_strlower(char *path);
-
-bool dirent_is_file(const struct dirent *de) _pure_;
-bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
-
-bool hidden_file(const char *filename) _pure_;
-
-bool chars_intersect(const char *a, const char *b) _pure_;
-
-/* For basic lookup tables with strictly enumerated entries */
-#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope)          \
-        scope const char *name##_to_string(type i) {                    \
-                if (i < 0 || i >= (type) ELEMENTSOF(name##_table))      \
-                        return NULL;                                    \
-                return name##_table[i];                                 \
-        }
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
-
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)        \
-        scope type name##_from_string(const char *s) {                  \
-                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(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)
-
-/* 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) {                \
-                char *s;                                                \
-                if (i < 0 || i > max)                                   \
-                        return -ERANGE;                                 \
-                if (i < (type) ELEMENTSOF(name##_table)) {              \
-                        s = strdup(name##_table[i]);                    \
-                        if (!s)                                         \
-                                return -ENOMEM;                         \
-                } else {                                                \
-                        if (asprintf(&s, "%i", i) < 0)                  \
-                                return -ENOMEM;                         \
-                }                                                       \
-                *str = s;                                               \
-                return 0;                                               \
-        }                                                               \
-        type name##_from_string(const char *s) {                        \
-                type i;                                                 \
-                unsigned u = 0;                                         \
-                if (!s)                                                 \
-                        return (type) -1;                               \
-                for (i = 0; i < (type) ELEMENTSOF(name##_table); i++)   \
-                        if (streq_ptr(name##_table[i], s))              \
-                                return i;                               \
-                if (safe_atou(s, &u) >= 0 && u <= max)                  \
-                        return (type) u;                                \
-                return (type) -1;                                       \
-        }                                                               \
-        struct __useless_struct_to_allow_trailing_semicolon__
-
-int fd_nonblock(int fd, bool nonblock);
-int fd_cloexec(int fd, bool cloexec);
-
-int close_all_fds(const int except[], unsigned n_except);
-
-bool fstype_is_network(const char *fstype);
-
-int flush_fd(int fd);
-
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
-
-bool is_device_path(const char *path);
-
-int dir_is_empty(const char *path);
-char* dirname_malloc(const char *path);
-
-char* lookup_uid(uid_t uid);
-char* getlogname_malloc(void);
-char* getusername_malloc(void);
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
-int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
-
-bool is_temporary_fs(const struct statfs *s) _pure_;
-int fd_is_temporary_fs(int fd);
-
-int pipe_eof(int fd);
-
-#define xsprintf(buf, fmt, ...) \
-        assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
-                          "xsprintf: " #buf "[] must be big enough")
-
-int files_same(const char *filea, const char *fileb);
-
-int running_in_chroot(void);
-
-char *ellipsize(const char *s, size_t length, unsigned percent);
-                                   /* bytes                 columns */
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
-int touch(const char *path);
-
-noreturn void freeze(void);
-
-bool null_or_empty(struct stat *st) _pure_;
-int null_or_empty_path(const char *fn);
-int null_or_empty_fd(int fd);
-
-DIR *xopendirat(int dirfd, const char *name, int flags);
-
-char *fstab_node_to_udev_node(const char *p);
-
 void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
 
-bool nulstr_contains(const char*nulstr, const char *needle);
-
 bool plymouth_running(void);
 
-char* strshorten(char *s, size_t l);
-
-int symlink_idempotent(const char *from, const char *to);
-
-int symlink_atomic(const char *from, const char *to);
-int mknod_atomic(const char *path, mode_t mode, dev_t dev);
-int mkfifo_atomic(const char *path, mode_t mode);
-
-int fchmod_umask(int fd, mode_t mode);
-
 bool display_is_local(const char *display) _pure_;
 int socket_from_display(const char *display, char **path);
 
-int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
-int get_group_creds(const char **groupname, gid_t *gid);
-
-int in_gid(gid_t gid);
-int in_group(const char *name);
-
-char* uid_to_name(uid_t uid);
-char* gid_to_name(gid_t gid);
-
-int glob_exists(const char *path);
-int glob_extend(char ***strv, const char *path);
-
-int dirent_ensure_type(DIR *d, struct dirent *de);
-
-int get_files_in_directory(const char *path, char ***list);
-
-char *strjoin(const char *x, ...) _sentinel_;
-
-bool is_main_thread(void);
-
-static inline bool _pure_ in_charset(const char *s, const char* charset) {
-        assert(s);
-        assert(charset);
-        return s[strspn(s, charset)] == '\0';
-}
-
 int block_get_whole_disk(dev_t d, dev_t *ret);
 
 #define NULSTR_FOREACH(i, l)                                    \
@@ -448,27 +74,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret);
 #define NULSTR_FOREACH_PAIR(i, j, l)                             \
         for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
 
-int ioprio_class_to_string_alloc(int i, char **s);
-int ioprio_class_from_string(const char *s);
-
-const char *sigchld_code_to_string(int i) _const_;
-int sigchld_code_from_string(const char *s) _pure_;
-
-int log_facility_unshifted_to_string_alloc(int i, char **s);
-int log_facility_unshifted_from_string(const char *s);
-
-int log_level_to_string_alloc(int i, char **s);
-int log_level_from_string(const char *s);
-
-int sched_policy_to_string_alloc(int i, char **s);
-int sched_policy_from_string(const char *s);
-
-const char *rlimit_to_string(int i) _const_;
-int rlimit_from_string(const char *s) _pure_;
-
-int ip_tos_to_string_alloc(int i, char **s);
-int ip_tos_from_string(const char *s);
-
 extern int saved_argc;
 extern char **saved_argv;
 
@@ -476,182 +81,36 @@ bool kexec_loaded(void);
 
 int prot_from_flags(int flags) _const_;
 
-char *format_bytes(char *buf, size_t l, uint64_t t);
-
-int fd_wait_for_event(int fd, int event, usec_t timeout);
-
-void* memdup(const void *p, size_t l) _alloc_(2);
-
-int fd_inc_sndbuf(int fd, size_t n);
-int fd_inc_rcvbuf(int fd, size_t n);
-
 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
 
-int setrlimit_closest(int resource, const struct rlimit *rlim);
-
-bool http_url_is_valid(const char *url) _pure_;
-bool documentation_url_is_valid(const char *url) _pure_;
-
-bool http_etag_is_valid(const char *etag);
-
 bool in_initrd(void);
 
-int get_home_dir(char **ret);
-int get_shell(char **_ret);
-
-static inline void freep(void *p) {
-        free(*(void**) p);
-}
-
-static inline void closep(int *fd) {
-        safe_close(*fd);
-}
-
-static inline void umaskp(mode_t *u) {
-        umask(*u);
-}
-
-static inline void close_pairp(int (*p)[2]) {
-        safe_close_pair(*p);
-}
-
-static inline void fclosep(FILE **f) {
-        safe_fclose(*f);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
-
-#define _cleanup_free_ _cleanup_(freep)
-#define _cleanup_close_ _cleanup_(closep)
-#define _cleanup_umask_ _cleanup_(umaskp)
-#define _cleanup_globfree_ _cleanup_(globfree)
-#define _cleanup_fclose_ _cleanup_(fclosep)
-#define _cleanup_pclose_ _cleanup_(pclosep)
-#define _cleanup_closedir_ _cleanup_(closedirp)
-#define _cleanup_endmntent_ _cleanup_(endmntentp)
-#define _cleanup_close_pair_ _cleanup_(close_pairp)
-
-_malloc_  _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
-        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
-                return NULL;
-
-        return malloc(a * b);
-}
-
-_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
-        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
-                return NULL;
-
-        return realloc(p, a * b);
-}
-
-_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
-        if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
-                return NULL;
-
-        return memdup(p, a * b);
-}
-
-bool filename_is_valid(const char *p) _pure_;
-bool path_is_safe(const char *p) _pure_;
-bool string_is_safe(const char *p) _pure_;
-bool string_has_cc(const char *p, const char *ok) _pure_;
-
-/**
- * Check if a string contains any glob patterns.
- */
-_pure_ static inline bool string_is_glob(const char *p) {
-        return !!strpbrk(p, GLOB_CHARS);
-}
-
 void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
                  int (*compar) (const void *, const void *, void *),
                  void *arg);
 
-#define _(String) gettext (String)
-#define N_(String) String
-void init_gettext(void);
-bool is_locale_utf8(void);
-
-typedef enum DrawSpecialChar {
-        DRAW_TREE_VERTICAL,
-        DRAW_TREE_BRANCH,
-        DRAW_TREE_RIGHT,
-        DRAW_TREE_SPACE,
-        DRAW_TRIANGULAR_BULLET,
-        DRAW_BLACK_CIRCLE,
-        DRAW_ARROW,
-        DRAW_DASH,
-        _DRAW_SPECIAL_CHAR_MAX
-} DrawSpecialChar;
-
-const char *draw_special_char(DrawSpecialChar ch);
-
-char *strreplace(const char *text, const char *old_string, const char *new_string);
+/**
+ * Normal qsort requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+        if (nmemb <= 1)
+                return;
 
-char *strip_tab_ansi(char **p, size_t *l);
+        assert(base);
+        qsort(base, nmemb, size, compar);
+}
 
 int on_ac_power(void);
 
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
-
-#define FOREACH_LINE(line, f, on_error)                         \
-        for (;;)                                                \
-                if (!fgets(line, sizeof(line), f)) {            \
-                        if (ferror(f)) {                        \
-                                on_error;                       \
-                        }                                       \
-                        break;                                  \
-                } else
-
-#define FOREACH_DIRENT(de, d, on_error)                                 \
-        for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d))   \
-                if (!de) {                                              \
-                        if (errno > 0) {                                \
-                                on_error;                               \
-                        }                                               \
-                        break;                                          \
-                } else if (hidden_file((de)->d_name))                   \
-                        continue;                                       \
-                else
-
-#define FOREACH_DIRENT_ALL(de, d, on_error)                             \
-        for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d))   \
-                if (!de) {                                              \
-                        if (errno > 0) {                                \
-                                on_error;                               \
-                        }                                               \
-                        break;                                          \
-                } else
+#define memzero(x,l) (memset((x), 0, (l)))
+#define zero(x) (memzero(&(x), sizeof(x)))
 
 static inline void *mempset(void *s, int c, size_t n) {
         memset(s, c, n);
         return (uint8_t*)s + n;
 }
 
-char *hexmem(const void *p, size_t l);
-int unhexmem(const char *p, size_t l, void **mem, size_t *len);
-
-char *base32hexmem(const void *p, size_t l, bool padding);
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
-
-char *base64mem(const void *p, size_t l);
-int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
-
-char *strextend(char **x, ...) _sentinel_;
-char *strrep(const char *s, unsigned n);
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
-#define GREEDY_REALLOC(array, allocated, need)                          \
-        greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
-#define GREEDY_REALLOC0(array, allocated, need)                         \
-        greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
 static inline void _reset_errno_(int *saved_errno) {
         errno = *saved_errno;
 }
@@ -667,20 +126,6 @@ static inline int negative_errno(void) {
         return -errno;
 }
 
-struct _umask_struct_ {
-        mode_t mask;
-        bool quit;
-};
-
-static inline void _reset_umask_(struct _umask_struct_ *s) {
-        umask(s->mask);
-};
-
-#define RUN_WITH_UMASK(mask)                                            \
-        for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
-             !_saved_umask_.quit ;                                      \
-             _saved_umask_.quit = true)
-
 static inline unsigned u64log2(uint64_t n) {
 #if __SIZEOF_LONG_LONG__ == 8
         return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@@ -718,224 +163,15 @@ static inline unsigned log2u_round_up(unsigned x) {
         return log2u(x - 1) + 1;
 }
 
-static inline bool logind_running(void) {
-        return access("/run/systemd/seats/", F_OK) >= 0;
-}
-
-#define DECIMAL_STR_WIDTH(x)                            \
-        ({                                              \
-                typeof(x) _x_ = (x);                    \
-                unsigned ans = 1;                       \
-                while (_x_ /= 10)                       \
-                        ans++;                          \
-                ans;                                    \
-        })
-
-int unlink_noerrno(const char *path);
-
-#define alloca0(n)                                      \
-        ({                                              \
-                char *_new_;                            \
-                size_t _len_ = n;                       \
-                _new_ = alloca(_len_);                  \
-                (void *) memset(_new_, 0, _len_);       \
-        })
-
-/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
-#define alloca_align(size, align)                                       \
-        ({                                                              \
-                void *_ptr_;                                            \
-                size_t _mask_ = (align) - 1;                            \
-                _ptr_ = alloca((size) + _mask_);                        \
-                (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_);         \
-        })
-
-#define alloca0_align(size, align)                                      \
-        ({                                                              \
-                void *_new_;                                            \
-                size_t _size_ = (size);                                 \
-                _new_ = alloca_align(_size_, (align));                  \
-                (void*)memset(_new_, 0, _size_);                        \
-        })
-
-#define strjoina(a, ...)                                                \
-        ({                                                              \
-                const char *_appendees_[] = { a, __VA_ARGS__ };         \
-                char *_d_, *_p_;                                        \
-                int _len_ = 0;                                          \
-                unsigned _i_;                                           \
-                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
-                        _len_ += strlen(_appendees_[_i_]);              \
-                _p_ = _d_ = alloca(_len_ + 1);                          \
-                for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
-                        _p_ = stpcpy(_p_, _appendees_[_i_]);            \
-                *_p_ = 0;                                               \
-                _d_;                                                    \
-        })
-
 bool id128_is_valid(const char *s) _pure_;
 
-int split_pair(const char *s, const char *sep, char **l, char **r);
-
-int shall_restore_state(void);
-
-/**
- * Normal qsort requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
-        if (nmemb <= 1)
-                return;
-
-        assert(base);
-        qsort(base, nmemb, size, compar);
-}
-
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
-        if (needlelen <= 0)
-                return (void*) haystack;
-
-        if (haystacklen < needlelen)
-                return NULL;
-
-        assert(haystack);
-        assert(needle);
-
-        return memmem(haystack, haystacklen, needle, needlelen);
-}
-
-int proc_cmdline(char **ret);
-int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
-int get_proc_cmdline_key(const char *parameter, char **value);
-
 int container_get_leader(const char *machine, pid_t *pid);
 
 int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
 int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
 
-int getpeercred(int fd, struct ucred *ucred);
-int getpeersec(int fd, char **ret);
-
-int writev_safe(int fd, const struct iovec *w, int j);
-
-int mkostemp_safe(char *pattern, int flags);
-int open_tmpfile(const char *path, int flags);
-
-int fd_warn_permissions(const char *path, int fd);
-
-#ifndef PERSONALITY_INVALID
-/* personality(7) documents that 0xffffffffUL is used for querying the
- * current personality, hence let's use that here as error
- * indicator. */
-#define PERSONALITY_INVALID 0xffffffffLU
-#endif
-
-unsigned long personality_from_string(const char *p);
-const char *personality_to_string(unsigned long);
-
 uint64_t physical_memory(void);
 
-void hexdump(FILE *f, const void *p, size_t s);
-
-union file_handle_union {
-        struct file_handle handle;
-        char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
-};
-#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
-
 int update_reboot_param_file(const char *param);
 
-int umount_recursive(const char *target, int flags);
-
-int bind_remount_recursive(const char *prefix, bool ro);
-
-int fflush_and_check(FILE *f);
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
-int tempfn_random(const char *p, const char *extra, char **ret);
-int tempfn_random_child(const char *p, const char *extra, char **ret);
-
-int take_password_lock(const char *root);
-
-int is_symlink(const char *path);
-int is_dir(const char *path, bool follow);
-int is_device_node(const char *path);
-
-typedef enum ExtractFlags {
-        EXTRACT_RELAX           = 1,
-        EXTRACT_CUNESCAPE       = 2,
-        EXTRACT_CUNESCAPE_RELAX = 4,
-        EXTRACT_QUOTES          = 8,
-        EXTRACT_DONT_COALESCE_SEPARATORS = 16,
-} ExtractFlags;
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
-int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
-
-int free_and_strdup(char **p, const char *s);
-
-#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
-
-#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
-        for ((e) = &buffer.ev;                                \
-             (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
-             (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
-
-union inotify_event_buffer {
-        struct inotify_event ev;
-        uint8_t raw[INOTIFY_EVENT_MAX];
-};
-
-#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
-
-ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
-
-int fd_setcrtime(int fd, usec_t usec);
-int fd_getcrtime(int fd, usec_t *usec);
-int path_getcrtime(const char *p, usec_t *usec);
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
-
-int same_fd(int a, int b);
-
-int chattr_fd(int fd, unsigned value, unsigned mask);
-int chattr_path(const char *p, unsigned value, unsigned mask);
-
-int read_attr_fd(int fd, unsigned *ret);
-int read_attr_path(const char *p, unsigned *ret);
-
-#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
-
-int syslog_parse_priority(const char **p, int *priority, bool with_facility);
-
-void cmsg_close_all(struct msghdr *mh);
-
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
-
-char *shell_escape(const char *s, const char *bad);
-char *shell_maybe_quote(const char *s);
-
-int parse_mode(const char *s, mode_t *ret);
-
-int mount_move_root(const char *path);
-
-int reset_uid_gid(void);
-
-int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
-int fgetxattr_malloc(int fd, const char *name, char **value);
-
-int send_one_fd(int transport_fd, int fd, int flags);
-int receive_one_fd(int transport_fd, int flags);
-
-void nop_signal_handler(int sig);
-
 int version(void);
-
-bool fdname_is_valid(const char *s);
index c7beccc2dc291c762307a3f7ccb87200c0fdf9eb..d63062d39e3bc88c9eaf5c343cb216e5cd844604 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "string-util.h"
 #include "util.h"
 #include "verbs.h"
 
index 70543177b6fe1f9910635c2df312a879497676cd..d088b7a8049493f44002e7c729c0e3382d34016c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
+#include <string.h>
 #include <unistd.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "fileio.h"
 #include "process-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
 #include "virt.h"
-#include "fileio.h"
 
 static int detect_vm_cpuid(void) {
 
-        /* Both CPUID and DMI are x86 specific interfaces... */
+        /* CPUID is an x86 specific interface. */
 #if defined(__i386__) || defined(__x86_64__)
 
         static const struct {
@@ -140,11 +144,10 @@ static int detect_vm_device_tree(void) {
 }
 
 static int detect_vm_dmi(void) {
-
-        /* Both CPUID and DMI are x86 specific interfaces... */
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
 
         static const char *const dmi_vendors[] = {
+                "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
                 "/sys/class/dmi/id/sys_vendor",
                 "/sys/class/dmi/id/board_vendor",
                 "/sys/class/dmi/id/bios_vendor"
@@ -154,6 +157,7 @@ static int detect_vm_dmi(void) {
                 const char *vendor;
                 int id;
         } dmi_vendor_table[] = {
+                { "KVM",           VIRTUALIZATION_KVM       },
                 { "QEMU",          VIRTUALIZATION_QEMU      },
                 /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
                 { "VMware",        VIRTUALIZATION_VMWARE    },
@@ -263,12 +267,7 @@ int detect_vm(void) {
         if (cached_found >= 0)
                 return cached_found;
 
-        /* Try xen capabilities file first, if not found try
-         * high-level hypervisor sysfs file:
-         *
-         * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
-
-        r = detect_vm_xen();
+        r = detect_vm_cpuid();
         if (r < 0)
                 return r;
         if (r != VIRTUALIZATION_NONE)
@@ -280,7 +279,14 @@ int detect_vm(void) {
         if (r != VIRTUALIZATION_NONE)
                 goto finish;
 
-        r = detect_vm_cpuid();
+        /* x86 xen will most likely be detected by cpuid. If not (most likely
+         * because we're not an x86 guest), then we should try the xen capabilities
+         * file next. If that's not found, then we check for the high-level
+         * hypervisor sysfs file:
+         *
+         * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
+
+        r = detect_vm_xen();
         if (r < 0)
                 return r;
         if (r != VIRTUALIZATION_NONE)
@@ -323,6 +329,7 @@ int detect_container(void) {
                 { "lxc-libvirt",    VIRTUALIZATION_LXC_LIBVIRT    },
                 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
                 { "docker",         VIRTUALIZATION_DOCKER         },
+                { "rkt",            VIRTUALIZATION_RKT            },
         };
 
         static thread_local int cached_found = _VIRTUALIZATION_INVALID;
@@ -393,7 +400,7 @@ int detect_container(void) {
                         goto finish;
                 }
 
-        r = VIRTUALIZATION_NONE;
+        r = VIRTUALIZATION_CONTAINER_OTHER;
 
 finish:
         cached_found = r;
@@ -410,6 +417,16 @@ int detect_virtualization(void) {
         return detect_vm();
 }
 
+int running_in_chroot(void) {
+        int ret;
+
+        ret = files_same("/proc/1/root", "/");
+        if (ret < 0)
+                return ret;
+
+        return ret == 0;
+}
+
 static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_NONE] = "none",
         [VIRTUALIZATION_KVM] = "kvm",
@@ -429,6 +446,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_LXC] = "lxc",
         [VIRTUALIZATION_OPENVZ] = "openvz",
         [VIRTUALIZATION_DOCKER] = "docker",
+        [VIRTUALIZATION_RKT] = "rkt",
         [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
 };
 
index 449e069901777787fe37a4e16a7cbe3009b97224..aca961867c4146ce8d7f367368e71068b7db5c1b 100644 (file)
@@ -48,6 +48,7 @@ enum {
         VIRTUALIZATION_LXC,
         VIRTUALIZATION_OPENVZ,
         VIRTUALIZATION_DOCKER,
+        VIRTUALIZATION_RKT,
         VIRTUALIZATION_CONTAINER_OTHER,
         VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER,
 
@@ -67,5 +68,7 @@ int detect_vm(void);
 int detect_container(void);
 int detect_virtualization(void);
 
+int running_in_chroot(void);
+
 const char *virtualization_to_string(int v) _const_;
 int virtualization_from_string(const char *s) _pure_;
diff --git a/src/basic/web-util.c b/src/basic/web-util.c
new file mode 100644 (file)
index 0000000..68ec040
--- /dev/null
@@ -0,0 +1,78 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+
+#include "string-util.h"
+#include "utf8.h"
+#include "web-util.h"
+
+bool http_etag_is_valid(const char *etag) {
+        if (isempty(etag))
+                return false;
+
+        if (!endswith(etag, "\""))
+                return false;
+
+        if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
+                return false;
+
+        return true;
+}
+
+bool http_url_is_valid(const char *url) {
+        const char *p;
+
+        if (isempty(url))
+                return false;
+
+        p = startswith(url, "http://");
+        if (!p)
+                p = startswith(url, "https://");
+        if (!p)
+                return false;
+
+        if (isempty(p))
+                return false;
+
+        return ascii_is_valid(p);
+}
+
+bool documentation_url_is_valid(const char *url) {
+        const char *p;
+
+        if (isempty(url))
+                return false;
+
+        if (http_url_is_valid(url))
+                return true;
+
+        p = startswith(url, "file:/");
+        if (!p)
+                p = startswith(url, "info:");
+        if (!p)
+                p = startswith(url, "man:");
+
+        if (isempty(p))
+                return false;
+
+        return ascii_is_valid(p);
+}
similarity index 80%
rename from src/core/dbus-snapshot.h
rename to src/basic/web-util.h
index 9288f44e150f36e2c1ed51300a224e14cff06e14..40c1509eb8c9eb8e868559c204195756fc2d5090 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "sd-bus.h"
+#include <stdbool.h>
 
-extern const sd_bus_vtable bus_snapshot_vtable[];
+#include "macro.h"
 
-int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
+bool http_url_is_valid(const char *url) _pure_;
+
+bool documentation_url_is_valid(const char *url) _pure_;
+
+bool http_etag_is_valid(const char *etag);
diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c
new file mode 100644 (file)
index 0000000..6abdaed
--- /dev/null
@@ -0,0 +1,195 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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/xattr.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "sparse-endian.h"
+#include "stdio-util.h"
+#include "util.h"
+#include "xattr-util.h"
+
+int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
+        char *v;
+        size_t l;
+        ssize_t n;
+
+        assert(path);
+        assert(name);
+        assert(value);
+
+        for (l = 100; ; l = (size_t) n + 1) {
+                v = new0(char, l);
+                if (!v)
+                        return -ENOMEM;
+
+                if (allow_symlink)
+                        n = lgetxattr(path, name, v, l);
+                else
+                        n = getxattr(path, name, v, l);
+
+                if (n >= 0 && (size_t) n < l) {
+                        *value = v;
+                        return n;
+                }
+
+                free(v);
+
+                if (n < 0 && errno != ERANGE)
+                        return -errno;
+
+                if (allow_symlink)
+                        n = lgetxattr(path, name, NULL, 0);
+                else
+                        n = getxattr(path, name, NULL, 0);
+                if (n < 0)
+                        return -errno;
+        }
+}
+
+int fgetxattr_malloc(int fd, const char *name, char **value) {
+        char *v;
+        size_t l;
+        ssize_t n;
+
+        assert(fd >= 0);
+        assert(name);
+        assert(value);
+
+        for (l = 100; ; l = (size_t) n + 1) {
+                v = new0(char, l);
+                if (!v)
+                        return -ENOMEM;
+
+                n = fgetxattr(fd, name, v, l);
+
+                if (n >= 0 && (size_t) n < l) {
+                        *value = v;
+                        return n;
+                }
+
+                free(v);
+
+                if (n < 0 && errno != ERANGE)
+                        return -errno;
+
+                n = fgetxattr(fd, name, NULL, 0);
+                if (n < 0)
+                        return -errno;
+        }
+}
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+        char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+        _cleanup_close_ int fd = -1;
+        ssize_t l;
+
+        /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
+
+        fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+        if (fd < 0)
+                return -errno;
+
+        xsprintf(fn, "/proc/self/fd/%i", fd);
+
+        l = getxattr(fn, attribute, value, size);
+        if (l < 0)
+                return -errno;
+
+        return l;
+}
+
+static int parse_crtime(le64_t le, usec_t *usec) {
+        uint64_t u;
+
+        assert(usec);
+
+        u = le64toh(le);
+        if (u == 0 || u == (uint64_t) -1)
+                return -EIO;
+
+        *usec = (usec_t) u;
+        return 0;
+}
+
+int fd_getcrtime(int fd, usec_t *usec) {
+        le64_t le;
+        ssize_t n;
+
+        assert(fd >= 0);
+        assert(usec);
+
+        /* Until Linux gets a real concept of birthtime/creation time,
+         * let's fake one with xattrs */
+
+        n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
+        if (n < 0)
+                return -errno;
+        if (n != sizeof(le))
+                return -EIO;
+
+        return parse_crtime(le, usec);
+}
+
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
+        le64_t le;
+        ssize_t n;
+
+        n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
+        if (n < 0)
+                return -errno;
+        if (n != sizeof(le))
+                return -EIO;
+
+        return parse_crtime(le, usec);
+}
+
+int path_getcrtime(const char *p, usec_t *usec) {
+        le64_t le;
+        ssize_t n;
+
+        assert(p);
+        assert(usec);
+
+        n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
+        if (n < 0)
+                return -errno;
+        if (n != sizeof(le))
+                return -EIO;
+
+        return parse_crtime(le, usec);
+}
+
+int fd_setcrtime(int fd, usec_t usec) {
+        le64_t le;
+
+        assert(fd >= 0);
+
+        if (usec <= 0)
+                usec = now(CLOCK_REALTIME);
+
+        le = htole64((uint64_t) usec);
+        if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h
new file mode 100644 (file)
index 0000000..cf4cb12
--- /dev/null
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 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 <stdbool.h>
+#include <sys/types.h>
+
+#include "time-util.h"
+
+int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
+int fgetxattr_malloc(int fd, const char *name, char **value);
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
+
+int fd_setcrtime(int fd, usec_t usec);
+
+int fd_getcrtime(int fd, usec_t *usec);
+int path_getcrtime(const char *p, usec_t *usec);
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
index 15c629b1884ca172ac16e719ba3bd9eec5aba8a0..8126bce212622caffea5d5cc75c5e540b5aa0989 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <string.h>
 
+#include "string-util.h"
 #include "util.h"
 #include "xml.h"
 
index ddb5c88806024556c79f6f1825507a93dfbcd02a..03fb413fe5e40ddfcbe8e25f6e703ada91cba503 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("binfmt.d");
 
 static int delete_rule(const char *rule) {
         _cleanup_free_ char *x = NULL, *fn = NULL;
@@ -90,8 +94,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
                         if (feof(f))
                                 break;
 
-                        log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
-                        return -errno;
+                        return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
                 }
 
                 p = strstrip(l);
index f991e30cfa24f159235aa5f3d2cda58971ad3eb4..4cf42d17f34b76b6dc71e317990966297af888aa 100644 (file)
 #include <sys/statfs.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "blkid-util.h"
 #include "efivars.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "locale-util.h"
 #include "rm-rf.h"
+#include "string-util.h"
 #include "util.h"
 
 static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
index 83ad90c222c4a2565ef7b27eefb4c6a2d3f79b9b..6a0e1d6b141b726f6413543d6901cba3084f7d67 100644 (file)
 
  ***/
 
-#include <sys/resource.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
 #include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
+#include <sys/resource.h>
 #include <time.h>
-#include <getopt.h>
-#include <limits.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include "systemd/sd-journal.h"
+#include <unistd.h>
 
-#include "util.h"
+#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "bootchart.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "io-util.h"
+#include "list.h"
 #include "macro.h"
-#include "conf-parser.h"
-#include "strxcpyx.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "store.h"
+#include "string-util.h"
+#include "strxcpyx.h"
 #include "svg.h"
-#include "bootchart.h"
-#include "list.h"
+#include "util.h"
 
 static int exiting = 0;
 
@@ -88,8 +95,6 @@ static void signal_handler(int sig) {
         exiting = 1;
 }
 
-#define BOOTCHART_CONF "/etc/systemd/bootchart.conf"
-
 #define BOOTCHART_MAX (16*1024*1024)
 
 static void parse_conf(void) {
@@ -110,8 +115,8 @@ static void parse_conf(void) {
                 { NULL, NULL, NULL, 0, NULL }
         };
 
-        config_parse_many(BOOTCHART_CONF,
-                          CONF_DIRS_NULSTR("systemd/bootchart.conf"),
+        config_parse_many(PKGSYSCONFDIR "/bootchart.conf",
+                          CONF_PATHS_NULSTR("systemd/bootchart.conf.d"),
                           NULL, config_item_table_lookup, items, true, NULL);
 
         if (init != NULL)
index caa97b97fc1566f69bc760b1fd76e2c2edab95b4..c1b1e77e4476a0c1cc7a3394cc6a435622f955b9 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
-#include <unistd.h>
-#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
 #include <time.h>
+#include <unistd.h>
 
-#include "util.h"
-#include "time-util.h"
-#include "strxcpyx.h"
-#include "store.h"
+#include "alloc-util.h"
 #include "bootchart.h"
 #include "cgroup-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "parse-util.h"
+#include "store.h"
+#include "string-util.h"
+#include "strxcpyx.h"
+#include "time-util.h"
+#include "util.h"
 
 /*
  * Alloc a static 4k buffer for stdio - primarily used to increase
index db5fc863b0fee84910f49024bb5875c8544e1acf..05330c057799a2a029a0272fcdfaa90b001a4806 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/utsname.h>
 #include <fcntl.h>
 
+#include "alloc-util.h"
 #include "architecture.h"
 #include "util.h"
 #include "fileio.h"
@@ -39,6 +40,7 @@
 #include "bootchart.h"
 #include "list.h"
 #include "utf8.h"
+#include "fd-util.h"
 
 #define time_to_graph(t) ((t) * arg_scale_x)
 #define ps_to_graph(n) ((n) * arg_scale_y)
index 2bc265d9b491c8a549a9a8608d6612c2f3191748..6a7134644fda775d57bc8d3ab5d64993407777f0 100644 (file)
 
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-xml-policy.h"
-#include "capability.h"
+#include "capability-util.h"
 #include "def.h"
+#include "fd-util.h"
 #include "formats-util.h"
 #include "log.h"
 #include "proxy.h"
+#include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
 
 static char *arg_address = NULL;
@@ -85,11 +89,11 @@ static void *run_client(void *userdata) {
         int r;
 
         r = proxy_new(&p, c->fd, c->fd, arg_address);
+        c->fd = -1;
+
         if (r < 0)
                 goto exit;
 
-        c->fd = -1;
-
         /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
         r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
         if (r >= (ssize_t)sizeof(comm))
@@ -116,13 +120,12 @@ static int loop_clients(int accept_fd, uid_t bus_uid) {
         int r;
 
         r = pthread_attr_init(&attr);
-        if (r < 0) {
-                return log_error_errno(errno, "Cannot initialize pthread attributes: %m");
-        }
+        if (r != 0)
+                return log_error_errno(r, "Cannot initialize pthread attributes: %m");
 
         r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-        if (r < 0) {
-                r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
+        if (r != 0) {
+                r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m");
                 goto finish;
         }
 
@@ -156,8 +159,8 @@ static int loop_clients(int accept_fd, uid_t bus_uid) {
                 c->bus_uid = bus_uid;
 
                 r = pthread_create(&tid, &attr, run_client, c);
-                if (r < 0) {
-                        log_error("Cannot spawn thread: %m");
+                if (r != 0) {
+                        log_warning_errno(r, "Cannot spawn thread, ignoring: %m");
                         client_context_free(c);
                         continue;
                 }
index 9a3b451c56a4f6059bcf507c4590bc6229247dd2..f0834e95257dd5c87b5c7bddb9d1d55fdc31a1ab 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "xml.h"
-#include "fileio.h"
-#include "strv.h"
-#include "set.h"
-#include "conf-files.h"
+#include "sd-login.h"
+
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-xml-policy.h"
-#include "sd-login.h"
+#include "conf-files.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "locale-util.h"
+#include "set.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "xml.h"
 
 static void policy_item_free(PolicyItem *i) {
         assert(i);
@@ -1186,14 +1192,14 @@ int shared_policy_new(SharedPolicy **out) {
                 return log_oom();
 
         r = pthread_mutex_init(&sp->lock, NULL);
-        if (r < 0) {
-                log_error_errno(r, "Cannot initialize shared policy mutex: %m");
+        if (r != 0) {
+                r = log_error_errno(r, "Cannot initialize shared policy mutex: %m");
                 goto exit_free;
         }
 
         r = pthread_rwlock_init(&sp->rwlock, NULL);
-        if (r < 0) {
-                log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
+        if (r != 0) {
+                r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
                 goto exit_mutex;
         }
 
index fa4aee691a53b5d8fafa1ebb40b42ee14e17cfb7..2e8bd83efde9a8ba6c7cece46980b45c01079148 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
 #include <stddef.h>
+#include <string.h>
 
-#include "util.h"
 #include "sd-bus.h"
+
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "strv.h"
-#include "set.h"
 #include "driver.h"
+#include "env-util.h"
 #include "proxy.h"
+#include "set.h"
+#include "strv.h"
 #include "synthesize.h"
-#include "env-util.h"
+#include "util.h"
 
 static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
index 88800f5e7f28e83237533d4024565dc9e1aa5e9d..db399b24f26d41d7685c2210d4cba4e3dbe949c8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <string.h>
 #include <errno.h>
 #include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
-#include "log.h"
-#include "util.h"
-#include "sd-daemon.h"
 #include "sd-bus.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "bus-control.h"
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "strv.h"
-#include "bus-control.h"
-#include "set.h"
 #include "bus-xml-policy.h"
 #include "driver.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "log.h"
 #include "proxy.h"
+#include "set.h"
+#include "strv.h"
 #include "synthesize.h"
-#include "formats-util.h"
+#include "user-util.h"
+#include "util.h"
 
 static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
         _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
@@ -100,18 +104,24 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha
         return 0;
 }
 
-static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
-        _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
+static int proxy_create_local(Proxy *p, bool negotiate_fds) {
         sd_id128_t server_id;
+        sd_bus *b;
         int r;
 
         r = sd_bus_new(&b);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate bus: %m");
 
-        r = sd_bus_set_fd(b, in_fd, out_fd);
-        if (r < 0)
+        r = sd_bus_set_fd(b, p->local_in, p->local_out);
+        if (r < 0) {
+                sd_bus_unref(b);
                 return log_error_errno(r, "Failed to set fds: %m");
+        }
+
+        /* The fds are now owned by the bus, and we indicate that by
+         * storing the bus object in the proxy object. */
+        p->local_bus = b;
 
         r = sd_bus_get_bus_id(p->destination_bus, &server_id);
         if (r < 0)
@@ -139,8 +149,6 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd
         if (r < 0)
                 return log_error_errno(r, "Failed to start bus client: %m");
 
-        p->local_bus = b;
-        b = NULL;
         return 0;
 }
 
@@ -224,9 +232,17 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
         bool is_unix;
         int r;
 
+        /* This takes possession/destroys the file descriptors passed
+         * in even on failure. The caller should hence forget about
+         * the fds in all cases after calling this function and not
+         * close them. */
+
         p = new0(Proxy, 1);
-        if (!p)
+        if (!p) {
+                safe_close(in_fd);
+                safe_close(out_fd);
                 return log_oom();
+        }
 
         p->local_in = in_fd;
         p->local_out = out_fd;
@@ -247,7 +263,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
         if (r < 0)
                 return r;
 
-        r = proxy_create_local(p, in_fd, out_fd, is_unix);
+        r = proxy_create_local(p, is_unix);
         if (r < 0)
                 return r;
 
@@ -257,6 +273,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
 
         *out = p;
         p = NULL;
+
         return 0;
 }
 
@@ -273,7 +290,14 @@ Proxy *proxy_free(Proxy *p) {
                 free(activation);
         }
 
-        sd_bus_flush_close_unref(p->local_bus);
+        if (p->local_bus)
+                sd_bus_flush_close_unref(p->local_bus);
+        else {
+                safe_close(p->local_in);
+                if (p->local_out != p->local_in)
+                        safe_close(p->local_out);
+        }
+
         sd_bus_flush_close_unref(p->destination_bus);
         set_free_free(p->owned_names);
         free(p);
index 6aac650ac93a8e469e3cadfc97f51d34b756a99b..7b2e5d422fe017f58b921af11b53d1ea32c66b4c 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "bus-xml-policy.h"
 
 typedef struct Proxy Proxy;
index 168fc9ead03a3b72dcf90cfb7390df4998164fb0..6e478842093f1aaeaf691cc02160a849432416c6 100644 (file)
@@ -30,6 +30,7 @@
 #include "sd-daemon.h"
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-util.h"
 #include "def.h"
@@ -37,6 +38,7 @@
 #include "log.h"
 #include "proxy.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
 
 static char *arg_address = NULL;
index 15d99103f6dc0aeaff2731ed339ccd524792eb3a..7f1f9dc28d68309ae3093b0a9abd213f3b1220fe 100644 (file)
 
 #include <stddef.h>
 
-#include "util.h"
 #include "sd-bus.h"
+
 #include "bus-internal.h"
+#include "bus-match.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "bus-match.h"
 #include "synthesize.h"
+#include "util.h"
 
 int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
         int r;
index b596daddf21ea717ade4f4ced0b18ca79cc7d389..ddfe2fd2663ab8ce8668c632404fa9adb9ebae7c 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "proxy.h"
 
 int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
index d19d0e1b606ca2650ce0a3491b2d30d0fac1f453..1f465edd9178ec566abb43b0fe04b330c31df916 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <errno.h>
 #include <stddef.h>
+#include <unistd.h>
 
-#include "log.h"
-#include "util.h"
 #include "sd-bus.h"
-#include "strv.h"
+
+#include "alloc-util.h"
 #include "bus-xml-policy.h"
+#include "log.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 static int test_policy_load(Policy *p, const char *name) {
         _cleanup_free_ char *path = NULL;
index 41c539a1bc5055b214f00ba88e57d3eed3eee835..22efc58ac9991c0fe660ede2ceefdb7768be7017 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
@@ -164,8 +165,10 @@ static int get_cgroup_root(char **ret) {
 }
 
 static void show_cg_info(const char *controller, const char *path) {
-        if (cg_unified() <= 0)
+
+        if (cg_unified() <= 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
                 printf("Controller %s; ", controller);
+
         printf("Control group %s:\n", isempty(path) ? "/" : path);
         fflush(stdout);
 }
@@ -269,6 +272,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);
                 }
         }
index b79519dd09726fd19ae1445e77b9d5003077b7cc..e48234f07562d568217d53213c5f80ffbdd8b24f 100644 (file)
@@ -22,8 +22,9 @@
 #include <stdlib.h>
 
 #include "sd-bus.h"
-#include "log.h"
+
 #include "bus-util.h"
+#include "log.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
index ad9cd2532f990767380d4361a5aa6f46ff009c00..eea8aea76bc248f3968e67d7f928e6193e585b52 100644 (file)
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "cgroup-util.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "hashmap.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "terminal-util.h"
index 5a18e263a85e80fde448fe4b6ce34a5d63869a73..3ae46d8cfb8d3cf6bc37f12515a71f109c7f2c4a 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "log.h"
 #include "util.h"
+#include "fd-util.h"
 
 static bool initialized = false;
 static int audit_fd;
index e0535ec20177ed10a8ee37d0d89766d39b97c6a0..85b7b4e8426f59cc4a5db9513d327dcebc187c27 100644 (file)
 ***/
 
 #include <errno.h>
-#include <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
 #include <fcntl.h>
+#include <limits.h>
+#include <linux/auto_dev-ioctl.h>
+#include <linux/auto_fs4.h>
 #include <sys/epoll.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
+#include <unistd.h>
 
-#include "unit.h"
+#include "alloc-util.h"
+#include "async.h"
 #include "automount.h"
-#include "mount.h"
-#include "unit-name.h"
-#include "special.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "dbus-automount.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
 #include "label.h"
 #include "mkdir.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "dbus-automount.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "formats-util.h"
 #include "process-util.h"
-#include "async.h"
+#include "special.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
 
 static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
         [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
@@ -81,26 +89,11 @@ static void automount_init(Unit *u) {
         UNIT(a)->ignore_on_isolate = true;
 }
 
-static void repeat_unmount(const char *path) {
-        assert(path);
-
-        for (;;) {
-                /* If there are multiple mounts on a mount point, this
-                 * removes them all */
-
-                if (umount2(path, MNT_DETACH) >= 0)
-                        continue;
-
-                if (errno != EINVAL)
-                        log_error_errno(errno, "Failed to unmount: %m");
-
-                break;
-        }
-}
-
 static int automount_send_ready(Automount *a, Set *tokens, int status);
 
 static void unmount_autofs(Automount *a) {
+        int r;
+
         assert(a);
 
         if (a->pipe_fd < 0)
@@ -116,8 +109,11 @@ static void unmount_autofs(Automount *a) {
          * around */
         if (a->where &&
             (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
-             UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
-                repeat_unmount(a->where);
+             UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) {
+                r = repeat_unmount(a->where, MNT_DETACH);
+                if (r < 0)
+                        log_error_errno(r, "Failed to unmount: %m");
+        }
 }
 
 static void automount_done(Unit *u) {
@@ -137,13 +133,12 @@ static void automount_done(Unit *u) {
 
 static int automount_add_mount_links(Automount *a) {
         _cleanup_free_ char *parent = NULL;
-        int r;
 
         assert(a);
 
-        r = path_get_parent(a->where, &parent);
-        if (r < 0)
-                return r;
+        parent = dirname_malloc(a->where);
+        if (!parent)
+                return -ENOMEM;
 
         return unit_require_mounts_for(UNIT(a), parent);
 }
@@ -153,6 +148,9 @@ static int automount_add_default_dependencies(Automount *a) {
 
         assert(a);
 
+        if (!UNIT(a)->default_dependencies)
+                return 0;
+
         if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
                 return 0;
 
@@ -224,11 +222,9 @@ static int automount_load(Unit *u) {
                 if (r < 0)
                         return r;
 
-                if (UNIT(a)->default_dependencies) {
-                        r = automount_add_default_dependencies(a);
-                        if (r < 0)
-                                return r;
-                }
+                r = automount_add_default_dependencies(a);
+                if (r < 0)
+                        return r;
         }
 
         return automount_verify(a);
@@ -608,12 +604,16 @@ static void automount_enter_waiting(Automount *a) {
         return;
 
 fail:
+        log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
+
         safe_close_pair(p);
 
-        if (mounted)
-                repeat_unmount(a->where);
+        if (mounted) {
+                r = repeat_unmount(a->where, MNT_DETACH);
+                if (r < 0)
+                        log_error_errno(r, "Failed to unmount, ignoring: %m");
+        }
 
-        log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
 }
 
@@ -728,8 +728,7 @@ static void automount_enter_runnning(Automount *a) {
         if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
                 log_unit_info(UNIT(a), "Automount point already active?");
         else {
-                r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
-                                    JOB_REPLACE, true, &error, NULL);
+                r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL);
                 if (r < 0) {
                         log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                         goto fail;
@@ -974,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
                         break;
                 }
 
-                r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
+                r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL);
                 if (r < 0) {
                         log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
                         goto fail;
index 0c4b3e7c8b6464870725e3f41b0c71e6d8c5f930..d22a80c91faeb245adf622938ae5eee409e92bba 100644 (file)
 
 #include <stdlib.h>
 
-#include "kdbus.h"
+#include "alloc-util.h"
+#include "bus-endpoint.h"
 #include "bus-kernel.h"
 #include "bus-policy.h"
-#include "bus-endpoint.h"
+#include "kdbus.h"
 
 int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
 
index a6a8fcd4d328966e53805d1d61c6e15ddd7adaba..4907c268e8c03f8e3cb4d7aa42c431a9c8bcfcbd 100644 (file)
 
 #include <stdlib.h>
 
-#include "kdbus.h"
-#include "util.h"
+#include "alloc-util.h"
 #include "bus-kernel.h"
 #include "bus-policy.h"
+#include "kdbus.h"
+#include "string-table.h"
+#include "user-util.h"
+#include "util.h"
 
 int bus_kernel_translate_access(BusPolicyAccess access) {
         assert(access >= 0);
index 38becfc119526041a4c371fcc2c90e558cfd69b5..04fa12a4da9938ec047ed8a855d8c41d4da54507 100644 (file)
 
 #include <sys/mman.h>
 
-#include "special.h"
-#include "formats-util.h"
-#include "signal-util.h"
-#include "bus-kernel.h"
+#include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-kernel.h"
+#include "bus-policy.h"
 #include "bus-util.h"
+#include "busname.h"
+#include "dbus-busname.h"
+#include "fd-util.h"
+#include "formats-util.h"
 #include "kdbus.h"
-#include "bus-policy.h"
+#include "parse-util.h"
+#include "process-util.h"
 #include "service.h"
-#include "dbus-busname.h"
-#include "busname.h"
+#include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
 
 static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
         [BUSNAME_DEAD] = UNIT_INACTIVE,
@@ -358,10 +364,9 @@ static int busname_coldplug(Unit *u) {
         if (n->deserialized_state == n->state)
                 return 0;
 
-        if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
-
-                if (n->control_pid <= 0)
-                        return -EBADMSG;
+        if (n->control_pid > 0 &&
+            pid_is_unwaited(n->control_pid) &&
+            IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
 
                 r = unit_watch_pid(UNIT(n), n->control_pid);
                 if (r < 0)
@@ -585,7 +590,13 @@ static void busname_enter_running(BusName *n) {
                 }
 
         if (!pending) {
-                r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
+                if (!UNIT_ISSET(n->service)) {
+                        log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
+                        r = -ENOENT;
+                        goto fail;
+                }
+
+                r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL);
                 if (r < 0)
                         goto fail;
         }
index 1bc32905963947d4f981632c88c71cec73c0ebb8..46f7b6f097ab31bb688a6f984f6f58b0f1bbc4a2 100644 (file)
@@ -24,6 +24,8 @@
 typedef struct BusName BusName;
 typedef struct BusNamePolicy BusNamePolicy;
 
+#include "unit.h"
+
 typedef enum BusNameResult {
         BUSNAME_SUCCESS,
         BUSNAME_FAILURE_RESOURCES,
index 0c790c33da4fa229f07cb3bae409ce1b4991e0a9..bed01fde211cee56161eb9e0053571d1ba3ff463 100644 (file)
 #include <fcntl.h>
 #include <fnmatch.h>
 
+#include "alloc-util.h"
 #include "cgroup-util.h"
+#include "cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "special.h"
-
-#include "cgroup.h"
+#include "string-table.h"
+#include "string-util.h"
 
 #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
 
@@ -1203,7 +1209,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
                         continue;
 
                 /* Ignore processes that aren't our kids */
-                if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+                if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
                         continue;
 
                 if (pid != 0)
index 5162ce34cb75f09bbbe9d5b019d3169ea197f3ac..45f2c2ffd64411798a564ad9790c12fd434273ee 100644 (file)
@@ -20,8 +20,9 @@
 ***/
 
 #include "automount.h"
-#include "dbus-automount.h"
 #include "bus-util.h"
+#include "string-util.h"
+#include "dbus-automount.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
 
index b1ceb05b1a2c1c5588efcbea352e20c961df62c3..05ac89c3c0344feee7e162746331c4db32190897 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
+#include "bus-util.h"
 #include "busname.h"
+#include "string-util.h"
+#include "unit.h"
 #include "dbus-busname.h"
-#include "bus-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
 
index f334dc928dd91e7565f27a92b8543dba5546f86d..3fd295baa918dcad83079ec2e0c6416683ca2a7c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "bus-util.h"
-#include "path-util.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
 #include "dbus-cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
 
@@ -421,7 +424,9 @@ int bus_cgroup_set_property(
                                                 fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
                         }
 
-                        fflush(f);
+                        r = fflush_and_check(f);
+                        if (r < 0)
+                                return r;
                         unit_write_drop_in_private(u, mode, name, buf);
                 }
 
@@ -495,7 +500,9 @@ int bus_cgroup_set_property(
                         LIST_FOREACH(device_weights, a, c->blockio_device_weights)
                                 fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
 
-                        fflush(f);
+                        r = fflush_and_check(f);
+                        if (r < 0)
+                                return r;
                         unit_write_drop_in_private(u, mode, name, buf);
                 }
 
@@ -640,7 +647,9 @@ int bus_cgroup_set_property(
                         LIST_FOREACH(device_allow, a, c->device_allow)
                                 fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
 
-                        fflush(f);
+                        r = fflush_and_check(f);
+                        if (r < 0)
+                                return r;
                         unit_write_drop_in_private(u, mode, name, buf);
                 }
 
index c2a3910f3d6466ccf13ffaf56ba58fe3b9a4eb7f..9dc187c066a25414cb2aed8beb210511beebf6d1 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "cgroup.h"
 
 extern const sd_bus_vtable bus_cgroup_vtable[];
index 030df555548fe17525ca006d0ff1e29082c7845a..093179c003f2612af8aff284e001862a83ada58e 100644 (file)
 #include <seccomp.h>
 #endif
 
+#include "af-list.h"
+#include "alloc-util.h"
 #include "bus-util.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "fileio.h"
-#include "execute.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "dbus-execute.h"
 #include "env-util.h"
-#include "af-list.h"
+#include "execute.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "ioprio.h"
+#include "missing.h"
 #include "namespace.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "dbus-execute.h"
-
+#include "process-util.h"
+#include "rlimit-util.h"
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
+#include "strv.h"
+#include "syslog-util.h"
+#include "utf8.h"
 
 BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
 
@@ -83,45 +89,6 @@ static int property_get_environment_files(
         return sd_bus_message_close_container(reply);
 }
 
-static int property_get_rlimit(
-                sd_bus *bus,
-                const char *path,
-                const char *interface,
-                const char *property,
-                sd_bus_message *reply,
-                void *userdata,
-                sd_bus_error *error) {
-
-        struct rlimit *rl;
-        uint64_t u;
-        rlim_t x;
-
-        assert(bus);
-        assert(reply);
-        assert(userdata);
-
-        rl = *(struct rlimit**) userdata;
-        if (rl)
-                x = rl->rlim_max;
-        else {
-                struct rlimit buf = {};
-                int z;
-
-                z = rlimit_from_string(property);
-                assert(z >= 0);
-
-                getrlimit(z, &buf);
-                x = buf.rlim_max;
-        }
-
-        /* rlim_t might have different sizes, let's map
-         * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
-         * all archs */
-        u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
-
-        return sd_bus_message_append(reply, "t", u);
-}
-
 static int property_get_oom_score_adjust(
                 sd_bus *bus,
                 const char *path,
@@ -146,7 +113,7 @@ static int property_get_oom_score_adjust(
 
                 n = 0;
                 if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
-                        safe_atoi(t, &n);
+                        safe_atoi32(t, &n);
         }
 
         return sd_bus_message_append(reply, "i", n);
@@ -622,27 +589,64 @@ static int property_get_working_directory(
         return sd_bus_message_append(reply, "s", wd);
 }
 
+static int property_get_syslog_level(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        ExecContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
+}
+
+static int property_get_syslog_facility(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        ExecContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
+}
+
 const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -664,6 +668,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -881,6 +887,38 @@ int bus_exec_context_set_transient_property(
                         unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
                 }
 
+                return 1;
+        } else if (streq(name, "SyslogLevel")) {
+                int level;
+
+                r = sd_bus_message_read(message, "i", &level);
+                if (r < 0)
+                        return r;
+
+                if (!log_level_is_valid(level))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
+
+                if (mode != UNIT_CHECK) {
+                        c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
+                        unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
+                }
+
+                return 1;
+        } else if (streq(name, "SyslogFacility")) {
+                int facility;
+
+                r = sd_bus_message_read(message, "i", &facility);
+                if (r < 0)
+                        return r;
+
+                if (!log_facility_unshifted_is_valid(facility))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
+
+                if (mode != UNIT_CHECK) {
+                        c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
+                        unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
+                }
+
                 return 1;
         } else if (streq(name, "Nice")) {
                 int n;
@@ -1124,18 +1162,299 @@ int bus_exec_context_set_transient_property(
                         _cleanup_free_ char *joined = NULL;
                         char **e;
 
-                        e = strv_env_merge(2, c->environment, l);
-                        if (!e)
-                                return -ENOMEM;
+                        if (strv_length(l) == 0) {
+                                c->environment = strv_free(c->environment);
+                                unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
+                        } else {
+                                e = strv_env_merge(2, c->environment, l);
+                                if (!e)
+                                        return -ENOMEM;
 
-                        strv_free(c->environment);
-                        c->environment = e;
+                                strv_free(c->environment);
+                                c->environment = e;
 
-                        joined = strv_join_quoted(c->environment);
-                        if (!joined)
-                                return -ENOMEM;
+                                joined = strv_join_quoted(c->environment);
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+                        }
+                }
+
+                return 1;
+
+        } else if (streq(name, "TimerSlackNSec")) {
+
+                nsec_t n;
+
+                r = sd_bus_message_read(message, "t", &n);
+                if (r < 0)
+                        return r;
+
+                if (mode != UNIT_CHECK) {
+                        c->timer_slack_nsec = n;
+                        unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+                }
+
+                return 1;
+
+        } else if (streq(name, "OOMScoreAdjust")) {
+                int oa;
+
+                r = sd_bus_message_read(message, "i", &oa);
+                if (r < 0)
+                        return r;
+
+                if (!oom_score_adjust_is_valid(oa))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
+
+                if (mode != UNIT_CHECK) {
+                        c->oom_score_adjust = oa;
+                        c->oom_score_adjust_set = true;
+                        unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa);
+                }
+
+                return 1;
+
+        } else if (streq(name, "EnvironmentFiles")) {
+
+                _cleanup_free_ char *joined = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
+                _cleanup_free_ char **l = NULL;
+                size_t size = 0;
+                char **i;
+
+                r = sd_bus_message_enter_container(message, 'a', "(sb)");
+                if (r < 0)
+                        return r;
+
+                f = open_memstream(&joined, &size);
+                if (!f)
+                        return -ENOMEM;
+
+                STRV_FOREACH(i, c->environment_files)
+                        fprintf(f, "EnvironmentFile=%s\n", *i);
+
+                while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
+                        const char *path;
+                        int b;
+
+                        r = sd_bus_message_read(message, "sb", &path, &b);
+                        if (r < 0)
+                                return r;
 
-                        unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+                        r = sd_bus_message_exit_container(message);
+                        if (r < 0)
+                                return r;
+
+                        if (!isempty(path) && !path_is_absolute(path))
+                                return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
+
+                        if (mode != UNIT_CHECK) {
+                                char *buf = NULL;
+
+                                buf = strjoin(b ? "-" : "", path, NULL);
+                                if (!buf)
+                                        return -ENOMEM;
+
+                                fprintf(f, "EnvironmentFile=%s\n", buf);
+
+                                r = strv_consume(&l, buf);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                r = fflush_and_check(f);
+                if (r < 0)
+                        return r;
+
+                if (mode != UNIT_CHECK) {
+                        if (strv_isempty(l)) {
+                                c->environment_files = strv_free(c->environment_files);
+                                unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n");
+                        } else {
+                                r = strv_extend_strv(&c->environment_files, l, true);
+                                if (r < 0)
+                                        return r;
+
+                                unit_write_drop_in_private(u, mode, name, joined);
+                        }
+                }
+
+                return 1;
+
+        } else if (streq(name, "PassEnvironment")) {
+
+                _cleanup_strv_free_ char **l = NULL;
+
+                r = sd_bus_message_read_strv(message, &l);
+                if (r < 0)
+                        return r;
+
+                if (!strv_env_name_is_valid(l))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block.");
+
+                if (mode != UNIT_CHECK) {
+                        if (strv_isempty(l)) {
+                                c->pass_environment = strv_free(c->pass_environment);
+                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n");
+                        } else {
+                                _cleanup_free_ char *joined = NULL;
+
+                                r = strv_extend_strv(&c->pass_environment, l, true);
+                                if (r < 0)
+                                        return r;
+
+                                joined = strv_join_quoted(c->pass_environment);
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined);
+                        }
+                }
+
+                return 1;
+
+        } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+
+                _cleanup_strv_free_ char **l = NULL;
+                char ***dirs;
+                char **p;
+
+                r = sd_bus_message_read_strv(message, &l);
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(p, l) {
+                        int offset;
+                        if (!utf8_is_valid(*p))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+
+                        offset = **p == '-';
+                        if (!path_is_absolute(*p + offset))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+                }
+
+                if (mode != UNIT_CHECK) {
+                        _cleanup_free_ char *joined = NULL;
+
+                        if (streq(name, "ReadWriteDirectories"))
+                                dirs = &c->read_write_dirs;
+                        else if (streq(name, "ReadOnlyDirectories"))
+                                dirs = &c->read_only_dirs;
+                        else if (streq(name, "InaccessibleDirectories"))
+                                dirs = &c->inaccessible_dirs;
+
+                        if (strv_length(l) == 0) {
+                                *dirs = strv_free(*dirs);
+                                unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+                        } else {
+                                r = strv_extend_strv(dirs, l, true);
+
+                                if (r < 0)
+                                        return -ENOMEM;
+
+                                joined = strv_join_quoted(*dirs);
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+                        }
+
+                }
+
+                return 1;
+
+        } else if (streq(name, "ProtectSystem")) {
+                const char *s;
+                ProtectSystem ps;
+
+                r = sd_bus_message_read(message, "s", &s);
+                if (r < 0)
+                        return r;
+
+                r = parse_boolean(s);
+                if (r > 0)
+                        ps = PROTECT_SYSTEM_YES;
+                else if (r == 0)
+                        ps = PROTECT_SYSTEM_NO;
+                else {
+                        ps = protect_system_from_string(s);
+                        if (ps < 0)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value");
+                }
+
+                if (mode != UNIT_CHECK) {
+                        c->protect_system = ps;
+                        unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+                }
+
+                return 1;
+
+        } else if (streq(name, "ProtectHome")) {
+                const char *s;
+                ProtectHome ph;
+
+                r = sd_bus_message_read(message, "s", &s);
+                if (r < 0)
+                        return r;
+
+                r = parse_boolean(s);
+                if (r > 0)
+                        ph = PROTECT_HOME_YES;
+                else if (r == 0)
+                        ph = PROTECT_HOME_NO;
+                else {
+                        ph = protect_home_from_string(s);
+                        if (ph < 0)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value");
+                }
+
+                if (mode != UNIT_CHECK) {
+                        c->protect_home = ph;
+                        unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+                }
+
+                return 1;
+
+        } else if (streq(name, "RuntimeDirectory")) {
+                _cleanup_strv_free_ char **l = NULL;
+                char **p;
+
+                r = sd_bus_message_read_strv(message, &l);
+                if (r < 0)
+                        return r;
+
+                STRV_FOREACH(p, l) {
+                        if (!filename_is_valid(*p))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
+                }
+
+                if (mode != UNIT_CHECK) {
+                        _cleanup_free_ char *joined = NULL;
+
+                        if (strv_isempty(l)) {
+                                c->runtime_directory = strv_free(c->runtime_directory);
+                                unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+                        } else {
+                                r = strv_extend_strv(&c->runtime_directory, l, true);
+
+                                if (r < 0)
+                                        return -ENOMEM;
+
+                                joined = strv_join_quoted(c->runtime_directory);
+                                if (!joined)
+                                        return -ENOMEM;
+
+                                unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+                        }
                 }
 
                 return 1;
index e4c2d5ddf678e158f8579ae1c547e502e5ef948b..c44517ea2271a104d75c209c579f33504fb8aefd 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "execute.h"
 
 #define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags)                   \
index cd6b909426cdcff94e51f4d90169f75e81fefa70..8c30d6625000a148c8f743d58434591af5f704f4 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "log.h"
 #include "sd-bus.h"
-#include "selinux-access.h"
-#include "job.h"
+
+#include "alloc-util.h"
 #include "dbus-job.h"
 #include "dbus.h"
+#include "job.h"
+#include "log.h"
+#include "selinux-access.h"
+#include "string-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
index fb5f1b513ebcfb88e9246710ba5318e0c2398a97..0f2fbe2ee2930d78466018cb84a431276deea49a 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "job.h"
 
 extern const sd_bus_vtable bus_job_vtable[];
index 7c15f3a90b60db16802ce5f1344703485a5f8844..794c402048adf3c663cad1747e717908b40d48c0 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "unit.h"
 #include "kill.h"
 
index 3f4f60d6e27ace07b1a79bd038892c1fc591137e..d3bcc795ae8801c4b3379c03b7ab222e0b43f6fc 100644 (file)
 ***/
 
 #include <errno.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 
-#include "log.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "architecture.h"
 #include "build.h"
-#include "install.h"
-#include "selinux-access.h"
-#include "watchdog.h"
+#include "bus-common-errors.h"
 #include "clock-util.h"
-#include "path-util.h"
-#include "virt.h"
-#include "architecture.h"
-#include "env-util.h"
-#include "dbus.h"
+#include "dbus-execute.h"
 #include "dbus-job.h"
 #include "dbus-manager.h"
 #include "dbus-unit.h"
-#include "dbus-snapshot.h"
-#include "dbus-execute.h"
-#include "bus-common-errors.h"
+#include "dbus.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "install.h"
+#include "log.h"
+#include "path-util.h"
+#include "selinux-access.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "virt.h"
+#include "watchdog.h"
 
 static int property_get_version(
                 sd_bus *bus,
@@ -346,6 +352,21 @@ static int property_set_runtime_watchdog(
         return watchdog_set_timeout(t);
 }
 
+static int property_get_timer_slack_nsec(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+}
+
 static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
@@ -1079,66 +1100,8 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er
         return sd_bus_reply_method_return(message, "s", dump);
 }
 
-static int method_create_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ char *path = NULL;
-        Manager *m = userdata;
-        const char *name;
-        int cleanup;
-        Snapshot *s = NULL;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = mac_selinux_access_check(message, "start", error);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(message, "sb", &name, &cleanup);
-        if (r < 0)
-                return r;
-
-        if (isempty(name))
-                name = NULL;
-
-        r = bus_verify_manage_units_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 = snapshot_create(m, name, cleanup, error, &s);
-        if (r < 0)
-                return r;
-
-        path = unit_dbus_path(UNIT(s));
-        if (!path)
-                return -ENOMEM;
-
-        return sd_bus_reply_method_return(message, "o", path);
-}
-
-static int method_remove_snapshot(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;
-
-        u = manager_get_unit(m, name);
-        if (!u)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
-
-        if (u->type != UNIT_SNAPSHOT)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
-
-        return bus_snapshot_method_remove(message, u, error);
+static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
 }
 
 static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1558,9 +1521,9 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
 
         scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
 
-        state = unit_file_get_state(scope, NULL, name);
-        if (state < 0)
-                return state;
+        r = unit_file_get_state(scope, NULL, name, &state);
+        if (r < 0)
+                return r;
 
         return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
 }
@@ -1688,6 +1651,8 @@ static int method_enable_unit_files_generic(
         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");
         if (r < 0)
                 return r;
 
@@ -1922,6 +1887,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
         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");
         if (r < 0)
                 return r;
 
@@ -1977,6 +1944,23 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
 
         SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2003,8 +1987,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
index 24813c6d20a77947db6ba0be45171ac3c2b6d516..90a6d3707325ba216bf00683f8599a1e9a257e91 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
-#include "mount.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
 #include "dbus-execute.h"
 #include "dbus-kill.h"
-#include "dbus-cgroup.h"
+#include "mount.h"
+#include "string-util.h"
+#include "unit.h"
 #include "dbus-mount.h"
-#include "bus-util.h"
 
 static int property_get_what(
                 sd_bus *bus,
index f7004d252f02f311f0ff058252decb0702ae0ccb..dd0bf51bb0afcc05f99f9d62e5b3fd9b55fe6369 100644 (file)
@@ -22,6 +22,7 @@
 ***/
 
 #include "sd-bus.h"
+
 #include "unit.h"
 
 extern const sd_bus_vtable bus_mount_vtable[];
index 683561999bd646aa8d3ee400bb926410f80aefac..9e32b5fb06d9c8a60d5d7d498595387df5f968db 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
+#include "bus-util.h"
 #include "path.h"
+#include "string-util.h"
+#include "unit.h"
 #include "dbus-path.h"
-#include "bus-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult);
 
index f8fb373bf01e8a45be62c08729cc8582cb789ac1..16375b2311b755f8585c7d33941ccf117c990d54 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "selinux-access.h"
-#include "unit.h"
-#include "scope.h"
-#include "dbus.h"
-#include "bus-util.h"
-#include "bus-internal.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
-#include "dbus-unit.h"
+#include "bus-internal.h"
+#include "bus-util.h"
 #include "dbus-cgroup.h"
 #include "dbus-kill.h"
 #include "dbus-scope.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "scope.h"
+#include "selinux-access.h"
+#include "unit.h"
 
 static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Scope *s = userdata;
index b636f8ba6a467e1383736eede865ea955b2cba2a..24f611a593e8fd465913565feb1c15e72c2e02f8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "async.h"
-#include "strv.h"
-#include "path-util.h"
-#include "unit.h"
-#include "service.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
 #include "dbus-execute.h"
 #include "dbus-kill.h"
-#include "dbus-cgroup.h"
 #include "dbus-service.h"
-#include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
+#include "service.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
@@ -59,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
         SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -243,7 +248,9 @@ static int bus_service_set_transient_property(
                                         a);
                         }
 
-                        fflush(f);
+                        r = fflush_and_check(f);
+                        if (r < 0)
+                                return r;
                         unit_write_drop_in_private(UNIT(s), mode, name, buf);
                 }
 
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
deleted file mode 100644 (file)
index cfe44c9..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 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 "selinux-access.h"
-#include "unit.h"
-#include "dbus.h"
-#include "snapshot.h"
-#include "dbus-snapshot.h"
-
-int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Snapshot *s = userdata;
-        int r;
-
-        assert(message);
-        assert(s);
-
-        r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
-        if (r < 0)
-                return r;
-
-        r = bus_verify_manage_units_async(UNIT(s)->manager, 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 */
-
-        snapshot_remove(s);
-
-        return sd_bus_reply_method_return(message, NULL);
-}
-
-const sd_bus_vtable bus_snapshot_vtable[] = {
-        SD_BUS_VTABLE_START(0),
-        SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_VTABLE_END
-};
index 7444649f8ba1022b581921b145f4a30cb63c0ed0..be5ef261a654283335f3192df513997cf138fb9a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
-#include "socket.h"
-#include "dbus-execute.h"
+#include "alloc-util.h"
+#include "bus-util.h"
 #include "dbus-cgroup.h"
+#include "dbus-execute.h"
 #include "dbus-socket.h"
-#include "bus-util.h"
+#include "socket.h"
+#include "string-util.h"
+#include "unit.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
index 00933713060375257ea63b723ea55d94d221ac5d..603ca95fd9fe02de096eced7af1aee7f00b1e603 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
-#include "swap.h"
-#include "dbus-execute.h"
+#include "bus-util.h"
 #include "dbus-cgroup.h"
+#include "dbus-execute.h"
+#include "string-util.h"
+#include "swap.h"
+#include "unit.h"
 #include "dbus-swap.h"
-#include "bus-util.h"
 
 static int property_get_priority(
                 sd_bus *bus,
index 4c4297bc9e68a63f2eeb1645f7219e2dbd2e4246..6be9c9f7084d0c4c976d14950070962e629f4bda 100644 (file)
@@ -21,5 +21,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "sd-bus.h"
 
 extern const sd_bus_vtable bus_target_vtable[];
index 8ea2cf84a493906b932f2461e3c03acc1da4633a..a8a280d961202c684d87615652213241d5dbb660 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
-#include "timer.h"
-#include "dbus-timer.h"
+#include "alloc-util.h"
 #include "bus-util.h"
+#include "dbus-timer.h"
 #include "strv.h"
+#include "timer.h"
+#include "unit.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
 
index cd88a87340783211f144d0627e6ff19698dad8bd..d9b7382c82b082b1b8913079303a7260477d5072 100644 (file)
 ***/
 
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "cgroup-util.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "locale-util.h"
 #include "log.h"
 #include "selinux-access.h"
-#include "cgroup-util.h"
-#include "strv.h"
-#include "bus-common-errors.h"
 #include "special.h"
-#include "dbus.h"
-#include "dbus-unit.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
@@ -113,6 +118,22 @@ static int property_get_dependencies(
         return sd_bus_message_close_container(reply);
 }
 
+static int property_get_obsolete_dependencies(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        assert(bus);
+        assert(reply);
+
+        /* For dependency types we don't support anymore always return an empty array */
+        return sd_bus_message_append(reply, "as", 0);
+}
+
 static int property_get_description(
                 sd_bus *bus,
                 const char *path,
@@ -616,16 +637,12 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
         SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -639,6 +656,10 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+        SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
         SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -666,7 +687,6 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
-        SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -679,7 +699,7 @@ 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("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0),
+        SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0),
 
         SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -984,10 +1004,11 @@ int bus_unit_queue_job(
 
         if ((type == JOB_START && u->refuse_manual_start) ||
             (type == JOB_STOP && u->refuse_manual_stop) ||
-            ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
+            ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+            (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
 
-        r = manager_add_job(u->manager, type, u, mode, true, error, &j);
+        r = manager_add_job(u->manager, type, u, mode, error, &j);
         if (r < 0)
                 return r;
 
@@ -1103,9 +1124,15 @@ static int bus_unit_set_transient_property(
                 UnitDependency d;
                 const char *other;
 
-                d = unit_dependency_from_string(name);
-                if (d < 0)
-                        return -EINVAL;
+                if (streq(name, "RequiresOverridable"))
+                        d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */
+                else if (streq(name, "RequisiteOverridable"))
+                        d = UNIT_REQUISITE; /* same here */
+                else {
+                        d = unit_dependency_from_string(name);
+                        if (d < 0)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name);
+                }
 
                 r = sd_bus_message_enter_container(message, 'a', "s");
                 if (r < 0)
index 2d6a1ff8360fa1f98a1be7703282c2153ca2137d..7932130036aa8148e0351ed0806b3e1955840ef6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/epoll.h>
 #include <errno.h>
+#include <sys/epoll.h>
 #include <unistd.h>
 
 #include "sd-bus.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
 #include "dbus-execute.h"
+#include "dbus-job.h"
 #include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "special.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
 #include "dbus.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "strxcpyx.h"
-#include "bus-internal.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+#include "mkdir.h"
 #include "selinux-access.h"
+#include "special.h"
+#include "string-util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+#include "user-util.h"
 
 #define CONNECTIONS_MAX 4096
 
@@ -172,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
                 goto failed;
         }
 
-        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
+        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
         if (r < 0)
                 goto failed;
 
@@ -777,9 +782,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
                 return r;
 
         HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
-                r = unit_install_bus_match(bus, u, name);
+                r = unit_install_bus_match(u, bus, name);
                 if (r < 0)
-                        log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+                        log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
         }
 
         r = sd_bus_add_match(
index a819ab8d4e121a03866e64466f58b67755d77c42..bcd4d1146bec44bb9a44c9ebf4ad75c26e0dba63 100644 (file)
 
 #include <errno.h>
 #include <sys/epoll.h>
-#include <libudev.h>
 
-#include "log.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
 #include "dbus-device.h"
+#include "device.h"
+#include "log.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "swap.h"
 #include "udev-util.h"
+#include "unit-name.h"
 #include "unit.h"
-#include "swap.h"
-#include "device.h"
 
 static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
         [DEVICE_DEAD] = UNIT_INACTIVE,
@@ -112,7 +117,6 @@ static void device_init(Unit *u) {
         u->job_timeout = u->manager->default_timeout_start_usec;
 
         u->ignore_on_isolate = true;
-        u->ignore_on_snapshot = true;
 }
 
 static void device_done(Unit *u) {
@@ -597,7 +601,7 @@ static void device_shutdown(Manager *m) {
         m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
 }
 
-static int device_enumerate(Manager *m) {
+static void device_enumerate(Manager *m) {
         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
         struct udev_list_entry *item = NULL, *first = NULL;
         int r;
@@ -607,7 +611,7 @@ static int device_enumerate(Manager *m) {
         if (!m->udev_monitor) {
                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
                 if (!m->udev_monitor) {
-                        r = -ENOMEM;
+                        log_oom();
                         goto fail;
                 }
 
@@ -617,37 +621,49 @@ static int device_enumerate(Manager *m) {
                 (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
 
                 r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to add udev tag match: %m");
                         goto fail;
+                }
 
                 r = udev_monitor_enable_receiving(m->udev_monitor);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to enable udev event reception: %m");
                         goto fail;
+                }
 
                 r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to watch udev file descriptor: %m");
                         goto fail;
+                }
 
                 (void) sd_event_source_set_description(m->udev_event_source, "device");
         }
 
         e = udev_enumerate_new(m->udev);
         if (!e) {
-                r = -ENOMEM;
+                log_oom();
                 goto fail;
         }
 
         r = udev_enumerate_add_match_tag(e, "systemd");
-        if (r < 0)
+        if (r < 0) {
+                log_error_errno(r, "Failed to create udev tag enumeration: %m");
                 goto fail;
+        }
 
         r = udev_enumerate_add_match_is_initialized(e);
-        if (r < 0)
+        if (r < 0) {
+                log_error_errno(r, "Failed to install initialization match into enumeration: %m");
                 goto fail;
+        }
 
         r = udev_enumerate_scan_devices(e);
-        if (r < 0)
+        if (r < 0) {
+                log_error_errno(r, "Failed to enumerate devices: %m");
                 goto fail;
+        }
 
         first = udev_enumerate_get_list_entry(e);
         udev_list_entry_foreach(item, first) {
@@ -670,13 +686,10 @@ static int device_enumerate(Manager *m) {
                 device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
         }
 
-        return 0;
+        return;
 
 fail:
-        log_error_errno(r, "Failed to enumerate devices: %m");
-
         device_shutdown(m);
-        return r;
 }
 
 static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
index d6217840c07cc8dbdd397777ea9cd7c6f922e966..07979bf8b30934aa6cb245d2fbf0f93d0f162051 100644 (file)
 #include "sd-messages.h"
 
 #include "af-list.h"
+#include "alloc-util.h"
+#ifdef HAVE_APPARMOR
+#include "apparmor-util.h"
+#endif
 #include "async.h"
 #include "barrier.h"
 #include "bus-endpoint.h"
 #include "cap-list.h"
-#include "capability.h"
+#include "capability-util.h"
 #include "def.h"
 #include "env-util.h"
 #include "errno-list.h"
+#include "execute.h"
 #include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
 #include "ioprio.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "namespace.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "rm-rf.h"
+#ifdef HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
 #include "securebits.h"
 #include "selinux-util.h"
 #include "signal-util.h"
 #include "smack-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
+#include "syslog-util.h"
 #include "terminal-util.h"
 #include "unit.h"
+#include "user-util.h"
 #include "util.h"
 #include "utmp-wtmp.h"
 
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-
-#include "execute.h"
-
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 #define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
 
@@ -1324,6 +1332,34 @@ static int build_environment(
         return 0;
 }
 
+static int build_pass_environment(const ExecContext *c, char ***ret) {
+        _cleanup_strv_free_ char **pass_env = NULL;
+        size_t n_env = 0, n_bufsize = 0;
+        char **i;
+
+        STRV_FOREACH(i, c->pass_environment) {
+                _cleanup_free_ char *x = NULL;
+                char *v;
+
+                v = getenv(*i);
+                if (!v)
+                        continue;
+                x = strjoin(*i, "=", v, NULL);
+                if (!x)
+                        return -ENOMEM;
+                if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
+                        return -ENOMEM;
+                pass_env[n_env++] = x;
+                pass_env[n_env] = NULL;
+                x = NULL;
+        }
+
+        *ret = pass_env;
+        pass_env = NULL;
+
+        return 0;
+}
+
 static bool exec_needs_mount_namespace(
                 const ExecContext *context,
                 const ExecParameters *params,
@@ -1404,7 +1440,7 @@ static int exec_child(
                 char **files_env,
                 int *exit_status) {
 
-        _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+        _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
         _cleanup_free_ char *mac_selinux_context_net = NULL;
         const char *username = NULL, *home = NULL, *shell = NULL, *wd;
         uid_t uid = UID_INVALID;
@@ -1920,9 +1956,16 @@ static int exec_child(
                 return r;
         }
 
-        final_env = strv_env_merge(5,
+        r = build_pass_environment(context, &pass_env);
+        if (r < 0) {
+                *exit_status = EXIT_MEMORY;
+                return r;
+        }
+
+        final_env = strv_env_merge(6,
                                    params->environment,
                                    our_env,
+                                   pass_env,
                                    context->environment,
                                    files_env,
                                    pam_env,
@@ -2080,6 +2123,7 @@ void exec_context_done(ExecContext *c) {
 
         c->environment = strv_free(c->environment);
         c->environment_files = strv_free(c->environment_files);
+        c->pass_environment = strv_free(c->pass_environment);
 
         for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
                 c->rlimit[l] = mfree(c->rlimit[l]);
@@ -2314,7 +2358,7 @@ static void strv_fprintf(FILE *f, char **l) {
 }
 
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char **e;
+        char **e, **d;
         unsigned i;
 
         assert(c);
@@ -2350,6 +2394,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         STRV_FOREACH(e, c->environment_files)
                 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
 
+        STRV_FOREACH(e, c->pass_environment)
+                fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
+
+        fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+
+        STRV_FOREACH(d, c->runtime_directory)
+                fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+
         if (c->nice_set)
                 fprintf(f,
                         "%sNice: %i\n",
index f8995a4203e355dcda7e4f149be069aacd6eba4a..1faff160cbea58d115938ba56ddf004872b85dea 100644 (file)
@@ -99,6 +99,7 @@ struct ExecRuntime {
 struct ExecContext {
         char **environment;
         char **environment_files;
+        char **pass_environment;
 
         struct rlimit *rlimit[_RLIMIT_MAX];
         char *working_directory, *root_directory;
index 3412accf3e6b4cd4cf6c85a7d58a375bfe246322..f67fb05af0b84bb73e636d0a6d280d52a86635ba 100644 (file)
 #include <sys/reboot.h>
 #include <linux/reboot.h>
 
-#include "bus-util.h"
 #include "bus-error.h"
-#include "special.h"
+#include "bus-util.h"
 #include "failure-action.h"
+#include "special.h"
+#include "string-table.h"
 #include "terminal-util.h"
 
 static void log_and_status(Manager *m, const char *message) {
@@ -41,8 +42,6 @@ int failure_action(
                 FailureAction action,
                 const char *reboot_arg) {
 
-        int r;
-
         assert(m);
         assert(action >= 0);
         assert(action < _FAILURE_ACTION_MAX);
@@ -61,18 +60,13 @@ int failure_action(
 
         switch (action) {
 
-        case FAILURE_ACTION_REBOOT: {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
+        case FAILURE_ACTION_REBOOT:
                 log_and_status(m, "Rebooting as result of failure.");
 
                 update_reboot_param_file(reboot_arg);
-                r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
-                if (r < 0)
-                        log_error("Failed to reboot: %s.", bus_error_message(&error, r));
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL);
 
                 break;
-        }
 
         case FAILURE_ACTION_REBOOT_FORCE:
                 log_and_status(m, "Forcibly rebooting as result of failure.");
@@ -95,17 +89,10 @@ int failure_action(
                 reboot(RB_AUTOBOOT);
                 break;
 
-        case FAILURE_ACTION_POWEROFF: {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
+        case FAILURE_ACTION_POWEROFF:
                 log_and_status(m, "Powering off as result of failure.");
-
-                r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL);
-                if (r < 0)
-                        log_error("Failed to poweroff: %s.", bus_error_message(&error, r));
-
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL);
                 break;
-        }
 
         case FAILURE_ACTION_POWEROFF_FORCE:
                 log_and_status(m, "Forcibly powering off as result of failure.");
index 932ddbf95a96147d28f2ef1c8023cf2695ad4210..3645f9c515eb67ee9e5f279498b0a3a60abc4999 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 
-#include "macro.h"
-#include "util.h"
-#include "log.h"
+#include "alloc-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "util.h"
 #include "hostname-setup.h"
 
 int hostname_setup(void) {
@@ -59,8 +61,9 @@ int hostname_setup(void) {
                 hn = "localhost";
         }
 
-        if (sethostname_idempotent(hn) < 0)
-                return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn);
+        r = sethostname_idempotent(hn);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
 
         log_info("Set hostname to <%s>.", hn);
         return 0;
index 42a3e9745920f30dda38475581039ea320bc7e0c..9572fa17d9cd61f3c53aacfd03ce4f0aca63d10c 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
+#include "fd-util.h"
+#include "fileio.h"
 #include "ima-setup.h"
-#include "util.h"
 #include "log.h"
+#include "util.h"
 
 #define IMA_SECFS_DIR "/sys/kernel/security/ima"
 #define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
index 558d8d2d52634c35e410fdd3e696ed836074b276..53e094721514ae9f660598d2a738e7d39a3718e5 100644 (file)
 
 #include "sd-id128.h"
 #include "sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "dbus-job.h"
-#include "special.h"
+
+#include "alloc-util.h"
 #include "async.h"
-#include "virt.h"
+#include "dbus-job.h"
 #include "dbus.h"
+#include "escape.h"
+#include "job.h"
+#include "log.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "set.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
 #include "terminal-util.h"
+#include "unit.h"
+#include "virt.h"
 
 Job* job_new_raw(Unit *unit) {
         Job *j;
@@ -168,7 +175,6 @@ static void job_merge_into_installed(Job *j, Job *other) {
         else
                 assert(other->type == JOB_NOP);
 
-        j->override = j->override || other->override;
         j->irreversible = j->irreversible || other->irreversible;
         j->ignore_order = j->ignore_order || other->ignore_order;
 }
@@ -300,12 +306,10 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
                 "%s-> Job %u:\n"
                 "%s\tAction: %s -> %s\n"
                 "%s\tState: %s\n"
-                "%s\tForced: %s\n"
                 "%s\tIrreversible: %s\n",
                 prefix, j->id,
                 prefix, j->unit->id, job_type_to_string(j->type),
                 prefix, job_state_to_string(j->state),
-                prefix, yes_no(j->override),
                 prefix, yes_no(j->irreversible));
 }
 
@@ -834,8 +838,6 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
                         job_fail_dependencies(u, UNIT_REQUIRED_BY);
                         job_fail_dependencies(u, UNIT_REQUISITE_OF);
                         job_fail_dependencies(u, UNIT_BOUND_BY);
-                        job_fail_dependencies(u, UNIT_REQUIRED_BY_OVERRIDABLE);
-                        job_fail_dependencies(u, UNIT_REQUISITE_OF_OVERRIDABLE);
                 } else if (t == JOB_STOP)
                         job_fail_dependencies(u, UNIT_CONFLICTED_BY);
         }
@@ -960,7 +962,6 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
         fprintf(f, "job-id=%u\n", j->id);
         fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
         fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
-        fprintf(f, "job-override=%s\n", yes_no(j->override));
         fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
         fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
         fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
@@ -1028,15 +1029,6 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
                         else
                                 job_set_state(j, s);
 
-                } else if (streq(l, "job-override")) {
-                        int b;
-
-                        b = parse_boolean(v);
-                        if (b < 0)
-                                log_debug("Failed to parse job override flag %s", v);
-                        else
-                                j->override = j->override || b;
-
                 } else if (streq(l, "job-irreversible")) {
                         int b;
 
index 1d1b10f1d36e845857ec9f36aa7cbf7f1f525a2f..60d8bd4f3e5e09e0487fe41de1af8fccc3ad1847 100644 (file)
 
 #include <stdbool.h>
 
+#include "sd-event.h"
+
+#include "list.h"
+
 typedef struct Job Job;
 typedef struct JobDependency JobDependency;
 typedef enum JobType JobType;
@@ -105,9 +109,7 @@ enum JobResult {
         _JOB_RESULT_INVALID = -1
 };
 
-#include "sd-event.h"
 #include "unit.h"
-#include "list.h"
 
 struct JobDependency {
         /* Encodes that the 'subject' job needs the 'object' job in
@@ -160,7 +162,6 @@ struct Job {
         bool installed:1;
         bool in_run_queue:1;
         bool matters_to_anchor:1;
-        bool override:1;
         bool in_dbus_queue:1;
         bool sent_dbus_new_signal:1;
         bool ignore_order:1;
index bddfa4460f9b7e3c163a7a5bb8a4ce75818825c9..1466d5ce64335021b30738875b3c658beb7e8755 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "signal-util.h"
 #include "kill.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "util.h"
 
 void kill_context_init(KillContext *c) {
         assert(c);
index ee5d388560d7da1f45069e4d15263f211a2d2447..77f145b4d1a006057b9415f1f097c2ef26d7d712 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/wait.h>
-#include <signal.h>
 #include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "killall.h"
-#include "set.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "killall.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "set.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "util.h"
 
 #define TIMEOUT_USEC (10 * USEC_PER_SEC)
 
index 2068ffd69b2008e0d506271e75485502e10b430d..651f79a1fe5cbc086bcd3eed782d14908a9eefc6 100644 (file)
@@ -27,7 +27,7 @@
 #endif
 
 #include "macro.h"
-#include "capability.h"
+#include "capability-util.h"
 #include "bus-util.h"
 #include "kmod-setup.h"
 
index 89e624b5579ab88ab30d7afa6035e7745e78a4b5..4c5376d6019e14872cb2dc0dee0d588113227b70 100644 (file)
@@ -33,6 +33,7 @@ $1.CPUAffinity,                  config_parse_exec_cpu_affinity,     0,
 $1.UMask,                        config_parse_mode,                  0,                             offsetof($1, exec_context.umask)
 $1.Environment,                  config_parse_environ,               0,                             offsetof($1, exec_context.environment)
 $1.EnvironmentFile,              config_parse_unit_env_file,         0,                             offsetof($1, exec_context.environment_files)
+$1.PassEnvironment,              config_parse_pass_environ,          0,                             offsetof($1, exec_context.pass_environment)
 $1.StandardInput,                config_parse_input,                 0,                             offsetof($1, exec_context.std_input)
 $1.StandardOutput,               config_parse_output,                0,                             offsetof($1, exec_context.std_output)
 $1.StandardError,                config_parse_output,                0,                             offsetof($1, exec_context.std_error)
@@ -58,22 +59,22 @@ $1.RestrictAddressFamilies,      config_parse_address_families,      0,
 $1.SystemCallArchitectures,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.SystemCallErrorNumber,        config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictAddressFamilies,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
-$1.LimitCPU,                     config_parse_limit,                 RLIMIT_CPU,                    offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE,                   config_parse_limit,                 RLIMIT_FSIZE,                  offsetof($1, exec_context.rlimit)
-$1.LimitDATA,                    config_parse_limit,                 RLIMIT_DATA,                   offsetof($1, exec_context.rlimit)
-$1.LimitSTACK,                   config_parse_limit,                 RLIMIT_STACK,                  offsetof($1, exec_context.rlimit)
-$1.LimitCORE,                    config_parse_limit,                 RLIMIT_CORE,                   offsetof($1, exec_context.rlimit)
-$1.LimitRSS,                     config_parse_limit,                 RLIMIT_RSS,                    offsetof($1, exec_context.rlimit)
+$1.LimitCPU,                     config_parse_sec_limit,             RLIMIT_CPU,                    offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE,                   config_parse_bytes_limit,           RLIMIT_FSIZE,                  offsetof($1, exec_context.rlimit)
+$1.LimitDATA,                    config_parse_bytes_limit,           RLIMIT_DATA,                   offsetof($1, exec_context.rlimit)
+$1.LimitSTACK,                   config_parse_bytes_limit,           RLIMIT_STACK,                  offsetof($1, exec_context.rlimit)
+$1.LimitCORE,                    config_parse_bytes_limit,           RLIMIT_CORE,                   offsetof($1, exec_context.rlimit)
+$1.LimitRSS,                     config_parse_bytes_limit,           RLIMIT_RSS,                    offsetof($1, exec_context.rlimit)
 $1.LimitNOFILE,                  config_parse_limit,                 RLIMIT_NOFILE,                 offsetof($1, exec_context.rlimit)
-$1.LimitAS,                      config_parse_limit,                 RLIMIT_AS,                     offsetof($1, exec_context.rlimit)
+$1.LimitAS,                      config_parse_bytes_limit,           RLIMIT_AS,                     offsetof($1, exec_context.rlimit)
 $1.LimitNPROC,                   config_parse_limit,                 RLIMIT_NPROC,                  offsetof($1, exec_context.rlimit)
-$1.LimitMEMLOCK,                 config_parse_limit,                 RLIMIT_MEMLOCK,                offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK,                 config_parse_bytes_limit,           RLIMIT_MEMLOCK,                offsetof($1, exec_context.rlimit)
 $1.LimitLOCKS,                   config_parse_limit,                 RLIMIT_LOCKS,                  offsetof($1, exec_context.rlimit)
 $1.LimitSIGPENDING,              config_parse_limit,                 RLIMIT_SIGPENDING,             offsetof($1, exec_context.rlimit)
-$1.LimitMSGQUEUE,                config_parse_limit,                 RLIMIT_MSGQUEUE,               offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE,                config_parse_bytes_limit,           RLIMIT_MSGQUEUE,               offsetof($1, exec_context.rlimit)
 $1.LimitNICE,                    config_parse_limit,                 RLIMIT_NICE,                   offsetof($1, exec_context.rlimit)
 $1.LimitRTPRIO,                  config_parse_limit,                 RLIMIT_RTPRIO,                 offsetof($1, exec_context.rlimit)
-$1.LimitRTTIME,                  config_parse_limit,                 RLIMIT_RTTIME,                 offsetof($1, exec_context.rlimit)
+$1.LimitRTTIME,                  config_parse_usec_limit,            RLIMIT_RTTIME,                 offsetof($1, exec_context.rlimit)
 $1.ReadWriteDirectories,         config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_write_dirs)
 $1.ReadOnlyDirectories,          config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.read_only_dirs)
 $1.InaccessibleDirectories,      config_parse_namespace_path_strv,   0,                             offsetof($1, exec_context.inaccessible_dirs)
@@ -133,9 +134,7 @@ Unit.Description,                config_parse_unit_string_printf,    0,
 Unit.Documentation,              config_parse_documentation,         0,                             offsetof(Unit, documentation)
 Unit.SourcePath,                 config_parse_path,                  0,                             offsetof(Unit, source_path)
 Unit.Requires,                   config_parse_unit_deps,             UNIT_REQUIRES,                 0
-Unit.RequiresOverridable,        config_parse_unit_deps,             UNIT_REQUIRES_OVERRIDABLE,     0
 Unit.Requisite,                  config_parse_unit_deps,             UNIT_REQUISITE,                0
-Unit.RequisiteOverridable,       config_parse_unit_deps,             UNIT_REQUISITE_OVERRIDABLE,    0
 Unit.Wants,                      config_parse_unit_deps,             UNIT_WANTS,                    0
 Unit.BindsTo,                    config_parse_unit_deps,             UNIT_BINDS_TO,                 0
 Unit.BindTo,                     config_parse_unit_deps,             UNIT_BINDS_TO,                 0
@@ -149,6 +148,8 @@ Unit.ReloadPropagatedFrom,       config_parse_unit_deps,             UNIT_RELOAD
 Unit.PropagateReloadFrom,        config_parse_unit_deps,             UNIT_RELOAD_PROPAGATED_FROM,   0
 Unit.PartOf,                     config_parse_unit_deps,             UNIT_PART_OF,                  0
 Unit.JoinsNamespaceOf,           config_parse_unit_deps,             UNIT_JOINS_NAMESPACE_OF,       0
+Unit.RequiresOverridable,        config_parse_obsolete_unit_deps,    UNIT_REQUIRES,                 0
+Unit.RequisiteOverridable,       config_parse_obsolete_unit_deps,    UNIT_REQUISITE,    0
 Unit.RequiresMountsFor,          config_parse_unit_requires_mounts_for, 0,                          0
 Unit.StopWhenUnneeded,           config_parse_bool,                  0,                             offsetof(Unit, stop_when_unneeded)
 Unit.RefuseManualStart,          config_parse_bool,                  0,                             offsetof(Unit, refuse_manual_start)
@@ -158,7 +159,7 @@ Unit.DefaultDependencies,        config_parse_bool,                  0,
 Unit.OnFailureJobMode,           config_parse_job_mode,              0,                             offsetof(Unit, on_failure_job_mode)
 Unit.OnFailureIsolate,           config_parse_job_mode_isolate,      0,                             offsetof(Unit, on_failure_job_mode)
 Unit.IgnoreOnIsolate,            config_parse_bool,                  0,                             offsetof(Unit, ignore_on_isolate)
-Unit.IgnoreOnSnapshot,           config_parse_bool,                  0,                             offsetof(Unit, ignore_on_snapshot)
+Unit.IgnoreOnSnapshot,           config_parse_warn_compat,           DISABLED_LEGACY,               0
 Unit.JobTimeoutSec,              config_parse_sec,                   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)
index b1d4c6b57d3e79093638a1cd8534204b944b9e6d..62cad0a0c0551ea34bfe4e9e29adb465f4b276e9 100644 (file)
@@ -32,6 +32,7 @@
 #include <sys/resource.h>
 #include <sys/stat.h>
 
+#include "alloc-util.h"
 #include "af-list.h"
 #include "bus-error.h"
 #include "bus-internal.h"
 #include "cpu-set-util.h"
 #include "env-util.h"
 #include "errno-list.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "ioprio.h"
+#include "load-fragment.h"
 #include "log.h"
 #include "missing.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #ifdef HAVE_SECCOMP
 #include "seccomp-util.h"
 #endif
 #include "securebits.h"
 #include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
 #include "unit-printf.h"
 #include "unit.h"
 #include "utf8.h"
-#include "load-fragment.h"
+#include "web-util.h"
 
 int config_parse_warn_compat(
                 const char *unit,
@@ -89,35 +98,42 @@ int config_parse_warn_compat(
         return 0;
 }
 
-int config_parse_unit_deps(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_unit_deps(
+                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) {
 
         UnitDependency d = ltype;
         Unit *u = userdata;
-        const char *word, *state;
-        size_t l;
+        const char *p;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *t = NULL, *k = NULL;
+        p = rvalue;
+        for(;;) {
+                _cleanup_free_ char *word = NULL, *k = NULL;
                 int r;
 
-                t = strndup(word, l);
-                if (!t)
+                r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+                        break;
+                }
 
-                r = unit_name_printf(u, t, &k);
+                r = unit_name_printf(u, word, &k);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
                         continue;
@@ -127,12 +143,28 @@ int config_parse_unit_deps(const char *unit,
                 if (r < 0)
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
 
         return 0;
 }
 
+int config_parse_obsolete_unit_deps(
+                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) {
+
+        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                   "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
+
+        return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
+}
+
 int config_parse_unit_string_printf(
                 const char *unit,
                 const char *filename,
@@ -522,9 +554,7 @@ int config_parse_exec(
         assert(e);
 
         e += ltype;
-
         rvalue += strspn(rvalue, WHITESPACE);
-        p = rvalue;
 
         if (isempty(rvalue)) {
                 /* An empty assignment resets the list */
@@ -532,14 +562,15 @@ int config_parse_exec(
                 return 0;
         }
 
+        p = rvalue;
         do {
-                int i;
+                _cleanup_free_ char *path = NULL, *firstword = NULL;
+                bool separate_argv0 = false, ignore = false;
+                _cleanup_free_ ExecCommand *nce = NULL;
                 _cleanup_strv_free_ char **n = NULL;
                 size_t nlen = 0, nbufsize = 0;
-                _cleanup_free_ ExecCommand *nce = NULL;
-                _cleanup_free_ char *path = NULL, *firstword = NULL;
                 char *f;
-                bool separate_argv0 = false, ignore = false;
+                int i;
 
                 semicolon = false;
 
@@ -962,22 +993,22 @@ int config_parse_exec_secure_bits(const char *unit,
         return 0;
 }
 
-int config_parse_bounding_set(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_bounding_set(
+                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) {
 
         uint64_t *capability_bounding_set_drop = data;
-        const char *word, *state;
-        size_t l;
+        uint64_t capability_bounding_set, sum = 0;
         bool invert = false;
-        uint64_t sum = 0;
+        const char *p;
 
         assert(filename);
         assert(lvalue);
@@ -994,46 +1025,54 @@ int config_parse_bounding_set(const char *unit,
          * non-inverted everywhere to have a fully normalized
          * interface. */
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *t = NULL;
-                int cap;
+        p = rvalue;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+                int cap, r;
 
-                t = strndup(word, l);
-                if (!t)
+                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
+                        break;
+                }
 
-                cap = capability_from_name(t);
+                cap = capability_from_name(word);
                 if (cap < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t);
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
                         continue;
                 }
 
-                sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+                sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
-        if (invert)
-                *capability_bounding_set_drop |= sum;
+        capability_bounding_set = invert ? ~sum : sum;
+        if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
+                *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
         else
-                *capability_bounding_set_drop |= ~sum;
+                *capability_bounding_set_drop = ~capability_bounding_set;
 
         return 0;
 }
 
-int config_parse_limit(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_limit(
+                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) {
 
         struct rlimit **rl = data;
-        unsigned long long u;
+        rlim_t v;
+        int r;
 
         assert(filename);
         assert(lvalue);
@@ -1043,15 +1082,172 @@ int config_parse_limit(const char *unit,
         rl += ltype;
 
         if (streq(rvalue, "infinity"))
-                u = (unsigned long long) RLIM_INFINITY;
+                v = RLIM_INFINITY;
         else {
-                int r;
+                uint64_t u;
+
+                /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
+                assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
+
+                r = safe_atou64(rvalue, &u);
+                if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+                        r = -ERANGE;
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+                        return 0;
+                }
+
+                v = (rlim_t) u;
+        }
+
+        if (!*rl) {
+                *rl = new(struct rlimit, 1);
+                if (!*rl)
+                        return log_oom();
+        }
+
+        (*rl)->rlim_cur = (*rl)->rlim_max = v;
+        return 0;
+}
+
+int config_parse_bytes_limit(
+                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) {
+
+        struct rlimit **rl = data;
+        rlim_t bytes;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        rl += ltype;
+
+        if (streq(rvalue, "infinity"))
+                bytes = RLIM_INFINITY;
+        else {
+                uint64_t u;
+
+                r = parse_size(rvalue, 1024, &u);
+                if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+                        r = -ERANGE;
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+                        return 0;
+                }
+
+                bytes = (rlim_t) u;
+        }
+
+        if (!*rl) {
+                *rl = new(struct rlimit, 1);
+                if (!*rl)
+                        return log_oom();
+        }
+
+        (*rl)->rlim_cur = (*rl)->rlim_max = bytes;
+        return 0;
+}
+
+int config_parse_sec_limit(
+                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) {
+
+        struct rlimit **rl = data;
+        rlim_t seconds;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        rl += ltype;
+
+        if (streq(rvalue, "infinity"))
+                seconds = RLIM_INFINITY;
+        else {
+                usec_t t;
+
+                r = parse_sec(rvalue, &t);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+                        return 0;
+                }
+
+                if (t == USEC_INFINITY)
+                        seconds = RLIM_INFINITY;
+                else
+                        seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
+        }
+
+        if (!*rl) {
+                *rl = new(struct rlimit, 1);
+                if (!*rl)
+                        return log_oom();
+        }
+
+        (*rl)->rlim_cur = (*rl)->rlim_max = seconds;
+        return 0;
+}
+
+
+int config_parse_usec_limit(
+                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) {
+
+        struct rlimit **rl = data;
+        rlim_t useconds;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        rl += ltype;
+
+        if (streq(rvalue, "infinity"))
+                useconds = RLIM_INFINITY;
+        else {
+                usec_t t;
 
-                r = safe_atollu(rvalue, &u);
+                r = parse_time(rvalue, &t, 1);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
                         return 0;
                 }
+
+                if (t == USEC_INFINITY)
+                        useconds = RLIM_INFINITY;
+                else
+                        useconds = (rlim_t) t;
         }
 
         if (!*rl) {
@@ -1060,7 +1256,7 @@ int config_parse_limit(const char *unit,
                         return log_oom();
         }
 
-        (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
+        (*rl)->rlim_cur = (*rl)->rlim_max = useconds;
         return 0;
 }
 
@@ -1564,8 +1760,7 @@ int config_parse_service_sockets(
                 void *userdata) {
 
         Service *s = data;
-        const char *word, *state;
-        size_t l;
+        const char *p;
         int r;
 
         assert(filename);
@@ -1573,14 +1768,21 @@ int config_parse_service_sockets(
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *t = NULL, *k = NULL;
+        p = rvalue;
+        for(;;) {
+                _cleanup_free_ char *word = NULL, *k = NULL;
 
-                t = strndup(word, l);
-                if (!t)
+                r = extract_first_word(&p, &word, NULL, 0);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
+                        break;
+                }
 
-                r = unit_name_printf(UNIT(s), t, &k);
+                r = unit_name_printf(UNIT(s), word, &k);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
                         continue;
@@ -1599,8 +1801,6 @@ int config_parse_service_sockets(
                 if (r < 0)
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
         return 0;
 }
@@ -2015,6 +2215,70 @@ int config_parse_environ(const char *unit,
         return 0;
 }
 
+int config_parse_pass_environ(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) {
+
+        const char *whole_rvalue = rvalue;
+        char*** passenv = data;
+        _cleanup_strv_free_ char **n = NULL;
+        size_t nlen = 0, nbufsize = 0;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                *passenv = strv_free(*passenv);
+                return 0;
+        }
+
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
+
+                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+                        break;
+                }
+
+                if (!env_name_is_valid(word)) {
+                        log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                                   "Invalid environment name for %s, ignoring: %s", lvalue, word);
+                        continue;
+                }
+
+                if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
+                        return log_oom();
+                n[nlen++] = word;
+                n[nlen] = NULL;
+                word = NULL;
+        }
+
+        if (n) {
+                r = strv_extend_strv(passenv, n, true);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 int config_parse_ip_tos(const char *unit,
                         const char *filename,
                         unsigned line,
@@ -2742,6 +3006,7 @@ int config_parse_tasks_max(
                 return 0;
         }
 
+        c->tasks_max = u;
         return 0;
 }
 
@@ -3192,8 +3457,8 @@ int config_parse_namespace_path_strv(
                 void *userdata) {
 
         char*** sv = data;
-        const char *word, *state;
-        size_t l;
+        const char *prev;
+        const char *cur;
         int r;
 
         assert(filename);
@@ -3207,35 +3472,43 @@ int config_parse_namespace_path_strv(
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *n;
+        prev = cur = rvalue;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
                 int offset;
 
-                n = strndup(word, l);
-                if (!n)
+                r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
+                        return 0;
+                }
 
-                if (!utf8_is_valid(n)) {
-                        log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+                if (!utf8_is_valid(word)) {
+                        log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
+                        prev = cur;
                         continue;
                 }
 
-                offset = n[0] == '-';
-                if (!path_is_absolute(n + offset)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
+                offset = word[0] == '-';
+                if (!path_is_absolute(word + offset)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
+                        prev = cur;
                         continue;
                 }
 
-                path_kill_slashes(n);
+                path_kill_slashes(word + offset);
 
-                r = strv_push(sv, n);
+                r = strv_push(sv, word);
                 if (r < 0)
                         return log_oom();
 
-                n = NULL;
+                prev = cur;
+                word = NULL;
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
         return 0;
 }
index 8661cbfedcdc3ffd28ddad6b6bce461a4a3026f3..62300c10f9fb192abc6e78ae813cda1b6e67da39 100644 (file)
@@ -31,6 +31,7 @@ void unit_dump_config_items(FILE *f);
 
 int config_parse_warn_compat(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_unit_deps(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_obsolete_unit_deps(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_unit_string_printf(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_unit_strv_printf(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_unit_path_printf(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);
@@ -56,6 +57,9 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig
 int config_parse_exec_secure_bits(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_bounding_set(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_limit(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_bytes_limit(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_sec_limit(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_usec_limit(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_sysv_priority(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_kill_signal(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_exec_mount_flags(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);
@@ -81,6 +85,7 @@ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned
 int config_parse_syscall_archs(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_syscall_errno(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_environ(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_pass_environ(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_unit_slice(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_cpu_shares(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_memory_limit(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 6961c26674515a8658c50daa7d0a4095a97fea09..bd632131b90cde0d699f53a97baf78473de82a32 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
+#include <stdlib.h>
 
-#include "locale-setup.h"
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "strv.h"
 #include "env-util.h"
+#include "fileio.h"
 #include "locale-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "virt.h"
+#include "locale-setup.h"
 
 int locale_setup(char ***environment) {
         char **add;
index 4503fc9dcca86b82863fda04d3dffe898a19a2ab..4a57793104e075ea9985a4d2f6c6b47c36bc55d5 100644 (file)
 #include <stdlib.h>
 
 #include "sd-netlink.h"
-#include "netlink-util.h"
-#include "missing.h"
+
 #include "loopback-setup.h"
+#include "missing.h"
+#include "netlink-util.h"
 
 static int start_loopback(sd_netlink *rtnl) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
index 363ffaaf05af65f7b26df9dbaa4741537af9333e..145ba2a28df62f98bf6c6334d419b746b64866e7 100644 (file)
 
 #include "sd-id128.h"
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
 #include "log.h"
+#include "machine-id-setup.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "mount-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "umask-util.h"
 #include "util.h"
 #include "virt.h"
-#include "machine-id-setup.h"
 
 static int shorten_uuid(char destination[34], const char source[36]) {
         unsigned i, j;
index 87b3af92bcd4704dc6239d8b2e9c51cba5c12dc4..33529c3e7681909e03bbaadbc0a0f30d713c8acf 100644 (file)
 #include "sd-daemon.h"
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "architecture.h"
 #include "build.h"
 #include "bus-error.h"
 #include "bus-util.h"
-#include "capability.h"
+#include "capability-util.h"
 #include "clock-util.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
 #include "dbus-manager.h"
 #include "def.h"
 #include "env-util.h"
+#include "fd-util.h"
 #include "fdset.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "hostname-setup.h"
 #include "ima-setup.h"
 #include "killall.h"
 #include "missing.h"
 #include "mount-setup.h"
 #include "pager.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "selinux-setup.h"
 #include "selinux-util.h"
 #include "signal-util.h"
 #include "smack-setup.h"
 #include "special.h"
+#include "stat-util.h"
+#include "stdio-util.h"
 #include "strv.h"
 #include "switch-root.h"
 #include "terminal-util.h"
+#include "user-util.h"
 #include "virt.h"
 #include "watchdog.h"
 
@@ -292,20 +301,6 @@ static int parse_crash_chvt(const char *value) {
 
 static int parse_proc_cmdline_item(const char *key, const char *value) {
 
-        static const char * const rlmap[] = {
-                "emergency", SPECIAL_EMERGENCY_TARGET,
-                "-b",        SPECIAL_EMERGENCY_TARGET,
-                "rescue",    SPECIAL_RESCUE_TARGET,
-                "single",    SPECIAL_RESCUE_TARGET,
-                "-s",        SPECIAL_RESCUE_TARGET,
-                "s",         SPECIAL_RESCUE_TARGET,
-                "S",         SPECIAL_RESCUE_TARGET,
-                "1",         SPECIAL_RESCUE_TARGET,
-                "2",         SPECIAL_MULTI_USER_TARGET,
-                "3",         SPECIAL_MULTI_USER_TARGET,
-                "4",         SPECIAL_MULTI_USER_TARGET,
-                "5",         SPECIAL_GRAPHICAL_TARGET,
-        };
         int r;
 
         assert(key);
@@ -406,12 +401,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                         log_set_target(LOG_TARGET_CONSOLE);
 
         } else if (!in_initrd() && !value) {
-                unsigned i;
+                const char *target;
 
                 /* SysV compatibility */
-                for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
-                        if (streq(key, rlmap[i]))
-                                return free_and_strdup(&arg_default_unit, rlmap[i+1]);
+                target = runlevel_to_target(key);
+                if (target)
+                        return free_and_strdup(&arg_default_unit, target);
         }
 
         return 0;
@@ -663,18 +658,18 @@ static int parse_config_file(void) {
                 { "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,            0, &arg_default_rlimit[RLIMIT_CPU]        },
-                { "Manager", "DefaultLimitFSIZE",         config_parse_limit,            0, &arg_default_rlimit[RLIMIT_FSIZE]      },
-                { "Manager", "DefaultLimitDATA",          config_parse_limit,            0, &arg_default_rlimit[RLIMIT_DATA]       },
-                { "Manager", "DefaultLimitSTACK",         config_parse_limit,            0, &arg_default_rlimit[RLIMIT_STACK]      },
-                { "Manager", "DefaultLimitCORE",          config_parse_limit,            0, &arg_default_rlimit[RLIMIT_CORE]       },
-                { "Manager", "DefaultLimitRSS",           config_parse_limit,            0, &arg_default_rlimit[RLIMIT_RSS]        },
+                { "Manager", "DefaultLimitFSIZE",         config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_FSIZE]      },
+                { "Manager", "DefaultLimitDATA",          config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_DATA]       },
+                { "Manager", "DefaultLimitSTACK",         config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_STACK]      },
+                { "Manager", "DefaultLimitCORE",          config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_CORE]       },
+                { "Manager", "DefaultLimitRSS",           config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_RSS]        },
                 { "Manager", "DefaultLimitNOFILE",        config_parse_limit,            0, &arg_default_rlimit[RLIMIT_NOFILE]     },
-                { "Manager", "DefaultLimitAS",            config_parse_limit,            0, &arg_default_rlimit[RLIMIT_AS]         },
+                { "Manager", "DefaultLimitAS",            config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_AS]         },
                 { "Manager", "DefaultLimitNPROC",         config_parse_limit,            0, &arg_default_rlimit[RLIMIT_NPROC]      },
-                { "Manager", "DefaultLimitMEMLOCK",       config_parse_limit,            0, &arg_default_rlimit[RLIMIT_MEMLOCK]    },
+                { "Manager", "DefaultLimitMEMLOCK",       config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_MEMLOCK]    },
                 { "Manager", "DefaultLimitLOCKS",         config_parse_limit,            0, &arg_default_rlimit[RLIMIT_LOCKS]      },
                 { "Manager", "DefaultLimitSIGPENDING",    config_parse_limit,            0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
-                { "Manager", "DefaultLimitMSGQUEUE",      config_parse_limit,            0, &arg_default_rlimit[RLIMIT_MSGQUEUE]   },
+                { "Manager", "DefaultLimitMSGQUEUE",      config_parse_bytes_limit,      0, &arg_default_rlimit[RLIMIT_MSGQUEUE]   },
                 { "Manager", "DefaultLimitNICE",          config_parse_limit,            0, &arg_default_rlimit[RLIMIT_NICE]       },
                 { "Manager", "DefaultLimitRTPRIO",        config_parse_limit,            0, &arg_default_rlimit[RLIMIT_RTPRIO]     },
                 { "Manager", "DefaultLimitRTTIME",        config_parse_limit,            0, &arg_default_rlimit[RLIMIT_RTTIME]     },
@@ -687,8 +682,14 @@ static int parse_config_file(void) {
 
         const char *fn, *conf_dirs_nulstr;
 
-        fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
-        conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
+        fn = arg_running_as == MANAGER_SYSTEM ?
+                PKGSYSCONFDIR "/system.conf" :
+                PKGSYSCONFDIR "/user.conf";
+
+        conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
+                CONF_PATHS_NULSTR("systemd/system.conf.d") :
+                CONF_PATHS_NULSTR("systemd/user.conf.d");
+
         config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
                           config_item_table_lookup, items, false, NULL);
 
@@ -1104,33 +1105,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
         return 0;
 }
 
-static void test_mtab(void) {
-
-        static const char ok[] =
-                "/proc/self/mounts\0"
-                "/proc/mounts\0"
-                "../proc/self/mounts\0"
-                "../proc/mounts\0";
-
-        _cleanup_free_ char *p = NULL;
-        int r;
-
-        /* Check that /etc/mtab is a symlink to the right place or
-         * non-existing. But certainly not a file, or a symlink to
-         * some weird place... */
-
-        r = readlink_malloc("/etc/mtab", &p);
-        if (r == -ENOENT)
-                return;
-        if (r >= 0 && nulstr_contains(ok, p))
-                return;
-
-        log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
-                  "This is not supported anymore. "
-                  "Please replace /etc/mtab with a symlink to /proc/self/mounts.");
-        freeze_or_reboot();
-}
-
 static void test_usr(void) {
 
         /* Check that /usr is not a separate fs */
@@ -1233,12 +1207,50 @@ static int status_welcome(void) {
 
 static int write_container_id(void) {
         const char *c;
+        int r;
 
         c = getenv("container");
         if (isempty(c))
                 return 0;
 
-        return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+        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");
+
+        return 1;
+}
+
+static int bump_unix_max_dgram_qlen(void) {
+        _cleanup_free_ char *qlen = NULL;
+        unsigned long v;
+        int r;
+
+        /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
+         * default of 16 is simply too low. We set the value really
+         * really early during boot, so that it is actually applied to
+         * all our sockets, including the $NOTIFY_SOCKET one. */
+
+        r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
+
+        r = safe_atolu(qlen, &v);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
+
+        if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
+                return 0;
+
+        qlen = mfree(qlen);
+        if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
+                return log_oom();
+
+        r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
+        if (r < 0)
+                return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                                      "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
+
+        return 1;
 }
 
 int main(int argc, char *argv[]) {
@@ -1604,8 +1616,8 @@ int main(int argc, char *argv[]) {
                 hostname_setup();
                 machine_id_setup(NULL);
                 loopback_setup();
+                bump_unix_max_dgram_qlen();
 
-                test_mtab();
                 test_usr();
         }
 
@@ -1732,11 +1744,13 @@ int main(int argc, char *argv[]) {
                         manager_dump_units(m, stdout, "\t");
                 }
 
-                r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job);
+                r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
                 if (r == -EPERM) {
                         log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
 
-                        r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job);
+                        sd_bus_error_free(&error);
+
+                        r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
                         if (r < 0) {
                                 log_emergency("Failed to start default target: %s", bus_error_message(&error, r));
                                 error_message = "Failed to start default target";
index 526d4d1cef0d9d93eeda8c204e8822ce7e35dd82..f695b8a66c0ea055c6295a1e9bc4c1636f02dab3 100644 (file)
@@ -40,6 +40,7 @@
 #include "sd-daemon.h"
 #include "sd-messages.h"
 
+#include "alloc-util.h"
 #include "audit-fd.h"
 #include "boot-timestamps.h"
 #include "bus-common-errors.h"
 #include "dbus-unit.h"
 #include "dbus.h"
 #include "env-util.h"
+#include "escape.h"
 #include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "hashmap.h"
+#include "io-util.h"
 #include "locale-setup.h"
 #include "log.h"
 #include "macro.h"
+#include "manager.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "rm-rf.h"
 #include "signal-util.h"
 #include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "time-util.h"
 #include "transaction.h"
+#include "umask-util.h"
 #include "unit-name.h"
 #include "util.h"
 #include "virt.h"
 #include "watchdog.h"
-#include "manager.h"
+
+#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
 
 /* Initial delay and the interval for printing status messages about running jobs */
 #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -473,7 +486,7 @@ static int manager_setup_signals(Manager *m) {
          * later than notify_fd processing, so that the notify
          * processing can still figure out to which process/service a
          * message belongs, before we reap the process. */
-        r = sd_event_source_set_priority(m->signal_event_source, -5);
+        r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5);
         if (r < 0)
                 return r;
 
@@ -678,6 +691,8 @@ static int manager_setup_notify(Manager *m) {
                 if (fd < 0)
                         return log_error_errno(errno, "Failed to allocate notification socket: %m");
 
+                fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
+
                 if (m->running_as == MANAGER_SYSTEM)
                         m->notify_socket = strdup("/run/systemd/notify");
                 else {
@@ -719,7 +734,7 @@ static int manager_setup_notify(Manager *m) {
 
                 /* Process signals a bit earlier than SIGCHLD, so that we can
                  * still identify to which service an exit message belongs */
-                r = sd_event_source_set_priority(m->notify_event_source, -7);
+                r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7);
                 if (r < 0)
                         return log_error_errno(r, "Failed to set priority of notify event source: %m");
 
@@ -978,8 +993,7 @@ Manager* manager_free(Manager *m) {
         return NULL;
 }
 
-int manager_enumerate(Manager *m) {
-        int r = 0;
+void manager_enumerate(Manager *m) {
         UnitType c;
 
         assert(m);
@@ -987,8 +1001,6 @@ int manager_enumerate(Manager *m) {
         /* Let's ask every type to load all units from disk/kernel
          * that it might know */
         for (c = 0; c < _UNIT_TYPE_MAX; c++) {
-                int q;
-
                 if (!unit_type_supported(c)) {
                         log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
                         continue;
@@ -997,13 +1009,10 @@ int manager_enumerate(Manager *m) {
                 if (!unit_vtable[c]->enumerate)
                         continue;
 
-                q = unit_vtable[c]->enumerate(m);
-                if (q < 0)
-                        r = q;
+                unit_vtable[c]->enumerate(m);
         }
 
         manager_dispatch_load_queue(m);
-        return r;
 }
 
 static void manager_coldplug(Manager *m) {
@@ -1085,10 +1094,9 @@ fail:
 }
 
 
-static int manager_distribute_fds(Manager *m, FDSet *fds) {
-        Unit *u;
+static void manager_distribute_fds(Manager *m, FDSet *fds) {
         Iterator i;
-        int r;
+        Unit *u;
 
         assert(m);
 
@@ -1097,14 +1105,11 @@ static int manager_distribute_fds(Manager *m, FDSet *fds) {
                 if (fdset_size(fds) <= 0)
                         break;
 
-                if (UNIT_VTABLE(u)->distribute_fds) {
-                        r = UNIT_VTABLE(u)->distribute_fds(u, fds);
-                        if (r < 0)
-                                return r;
-                }
-        }
+                if (!UNIT_VTABLE(u)->distribute_fds)
+                        continue;
 
-        return 0;
+                UNIT_VTABLE(u)->distribute_fds(u, fds);
+        }
 }
 
 int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
@@ -1137,7 +1142,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
 
         /* First, enumerate what we can from all config files */
         dual_timestamp_get(&m->units_load_start_timestamp);
-        r = manager_enumerate(m);
+        manager_enumerate(m);
         dual_timestamp_get(&m->units_load_finish_timestamp);
 
         /* Second, deserialize if there is something to deserialize */
@@ -1148,11 +1153,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
          * useful to allow container managers to pass some file
          * descriptors to us pre-initialized. This enables
          * socket-based activation of entire containers. */
-        if (fdset_size(fds) > 0) {
-                q = manager_distribute_fds(m, fds);
-                if (q < 0 && r == 0)
-                        r = q;
-        }
+        manager_distribute_fds(m, fds);
 
         /* We might have deserialized the notify fd, but if we didn't
          * then let's create the bus now */
@@ -1182,7 +1183,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         return r;
 }
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
         int r;
         Transaction *tr;
 
@@ -1205,7 +1206,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
         if (!tr)
                 return -ENOMEM;
 
-        r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
+        r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
                                                  mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
                                                  mode == JOB_IGNORE_DEPENDENCIES, e);
         if (r < 0)
@@ -1237,7 +1238,7 @@ tr_abort:
         return r;
 }
 
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
         Unit *unit;
         int r;
 
@@ -1250,7 +1251,23 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
         if (r < 0)
                 return r;
 
-        return manager_add_job(m, type, unit, mode, override, e, _ret);
+        return manager_add_job(m, type, unit, mode, e, ret);
+}
+
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        assert(m);
+        assert(type < _JOB_TYPE_MAX);
+        assert(name);
+        assert(mode < _JOB_MODE_MAX);
+
+        r = manager_add_job_by_name(m, type, name, mode, &error, ret);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
+
+        return r;
 }
 
 Job *manager_get_job(Manager *m, uint32_t id) {
@@ -1477,7 +1494,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
         return n;
 }
 
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
+static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
         _cleanup_strv_free_ char **tags = NULL;
 
         assert(m);
@@ -1498,9 +1515,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
 }
 
 static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+        _cleanup_fdset_free_ FDSet *fds = NULL;
         Manager *m = userdata;
+
+        char buf[NOTIFY_BUFFER_MAX+1];
+        struct iovec iovec = {
+                .iov_base = buf,
+                .iov_len = sizeof(buf)-1,
+        };
+        union {
+                struct cmsghdr cmsghdr;
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
+        } control = {};
+        struct msghdr msghdr = {
+                .msg_iov = &iovec,
+                .msg_iovlen = 1,
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+        };
+
+        struct cmsghdr *cmsg;
+        struct ucred *ucred = NULL;
+        bool found = false;
+        Unit *u1, *u2, *u3;
+        int r, *fd_array = NULL;
+        unsigned n_fds = 0;
         ssize_t n;
-        int r;
 
         assert(m);
         assert(m->notify_fd == fd);
@@ -1510,106 +1551,80 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
                 return 0;
         }
 
-        for (;;) {
-                _cleanup_fdset_free_ FDSet *fds = NULL;
-                char buf[NOTIFY_BUFFER_MAX+1];
-                struct iovec iovec = {
-                        .iov_base = buf,
-                        .iov_len = sizeof(buf)-1,
-                };
-                union {
-                        struct cmsghdr cmsghdr;
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                                    CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
-                } control = {};
-                struct msghdr msghdr = {
-                        .msg_iov = &iovec,
-                        .msg_iovlen = 1,
-                        .msg_control = &control,
-                        .msg_controllen = sizeof(control),
-                };
-                struct cmsghdr *cmsg;
-                struct ucred *ucred = NULL;
-                bool found = false;
-                Unit *u1, *u2, *u3;
-                int *fd_array = NULL;
-                unsigned n_fds = 0;
-
-                n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-                if (n < 0) {
-                        if (errno == EAGAIN || errno == EINTR)
-                                break;
+        n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+        if (n < 0) {
+                if (errno == EAGAIN || errno == EINTR)
+                        return 0;
 
-                        return -errno;
-                }
+                return -errno;
+        }
 
-                CMSG_FOREACH(cmsg, &msghdr) {
-                        if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+        CMSG_FOREACH(cmsg, &msghdr) {
+                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
 
-                                fd_array = (int*) CMSG_DATA(cmsg);
-                                n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+                        fd_array = (int*) CMSG_DATA(cmsg);
+                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
 
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+                } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                           cmsg->cmsg_type == SCM_CREDENTIALS &&
+                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
 
-                                ucred = (struct ucred*) CMSG_DATA(cmsg);
-                        }
+                        ucred = (struct ucred*) CMSG_DATA(cmsg);
                 }
+        }
 
-                if (n_fds > 0) {
-                        assert(fd_array);
+        if (n_fds > 0) {
+                assert(fd_array);
 
-                        r = fdset_new_array(&fds, fd_array, n_fds);
-                        if (r < 0) {
-                                close_many(fd_array, n_fds);
-                                return log_oom();
-                        }
+                r = fdset_new_array(&fds, fd_array, n_fds);
+                if (r < 0) {
+                        close_many(fd_array, n_fds);
+                        return log_oom();
                 }
+        }
 
-                if (!ucred || ucred->pid <= 0) {
-                        log_warning("Received notify message without valid credentials. Ignoring.");
-                        continue;
-                }
+        if (!ucred || ucred->pid <= 0) {
+                log_warning("Received notify message without valid credentials. Ignoring.");
+                return 0;
+        }
 
-                if ((size_t) n >= sizeof(buf)) {
-                        log_warning("Received notify message exceeded maximum size. Ignoring.");
-                        continue;
-                }
+        if ((size_t) n >= sizeof(buf)) {
+                log_warning("Received notify message exceeded maximum size. Ignoring.");
+                return 0;
+        }
 
-                buf[n] = 0;
+        buf[n] = 0;
 
-                /* Notify every unit that might be interested, but try
-                 * to avoid notifying the same one multiple times. */
-                u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
-                if (u1) {
-                        manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
-                        found = true;
-                }
+        /* Notify every unit that might be interested, but try
+         * to avoid notifying the same one multiple times. */
+        u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
+        if (u1) {
+                manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
+                found = true;
+        }
 
-                u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
-                if (u2 && u2 != u1) {
-                        manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
-                        found = true;
-                }
+        u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
+        if (u2 && u2 != u1) {
+                manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
+                found = true;
+        }
 
-                u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
-                if (u3 && u3 != u2 && u3 != u1) {
-                        manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
-                        found = true;
-                }
+        u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
+        if (u3 && u3 != u2 && u3 != u1) {
+                manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
+                found = true;
+        }
 
-                if (!found)
-                        log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
+        if (!found)
+                log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
 
-                if (fdset_size(fds) > 0)
-                        log_warning("Got auxiliary fds with notification message, closing all.");
-        }
+        if (fdset_size(fds) > 0)
+                log_warning("Got auxiliary fds with notification message, closing all.");
 
         return 0;
 }
 
-static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
+static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
         assert(m);
         assert(u);
         assert(si);
@@ -1688,7 +1703,7 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
 
         log_debug("Activating special unit %s", name);
 
-        r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
+        r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
         if (r < 0)
                 log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
 
@@ -1991,8 +2006,7 @@ int manager_loop(Manager *m) {
         m->exit_code = MANAGER_OK;
 
         /* Release the path cache */
-        set_free_free(m->unit_path_cache);
-        m->unit_path_cache = NULL;
+        m->unit_path_cache = set_free_free(m->unit_path_cache);
 
         manager_check_finished(m);
 
@@ -2012,7 +2026,6 @@ int manager_loop(Manager *m) {
                         /* Yay, something is going seriously wrong, pause a little */
                         log_warning("Looping too fast. Throttling execution a little.");
                         sleep(1);
-                        continue;
                 }
 
                 if (manager_dispatch_load_queue(m) > 0)
@@ -2102,6 +2115,9 @@ 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)
+                return;
+
         audit_fd = get_audit_fd();
         if (audit_fd < 0)
                 return;
@@ -2111,9 +2127,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
         if (m->n_reloading > 0)
                 return;
 
-        if (m->running_as != MANAGER_SYSTEM)
-                return;
-
         if (u->type != UNIT_SERVICE)
                 return;
 
@@ -2543,9 +2556,7 @@ int manager_reload(Manager *m) {
         manager_build_unit_path_cache(m);
 
         /* First, enumerate what we can from all config files */
-        q = manager_enumerate(m);
-        if (q < 0 && r >= 0)
-                r = q;
+        manager_enumerate(m);
 
         /* Second, deserialize our stored data */
         q = manager_deserialize(m, f, fds);
@@ -2762,8 +2773,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
                         return log_oom();
 
                 if (!mkdtemp(p)) {
-                        log_error_errno(errno, "Failed to create generator directory %s: %m",
-                                  p);
+                        log_error_errno(errno, "Failed to create generator directory %s: %m", p);
                         free(p);
                         return -errno;
                 }
@@ -2952,9 +2962,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
         m->show_status = mode;
 
         if (mode > 0)
-                touch("/run/systemd/show-status");
+                (void) touch("/run/systemd/show-status");
         else
-                unlink("/run/systemd/show-status");
+                (void) unlink("/run/systemd/show-status");
 }
 
 static bool manager_get_show_status(Manager *m, StatusType type) {
@@ -3013,30 +3023,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
         va_end(ap);
 }
 
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
-        _cleanup_free_ char *p = NULL;
-        Unit *found;
-        int r;
-
-        assert(m);
-        assert(path);
-        assert(suffix);
-        assert(_found);
-
-        r = unit_name_from_path(path, suffix, &p);
-        if (r < 0)
-                return r;
-
-        found = manager_get_unit(m, p);
-        if (!found) {
-                *_found = NULL;
-                return 0;
-        }
-
-        *_found = found;
-        return 1;
-}
-
 Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
         char p[strlen(path)+1];
 
index fad10aaacf3827dd00299cb74bb2c36f1ac322ea..bc3f02f872e09b9f01598104c75add9af17f39e9 100644 (file)
@@ -141,8 +141,6 @@ struct Manager {
 
         sd_event_source *jobs_in_progress_event_source;
 
-        unsigned n_snapshots;
-
         LookupPaths lookup_paths;
         Set *unit_path_cache;
 
@@ -316,22 +314,21 @@ struct Manager {
 int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
 Manager* manager_free(Manager *m);
 
-int manager_enumerate(Manager *m);
+void manager_enumerate(Manager *m);
 int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
 
 Job *manager_get_job(Manager *m, uint32_t id);
 Unit *manager_get_unit(Manager *m, const char *name);
 
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
-
 int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
 
 int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
 int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
 int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret);
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
 
 void manager_dump_units(Manager *s, FILE *f, const char *prefix);
 void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
index 9b16eaa0e2d9ae0679164017995922fce9a1bf05..b2596d1cd199e55aab1167565b4e38863e1e6d29 100644 (file)
 #include <unistd.h>
 #include <ftw.h>
 
-#include "mount-setup.h"
-#include "dev-setup.h"
+#include "alloc-util.h"
 #include "bus-util.h"
+#include "cgroup-util.h"
+#include "dev-setup.h"
+#include "efivars.h"
+#include "label.h"
 #include "log.h"
 #include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
+#include "missing.h"
 #include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
 #include "path-util.h"
-#include "missing.h"
-#include "virt.h"
-#include "efivars.h"
+#include "set.h"
 #include "smack-util.h"
-#include "cgroup-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
 
 typedef enum MountMode {
         MNT_NONE  =        0,
index 861112945353b6daf59aff46142187539b33174b..9b44357e905f26895e571f90df5736ad2209630d 100644 (file)
 ***/
 
 #include <errno.h>
+#include <signal.h>
 #include <stdio.h>
 #include <sys/epoll.h>
-#include <signal.h>
 
-#include "manager.h"
-#include "unit.h"
-#include "mount.h"
-#include "log.h"
 #include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "mount-setup.h"
-#include "unit-name.h"
+
+#include "alloc-util.h"
 #include "dbus-mount.h"
-#include "special.h"
+#include "escape.h"
 #include "exit-status.h"
-#include "fstab-util.h"
 #include "formats-util.h"
+#include "fstab-util.h"
+#include "log.h"
+#include "manager.h"
+#include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit.h"
 
 #define RETRY_UMOUNT_MAX 32
 
@@ -246,9 +254,10 @@ static int mount_add_mount_links(Mount *m) {
         if (!path_equal(m->where, "/")) {
                 /* Adds in links to other mount points that might lie further
                  * up in the hierarchy */
-                r = path_get_parent(m->where, &parent);
-                if (r < 0)
-                        return r;
+
+                parent = dirname_malloc(m->where);
+                if (!parent)
+                        return -ENOMEM;
 
                 r = unit_require_mounts_for(UNIT(m), parent);
                 if (r < 0)
@@ -376,12 +385,15 @@ static bool should_umount(Mount *m) {
 }
 
 static int mount_add_default_dependencies(Mount *m) {
-        const char *after, *after2, *online;
         MountParameters *p;
+        const char *after;
         int r;
 
         assert(m);
 
+        if (!UNIT(m)->default_dependencies)
+                return 0;
+
         if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
                 return 0;
 
@@ -402,30 +414,34 @@ static int mount_add_default_dependencies(Mount *m) {
                 return 0;
 
         if (mount_is_network(p)) {
-                after = SPECIAL_REMOTE_FS_PRE_TARGET;
-                after2 = SPECIAL_NETWORK_TARGET;
-                online = SPECIAL_NETWORK_ONLINE_TARGET;
-        } else {
-                after = SPECIAL_LOCAL_FS_PRE_TARGET;
-                after2 = NULL;
-                online = NULL;
-        }
-
-        r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
-        if (r < 0)
-                return r;
+                /* We order ourselves after network.target. This is
+                 * primarily useful at shutdown: services that take
+                 * down the network should order themselves before
+                 * network.target, so that they are shut down only
+                 * after this mount unit is stopped. */
 
-        if (after2) {
-                r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true);
+                r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
                 if (r < 0)
                         return r;
-        }
 
-        if (online) {
-                r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, online, NULL, true);
+                /* We pull in network-online.target, and order
+                 * ourselves after it. This is useful at start-up to
+                 * actively pull in tools that want to be started
+                 * before we start mounting network file systems, and
+                 * whose purpose it is to delay this until the network
+                 * is "up". */
+
+                r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
                 if (r < 0)
                         return r;
-        }
+
+                after = SPECIAL_REMOTE_FS_PRE_TARGET;
+        } else
+                after = SPECIAL_LOCAL_FS_PRE_TARGET;
+
+        r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
+        if (r < 0)
+                return r;
 
         if (should_umount(m)) {
                 r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
@@ -522,11 +538,9 @@ static int mount_add_extras(Mount *m) {
         if (r < 0)
                 return r;
 
-        if (u->default_dependencies) {
-                r = mount_add_default_dependencies(m);
-                if (r < 0)
-                        return r;
-        }
+        r = mount_add_default_dependencies(m);
+        if (r < 0)
+                return r;
 
         return 0;
 }
@@ -621,19 +635,19 @@ static int mount_coldplug(Unit *u) {
         if (new_state == m->state)
                 return 0;
 
-        if (new_state == MOUNT_MOUNTING ||
-            new_state == MOUNT_MOUNTING_DONE ||
-            new_state == MOUNT_REMOUNTING ||
-            new_state == MOUNT_UNMOUNTING ||
-            new_state == MOUNT_MOUNTING_SIGTERM ||
-            new_state == MOUNT_MOUNTING_SIGKILL ||
-            new_state == MOUNT_UNMOUNTING_SIGTERM ||
-            new_state == MOUNT_UNMOUNTING_SIGKILL ||
-            new_state == MOUNT_REMOUNTING_SIGTERM ||
-            new_state == MOUNT_REMOUNTING_SIGKILL) {
-
-                if (m->control_pid <= 0)
-                        return -EBADMSG;
+        if (m->control_pid > 0 &&
+            pid_is_unwaited(m->control_pid) &&
+            IN_SET(new_state,
+                   MOUNT_MOUNTING,
+                   MOUNT_MOUNTING_DONE,
+                   MOUNT_REMOUNTING,
+                   MOUNT_UNMOUNTING,
+                   MOUNT_MOUNTING_SIGTERM,
+                   MOUNT_MOUNTING_SIGKILL,
+                   MOUNT_UNMOUNTING_SIGTERM,
+                   MOUNT_UNMOUNTING_SIGKILL,
+                   MOUNT_REMOUNTING_SIGTERM,
+                   MOUNT_REMOUNTING_SIGKILL)) {
 
                 r = unit_watch_pid(UNIT(m), m->control_pid);
                 if (r < 0)
@@ -852,6 +866,11 @@ fail:
         mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
 }
 
+static int mount_get_opts(Mount *m, char **ret) {
+        return fstab_filter_options(m->parameters_fragment.options,
+                                    "nofail\0" "noauto\0" "auto\0", NULL, NULL, ret);
+}
+
 static void mount_enter_mounting(Mount *m) {
         int r;
         MountParameters *p;
@@ -877,8 +896,7 @@ static void mount_enter_mounting(Mount *m) {
         if (m->from_fragment) {
                 _cleanup_free_ char *opts = NULL;
 
-                r = fstab_filter_options(m->parameters_fragment.options,
-                                         "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
+                r = mount_get_opts(m, &opts);
                 if (r < 0)
                         goto fail;
 
@@ -1559,7 +1577,7 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) {
         return 1;
 }
 
-static int mount_enumerate(Manager *m) {
+static void mount_enumerate(Manager *m) {
         int r;
 
         assert(m);
@@ -1571,29 +1589,40 @@ static int mount_enumerate(Manager *m) {
 
                 m->mount_monitor = mnt_new_monitor();
                 if (!m->mount_monitor) {
-                        r = -ENOMEM;
+                        log_oom();
                         goto fail;
                 }
 
                 r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to enable watching of kernel mount events: %m");
                         goto fail;
+                }
+
                 r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to enable watching of userspace mount events: %m");
                         goto fail;
+                }
 
                 /* mnt_unref_monitor() will close the fd */
                 fd = r = mnt_monitor_get_fd(m->mount_monitor);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to acquire watch file descriptor: %m");
                         goto fail;
+                }
 
                 r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to watch mount file descriptor: %m");
                         goto fail;
+                }
 
                 r = sd_event_source_set_priority(m->mount_event_source, -10);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to adjust mount watch priority: %m");
                         goto fail;
+                }
 
                 (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
         }
@@ -1602,11 +1631,10 @@ static int mount_enumerate(Manager *m) {
         if (r < 0)
                 goto fail;
 
-        return 0;
+        return;
 
 fail:
         mount_shutdown(m);
-        return r;
 }
 
 static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
index 2b8b707df5e5bc24ca9e5d6aec7b821d23a99197..81ba09ea5ddf9166e493455ae030e9013a710d4a 100644 (file)
 ***/
 
 #include <errno.h>
-#include <sys/mount.h>
-#include <string.h>
+#include <sched.h>
 #include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
-#include <sched.h>
+#include <unistd.h>
 #include <linux/fs.h>
 
-#include "strv.h"
-#include "util.h"
-#include "path-util.h"
-#include "missing.h"
-#include "loopback-setup.h"
+#include "alloc-util.h"
 #include "dev-setup.h"
-#include "selinux-util.h"
-#include "namespace.h"
+#include "fd-util.h"
+#include "loopback-setup.h"
+#include "missing.h"
 #include "mkdir.h"
+#include "mount-util.h"
+#include "namespace.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "user-util.h"
+#include "util.h"
 
 typedef enum MountMode {
         /* This is ordered by priority! */
index 081ac2040d7531eff41337b114b9f1d59416b445..02fb134bb934361dbc20823dc430970c086f1c01 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/inotify.h>
-#include <sys/epoll.h>
 #include <errno.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
 #include <unistd.h>
 
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
+#include "bus-error.h"
+#include "bus-util.h"
 #include "dbus-path.h"
-#include "special.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
 #include "macro.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "mkdir.h"
+#include "path.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
 
 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
         [PATH_DEAD] = UNIT_INACTIVE,
@@ -309,20 +315,20 @@ static int path_add_default_dependencies(Path *p) {
 
         assert(p);
 
-        r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
-                                        SPECIAL_PATHS_TARGET, NULL, true);
+        if (!UNIT(p)->default_dependencies)
+                return 0;
+
+        r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true);
         if (r < 0)
                 return r;
 
         if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
-                r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
-                                                      SPECIAL_SYSINIT_TARGET, NULL, true);
+                r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
                 if (r < 0)
                         return r;
         }
 
-        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
-                                                 SPECIAL_SHUTDOWN_TARGET, NULL, true);
+        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
 }
 
 static int path_load(Unit *u) {
@@ -354,11 +360,9 @@ static int path_load(Unit *u) {
                 if (r < 0)
                         return r;
 
-                if (UNIT(p)->default_dependencies) {
-                        r = path_add_default_dependencies(p);
-                        if (r < 0)
-                                return r;
-                }
+                r = path_add_default_dependencies(p);
+                if (r < 0)
+                        return r;
         }
 
         return path_verify(p);
@@ -470,8 +474,7 @@ static void path_enter_running(Path *p) {
         if (unit_stop_pending(UNIT(p)))
                 return;
 
-        r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
-                            JOB_REPLACE, true, &error, NULL);
+        r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), JOB_REPLACE, &error, NULL);
         if (r < 0)
                 goto fail;
 
index ea7d846578bf10ce23ffb12c7a3743f0991e916f..5f6527c1551123c0f1449a739d1226efaa10f4ab 100644 (file)
 #include <errno.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "dbus-scope.h"
+#include "load-dropin.h"
 #include "log.h"
-#include "strv.h"
+#include "scope.h"
 #include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
 #include "unit-name.h"
 #include "unit.h"
-#include "scope.h"
-#include "dbus-scope.h"
-#include "load-dropin.h"
 
 static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
         [SCOPE_DEAD] = UNIT_INACTIVE,
@@ -51,7 +54,6 @@ static void scope_init(Unit *u) {
         s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
 
         UNIT(s)->ignore_on_isolate = true;
-        UNIT(s)->ignore_on_snapshot = true;
 }
 
 static void scope_done(Unit *u) {
@@ -120,6 +122,9 @@ static int scope_add_default_dependencies(Scope *s) {
 
         assert(s);
 
+        if (!UNIT(s)->default_dependencies)
+                return 0;
+
         /* Make sure scopes are unloaded on shutdown */
         r = unit_add_two_dependencies_by_name(
                         UNIT(s),
@@ -171,11 +176,9 @@ static int scope_load(Unit *u) {
         if (r < 0)
                 return r;
 
-        if (u->default_dependencies) {
-                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);
 }
@@ -507,7 +510,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) {
         return scope_state_to_string(SCOPE(u)->state);
 }
 
-static int scope_enumerate(Manager *m) {
+static void scope_enumerate(Manager *m) {
         Unit *u;
         int r;
 
@@ -521,13 +524,16 @@ static int scope_enumerate(Manager *m) {
         u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
         if (!u) {
                 u = unit_new(m, sizeof(Scope));
-                if (!u)
-                        return log_oom();
+                if (!u) {
+                        log_oom();
+                        return;
+                }
 
                 r = unit_add_name(u, SPECIAL_INIT_SCOPE);
                 if (r < 0)  {
                         unit_free(u);
-                        return log_error_errno(r, "Failed to add init.scope name");
+                        log_error_errno(r, "Failed to add init.scope name");
+                        return;
                 }
         }
 
@@ -548,8 +554,6 @@ static int scope_enumerate(Manager *m) {
 
         unit_add_to_load_queue(u);
         unit_add_to_dbus_queue(u);
-
-        return 0;
 }
 
 static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
index 40ca0c616635159c9a0e3c4516210725c56afae7..4bcdd273899d2080166dbbbb6c3cb1895c7f1612 100644 (file)
 #endif
 
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "audit-fd.h"
 #include "bus-util.h"
-#include "util.h"
 #include "log.h"
+#include "path-util.h"
 #include "selinux-util.h"
-#include "audit-fd.h"
+#include "stdio-util.h"
 #include "strv.h"
-#include "path-util.h"
+#include "util.h"
 
 static bool initialized = false;
 
@@ -178,17 +181,6 @@ static int mac_selinux_access_init(sd_bus_error *error) {
 }
 #endif
 
-void mac_selinux_access_free(void) {
-
-#ifdef HAVE_SELINUX
-        if (!initialized)
-                return;
-
-        avc_destroy();
-        initialized = false;
-#endif
-}
-
 /*
    This function communicates with the kernel to check whether or not it should
    allow the access.
index e6b4dd7feee04ae29ec8ca5bb852386c615f227a..30725521cb34d4a77a3def35410d2fb7aa1bd938 100644 (file)
@@ -25,8 +25,6 @@
 #include "bus-util.h"
 #include "manager.h"
 
-void mac_selinux_access_free(void);
-
 int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
 
 #ifdef HAVE_SELINUX
index ff1ea235288ec5880fc5fb56e878b15cde03109e..d9b00fb95c46fc54943a9a9559091a85988eb55b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
 
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 #endif
 
-#include "selinux-setup.h"
-#include "selinux-util.h"
+#include "log.h"
 #include "macro.h"
+#include "selinux-util.h"
+#include "string-util.h"
 #include "util.h"
-#include "log.h"
+#include "selinux-setup.h"
 
 #ifdef HAVE_SELINUX
 _printf_(2,3)
index 1e4f707bf4fef56c6327f87ff54f2948f93d4a7e..c27b70fa3ca208c9ab151db80a537991f6d386f4 100644 (file)
 #include <signal.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "async.h"
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
 #include "dbus-service.h"
-#include "special.h"
-#include "exit-status.h"
 #include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
 #include "env-util.h"
+#include "escape.h"
+#include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "manager.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "service.h"
 #include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "util.h"
 
 static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
         [SERVICE_DEAD] = UNIT_INACTIVE,
@@ -168,7 +175,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
         s->main_pid = pid;
         s->main_pid_known = true;
 
-        if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
+        if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) {
                 log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
                 s->main_pid_alien = true;
         } else
@@ -413,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
         }
 
         if (fdset_size(fds) > 0)
-                log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
+                log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
 
         return 0;
 }
@@ -508,15 +515,38 @@ static int service_add_default_dependencies(Service *s) {
 
         assert(s);
 
+        if (!UNIT(s)->default_dependencies)
+                return 0;
+
         /* Add a number of automatic dependencies useful for the
          * majority of services. */
 
-        /* First, pull in base system */
-        r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
+        if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+                /* First, pull in the really early boot stuff, and
+                 * require it, so that we fail if we can't acquire
+                 * it. */
+
+                r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+                if (r < 0)
+                        return r;
+        } else {
+
+                /* In the --user instance there's no sysinit.target,
+                 * in that case require basic.target instead. */
+
+                r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
+                if (r < 0)
+                        return r;
+        }
+
+        /* Second, if the rest of the base system is in the same
+         * transaction, order us after it, but do not pull it in or
+         * even require it. */
+        r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true);
         if (r < 0)
                 return r;
 
-        /* Second, activate normal shutdown */
+        /* Third, add us in for normal shutdown. */
         return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
 }
 
@@ -538,6 +568,43 @@ static void service_fix_output(Service *s) {
                 s->exec_context.std_output = UNIT(s)->manager->default_std_output;
 }
 
+static int service_setup_bus_name(Service *s) {
+        int r;
+
+        assert(s);
+
+        if (!s->bus_name)
+                return 0;
+
+        if (is_kdbus_available()) {
+                const char *n;
+
+                n = strjoina(s->bus_name, ".busname");
+                r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
+                if (r < 0)
+                        return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m");
+
+        } else {
+                /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */
+                r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true);
+                if (r < 0)
+                        return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
+        }
+
+        /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */
+        r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
+        if (r < 0)
+                return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
+
+        r = unit_watch_bus_name(UNIT(s), s->bus_name);
+        if (r == -EEXIST)
+                return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
+        if (r < 0)
+                return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
+
+        return 0;
+}
+
 static int service_add_extras(Service *s) {
         int r;
 
@@ -577,26 +644,13 @@ static int service_add_extras(Service *s) {
         if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
                 s->notify_access = NOTIFY_MAIN;
 
-        if (s->bus_name) {
-                const char *n;
-
-                n = strjoina(s->bus_name, ".busname");
-                r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
-                if (r < 0)
-                        return r;
-
-                r = unit_watch_bus_name(UNIT(s), s->bus_name);
-                if (r == -EEXIST)
-                        return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
-                if (r < 0)
-                        return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
-        }
+        r = service_add_default_dependencies(s);
+        if (r < 0)
+                return r;
 
-        if (UNIT(s)->default_dependencies) {
-                r = service_add_default_dependencies(s);
-                if (r < 0)
-                        return r;
-        }
+        r = service_setup_bus_name(s);
+        if (r < 0)
+                return r;
 
         return 0;
 }
@@ -905,66 +959,67 @@ static int service_coldplug(Unit *u) {
         assert(s);
         assert(s->state == SERVICE_DEAD);
 
-        if (s->deserialized_state != s->state) {
-
-                if (IN_SET(s->deserialized_state,
-                           SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
-                           SERVICE_RELOAD,
-                           SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                           SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-
-                        usec_t k;
-
-                        k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
+        if (s->deserialized_state == s->state)
+                return 0;
 
-                        /* For the start/stop timeouts 0 means off */
-                        if (k > 0) {
-                                r = service_arm_timer(s, k);
-                                if (r < 0)
-                                        return r;
-                        }
-                }
+        if (IN_SET(s->deserialized_state,
+                   SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+                   SERVICE_RELOAD,
+                   SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
 
-                if (s->deserialized_state == SERVICE_AUTO_RESTART) {
+                usec_t k;
 
-                        /* The restart timeouts 0 means immediately */
-                        r = service_arm_timer(s, s->restart_usec);
-                        if (r < 0)
-                                return r;
-                }
+                k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
 
-                if (pid_is_unwaited(s->main_pid) &&
-                    ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
-                     IN_SET(s->deserialized_state,
-                            SERVICE_START, SERVICE_START_POST,
-                            SERVICE_RUNNING, SERVICE_RELOAD,
-                            SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                            SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
-                        r = unit_watch_pid(UNIT(s), s->main_pid);
+                /* For the start/stop timeouts 0 means off */
+                if (k > 0) {
+                        r = service_arm_timer(s, k);
                         if (r < 0)
                                 return r;
                 }
+        }
 
-                if (pid_is_unwaited(s->control_pid) &&
-                    IN_SET(s->deserialized_state,
-                           SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
-                           SERVICE_RELOAD,
-                           SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
-                           SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-                        r = unit_watch_pid(UNIT(s), s->control_pid);
-                        if (r < 0)
-                                return r;
-                }
+        if (s->deserialized_state == SERVICE_AUTO_RESTART) {
 
-                if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
-                        unit_watch_all_pids(UNIT(s));
+                /* The restart timeouts 0 means immediately */
+                r = service_arm_timer(s, s->restart_usec);
+                if (r < 0)
+                        return r;
+        }
 
-                if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
-                        service_start_watchdog(s);
+        if (s->main_pid > 0 &&
+            pid_is_unwaited(s->main_pid) &&
+            ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
+             IN_SET(s->deserialized_state,
+                    SERVICE_START, SERVICE_START_POST,
+                    SERVICE_RUNNING, SERVICE_RELOAD,
+                    SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+                r = unit_watch_pid(UNIT(s), s->main_pid);
+                if (r < 0)
+                        return r;
+        }
 
-                service_set_state(s, s->deserialized_state);
+        if (s->control_pid > 0 &&
+            pid_is_unwaited(s->control_pid) &&
+            IN_SET(s->deserialized_state,
+                   SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+                   SERVICE_RELOAD,
+                   SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+                   SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+                r = unit_watch_pid(UNIT(s), s->control_pid);
+                if (r < 0)
+                        return r;
         }
 
+        if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+                unit_watch_all_pids(UNIT(s));
+
+        if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+                service_start_watchdog(s);
+
+        service_set_state(s, s->deserialized_state);
         return 0;
 }
 
@@ -1215,7 +1270,7 @@ static int service_spawn(
 
         if (is_control && UNIT(s)->cgroup_path) {
                 path = strjoina(UNIT(s)->cgroup_path, "/control");
-                cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+                (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
         } else
                 path = UNIT(s)->cgroup_path;
 
@@ -1794,7 +1849,7 @@ static void service_enter_restart(Service *s) {
          * restarted. We use JOB_RESTART (instead of the more obvious
          * JOB_START) here so that those dependency jobs will be added
          * as well. */
-        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL);
+        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL);
         if (r < 0)
                 goto fail;
 
@@ -2357,14 +2412,6 @@ static bool service_check_gc(Unit *u) {
         return false;
 }
 
-_pure_ static bool service_check_snapshot(Unit *u) {
-        Service *s = SERVICE(u);
-
-        assert(s);
-
-        return s->socket_fd < 0;
-}
-
 static int service_retry_pid_file(Service *s) {
         int r;
 
@@ -3286,7 +3333,6 @@ const UnitVTable service_vtable = {
         .sub_state_to_string = service_sub_state_to_string,
 
         .check_gc = service_check_gc,
-        .check_snapshot = service_check_snapshot,
 
         .sigchld_event = service_sigchld_event,
 
index 02b1be73e32eb61982216192c46708554c56b500..e4e12a33650c01aa34a42c98a07a98c5baad78a3 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "parse-util.h"
 #include "show-status.h"
+#include "string-util.h"
+#include "terminal-util.h"
 #include "util.h"
 
 int parse_show_status(const char *v, ShowStatus *ret) {
@@ -40,3 +46,81 @@ int parse_show_status(const char *v, ShowStatus *ret) {
         *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
         return 0;
 }
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
+        static const char status_indent[] = "         "; /* "[" STATUS "] " */
+        _cleanup_free_ char *s = NULL;
+        _cleanup_close_ int fd = -1;
+        struct iovec iovec[6] = {};
+        int n = 0;
+        static bool prev_ephemeral;
+
+        assert(format);
+
+        /* This is independent of logging, as status messages are
+         * optional and go exclusively to the console. */
+
+        if (vasprintf(&s, format, ap) < 0)
+                return log_oom();
+
+        fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+        if (fd < 0)
+                return fd;
+
+        if (ellipse) {
+                char *e;
+                size_t emax, sl;
+                int c;
+
+                c = fd_columns(fd);
+                if (c <= 0)
+                        c = 80;
+
+                sl = status ? sizeof(status_indent)-1 : 0;
+
+                emax = c - sl - 1;
+                if (emax < 3)
+                        emax = 3;
+
+                e = ellipsize(s, emax, 50);
+                if (e) {
+                        free(s);
+                        s = e;
+                }
+        }
+
+        if (prev_ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+        prev_ephemeral = ephemeral;
+
+        if (status) {
+                if (!isempty(status)) {
+                        IOVEC_SET_STRING(iovec[n++], "[");
+                        IOVEC_SET_STRING(iovec[n++], status);
+                        IOVEC_SET_STRING(iovec[n++], "] ");
+                } else
+                        IOVEC_SET_STRING(iovec[n++], status_indent);
+        }
+
+        IOVEC_SET_STRING(iovec[n++], s);
+        if (!ephemeral)
+                IOVEC_SET_STRING(iovec[n++], "\n");
+
+        if (writev(fd, iovec, n) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
+        va_list ap;
+        int r;
+
+        assert(format);
+
+        va_start(ap, format);
+        r = status_vprintf(status, ellipse, ephemeral, format, ap);
+        va_end(ap);
+
+        return r;
+}
index a2b2153746c997380a284a2e2be02a8968e966eb..c79d4acb66bc605727abbea93176925458954977 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdbool.h>
+
+#include "macro.h"
+
 /* Manager status */
 
 typedef enum ShowStatus {
@@ -32,3 +36,6 @@ typedef enum ShowStatus {
 } ShowStatus;
 
 int parse_show_status(const char *v, ShowStatus *ret);
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
index 27c581d9c10ca2ef57b51c4d55b80860a2cdc4ef..3a95b5fd72c859a5d31f3b6199dc780556acf885 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/mman.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
 #include <errno.h>
-#include <unistd.h>
+#include <getopt.h>
+#include <linux/reboot.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <stdlib.h>
-#include <getopt.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-#include "missing.h"
-#include "log.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "def.h"
 #include "fileio.h"
+#include "killall.h"
+#include "log.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
+#include "switch-root.h"
+#include "terminal-util.h"
 #include "umount.h"
 #include "util.h"
 #include "virt.h"
 #include "watchdog.h"
-#include "killall.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "switch-root.h"
-#include "process-util.h"
-#include "terminal-util.h"
 
 #define FINALIZE_ATTEMPTS 50
 
index 1542e83eb6b468e0fef2ecb797083aa06f04b6e5..39dabae05545681ebc256572d1bd6ebb365fd31b 100644 (file)
 
 #include <errno.h>
 
+#include "alloc-util.h"
+#include "dbus-slice.h"
 #include "log.h"
-#include "strv.h"
 #include "special.h"
+#include "string-util.h"
+#include "strv.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "slice.h"
-#include "dbus-slice.h"
 
 static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
         [SLICE_DEAD] = UNIT_INACTIVE,
@@ -83,6 +85,9 @@ static int slice_add_default_dependencies(Slice *s) {
 
         assert(s);
 
+        if (!UNIT(s)->default_dependencies)
+                return 0;
+
         /* Make sure slices are unloaded on shutdown */
         r = unit_add_two_dependencies_by_name(
                         UNIT(s),
@@ -94,7 +99,6 @@ static int slice_add_default_dependencies(Slice *s) {
         return 0;
 }
 
-
 static int slice_verify(Slice *s) {
         _cleanup_free_ char *parent = NULL;
         int r;
@@ -142,11 +146,9 @@ static int slice_load(Unit *u) {
                 if (r < 0)
                         return r;
 
-                if (u->default_dependencies) {
-                        r = slice_add_default_dependencies(s);
-                        if (r < 0)
-                                return r;
-                }
+                r = slice_add_default_dependencies(s);
+                if (r < 0)
+                        return r;
         }
 
         return slice_verify(s);
@@ -253,7 +255,7 @@ _pure_ static const char *slice_sub_state_to_string(Unit *u) {
         return slice_state_to_string(SLICE(u)->state);
 }
 
-static int slice_enumerate(Manager *m) {
+static void slice_enumerate(Manager *m) {
         Unit *u;
         int r;
 
@@ -262,13 +264,16 @@ static int slice_enumerate(Manager *m) {
         u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
         if (!u) {
                 u = unit_new(m, sizeof(Slice));
-                if (!u)
-                        return log_oom();
+                if (!u)  {
+                        log_oom();
+                        return;
+                }
 
                 r = unit_add_name(u, SPECIAL_ROOT_SLICE);
                 if (r < 0) {
                         unit_free(u);
-                        return log_error_errno(r, "Failed to add -.slice name");
+                        log_error_errno(r, "Failed to add -.slice name");
+                        return;
                 }
         }
 
@@ -286,8 +291,6 @@ static int slice_enumerate(Manager *m) {
 
         unit_add_to_load_queue(u);
         unit_add_to_dbus_queue(u);
-
-        return 0;
 }
 
 const UnitVTable slice_vtable = {
index 761582c7a2d847e3e637527a34ec118078b76cbf..0661ff9ecd5214f95010c21c3d73d4b6727e1fca 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
+#include <dirent.h>
 #include <errno.h>
-#include <string.h>
-#include <stdlib.h>
 #include <fcntl.h>
-#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
 #include "macro.h"
 #include "smack-setup.h"
+#include "string-util.h"
 #include "util.h"
-#include "fileio.h"
-#include "log.h"
 
 #ifdef HAVE_SMACK
 
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
deleted file mode 100644 (file)
index 867f376..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright 2010 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 <errno.h>
-
-#include "unit.h"
-#include "snapshot.h"
-#include "unit-name.h"
-#include "dbus-snapshot.h"
-#include "bus-common-errors.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
-        [SNAPSHOT_DEAD] = UNIT_INACTIVE,
-        [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_init(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(UNIT(s)->load_state == UNIT_STUB);
-
-        UNIT(s)->ignore_on_isolate = true;
-        UNIT(s)->ignore_on_snapshot = true;
-        UNIT(s)->allow_isolate = true;
-}
-
-static void snapshot_set_state(Snapshot *s, SnapshotState state) {
-        SnapshotState old_state;
-        assert(s);
-
-        old_state = s->state;
-        s->state = state;
-
-        if (state != old_state)
-                log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
-
-        unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int snapshot_load(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(u);
-        assert(u->load_state == UNIT_STUB);
-
-        /* Make sure that only snapshots created via snapshot_create()
-         * can be loaded */
-        if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
-                return -ENOENT;
-
-        u->load_state = UNIT_LOADED;
-        return 0;
-}
-
-static int snapshot_coldplug(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_DEAD);
-
-        if (s->deserialized_state != s->state)
-                snapshot_set_state(s, s->deserialized_state);
-
-        return 0;
-}
-
-static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(f);
-
-        fprintf(f,
-                "%sSnapshot State: %s\n"
-                "%sClean Up: %s\n",
-                prefix, snapshot_state_to_string(s->state),
-                prefix, yes_no(s->cleanup));
-}
-
-static int snapshot_start(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_DEAD);
-
-        snapshot_set_state(s, SNAPSHOT_ACTIVE);
-
-        if (s->cleanup)
-                unit_add_to_cleanup_queue(u);
-
-        return 1;
-}
-
-static int snapshot_stop(Unit *u) {
-        Snapshot *s = SNAPSHOT(u);
-
-        assert(s);
-        assert(s->state == SNAPSHOT_ACTIVE);
-
-        snapshot_set_state(s, SNAPSHOT_DEAD);
-        return 1;
-}
-
-static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
-        Snapshot *s = SNAPSHOT(u);
-        Unit *other;
-        Iterator i;
-
-        assert(s);
-        assert(f);
-        assert(fds);
-
-        unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
-        unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
-        SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
-                unit_serialize_item(u, f, "wants", other->id);
-
-        return 0;
-}
-
-static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
-        Snapshot *s = SNAPSHOT(u);
-        int r;
-
-        assert(u);
-        assert(key);
-        assert(value);
-        assert(fds);
-
-        if (streq(key, "state")) {
-                SnapshotState state;
-
-                state = snapshot_state_from_string(value);
-                if (state < 0)
-                        log_unit_debug(u, "Failed to parse state value: %s", value);
-                else
-                        s->deserialized_state = state;
-
-        } else if (streq(key, "cleanup")) {
-
-                r = parse_boolean(value);
-                if (r < 0)
-                        log_unit_debug(u, "Failed to parse cleanup value: %s", value);
-                else
-                        s->cleanup = r;
-
-        } else if (streq(key, "wants")) {
-
-                r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
-                if (r < 0)
-                        return r;
-        } else
-                log_unit_debug(u, "Unknown serialization key: %s", key);
-
-        return 0;
-}
-
-_pure_ static UnitActiveState snapshot_active_state(Unit *u) {
-        assert(u);
-
-        return state_translation_table[SNAPSHOT(u)->state];
-}
-
-_pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
-        assert(u);
-
-        return snapshot_state_to_string(SNAPSHOT(u)->state);
-}
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
-        _cleanup_free_ char *n = NULL;
-        Unit *other, *u = NULL;
-        Iterator i;
-        int r;
-        const char *k;
-
-        assert(m);
-        assert(_s);
-
-        if (name) {
-                if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
-                        return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
-
-                if (!endswith(name, ".snapshot"))
-                        return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
-
-                if (manager_get_unit(m, name))
-                        return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
-
-        } else {
-
-                for (;;) {
-                        if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
-                                return -ENOMEM;
-
-                        if (!manager_get_unit(m, n)) {
-                                name = n;
-                                break;
-                        }
-
-                        n = mfree(n);
-                }
-        }
-
-        r = manager_load_unit_prepare(m, name, NULL, e, &u);
-        if (r < 0)
-                goto fail;
-
-        u->transient = true;
-        manager_dispatch_load_queue(m);
-        assert(u->load_state == UNIT_LOADED);
-
-        HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
-                if (other->ignore_on_snapshot ||
-                    other->transient)
-                        continue;
-
-                if (k != other->id)
-                        continue;
-
-                if (UNIT_VTABLE(other)->check_snapshot)
-                        if (!UNIT_VTABLE(other)->check_snapshot(other))
-                            continue;
-
-                if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        continue;
-
-                r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
-                if (r < 0)
-                        goto fail;
-        }
-
-        SNAPSHOT(u)->cleanup = cleanup;
-        *_s = SNAPSHOT(u);
-
-        log_unit_info(u, "Created snapshot.");
-
-        return 0;
-
-fail:
-        if (u)
-                unit_add_to_cleanup_queue(u);
-
-        return r;
-}
-
-void snapshot_remove(Snapshot *s) {
-        assert(s);
-
-        log_unit_info(UNIT(s), "Removing snapshot.");
-
-        unit_add_to_cleanup_queue(UNIT(s));
-}
-
-const UnitVTable snapshot_vtable = {
-        .object_size = sizeof(Snapshot),
-
-        .no_alias = true,
-        .no_instances = true,
-        .no_gc = true,
-
-        .init = snapshot_init,
-        .load = snapshot_load,
-
-        .coldplug = snapshot_coldplug,
-
-        .dump = snapshot_dump,
-
-        .start = snapshot_start,
-        .stop = snapshot_stop,
-
-        .serialize = snapshot_serialize,
-        .deserialize_item = snapshot_deserialize_item,
-
-        .active_state = snapshot_active_state,
-        .sub_state_to_string = snapshot_sub_state_to_string,
-
-        .bus_vtable = bus_snapshot_vtable
-};
index e42ed62ef1a88e23e83d758867b8d6431fb261c1..5b9e32ce9dc98ab8875fa48c17b3363a31e5a989 100644 (file)
 
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "copy.h"
 #include "dbus-socket.h"
 #include "def.h"
 #include "exit-status.h"
+#include "fd-util.h"
 #include "formats-util.h"
 #include "label.h"
 #include "log.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
 #include "smack-util.h"
 #include "socket.h"
 #include "special.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
 #include "unit-printf.h"
 #include "unit.h"
+#include "user-util.h"
 
 static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = UNIT_INACTIVE,
@@ -107,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) {
 }
 
 static void socket_cleanup_fd_list(SocketPort *p) {
-        int k = p->n_auxiliary_fds;
-
-        while (k--)
-                safe_close(p->auxiliary_fds[k]);
+        assert(p);
 
+        close_many(p->auxiliary_fds, p->n_auxiliary_fds);
         p->auxiliary_fds = mfree(p->auxiliary_fds);
         p->n_auxiliary_fds = 0;
 }
@@ -291,6 +296,9 @@ static int socket_add_default_dependencies(Socket *s) {
         int r;
         assert(s);
 
+        if (!UNIT(s)->default_dependencies)
+                return 0;
+
         r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true);
         if (r < 0)
                 return r;
@@ -360,11 +368,9 @@ static int socket_add_extras(Socket *s) {
                         return r;
         }
 
-        if (u->default_dependencies) {
-                r = socket_add_default_dependencies(s);
-                if (r < 0)
-                        return r;
-        }
+        r = socket_add_default_dependencies(s);
+        if (r < 0)
+                return r;
 
         return 0;
 }
@@ -1167,9 +1173,9 @@ static int usbffs_dispatch_eps(SocketPort *p) {
         _cleanup_free_ char *path = NULL;
         int r, i, n, k;
 
-        r = path_get_parent(p->path, &path);
-        if (r < 0)
-                return r;
+        path = dirname_malloc(p->path);
+        if (!path)
+                return -ENOMEM;
 
         r = scandir(path, &ent, usbffs_select_ep, alphasort);
         if (r < 0)
@@ -1450,7 +1456,9 @@ static int socket_coldplug(Unit *u) {
         if (s->deserialized_state == s->state)
                 return 0;
 
-        if (IN_SET(s->deserialized_state,
+        if (s->control_pid > 0 &&
+            pid_is_unwaited(s->control_pid) &&
+            IN_SET(s->deserialized_state,
                    SOCKET_START_PRE,
                    SOCKET_START_CHOWN,
                    SOCKET_START_POST,
@@ -1461,9 +1469,6 @@ static int socket_coldplug(Unit *u) {
                    SOCKET_FINAL_SIGTERM,
                    SOCKET_FINAL_SIGKILL)) {
 
-                if (s->control_pid <= 0)
-                        return -EBADMSG;
-
                 r = unit_watch_pid(UNIT(s), s->control_pid);
                 if (r < 0)
                         return r;
@@ -1916,7 +1921,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                                 goto fail;
                         }
 
-                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
+                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
                         if (r < 0)
                                 goto fail;
                 }
@@ -1974,7 +1979,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                 cfd = -1;
                 s->n_connections ++;
 
-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
+                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
                 if (r < 0)
                         goto fail;
 
@@ -2328,7 +2333,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
         return 0;
 }
 
-static int socket_distribute_fds(Unit *u, FDSet *fds) {
+static void socket_distribute_fds(Unit *u, FDSet *fds) {
         Socket *s = SOCKET(u);
         SocketPort *p;
 
@@ -2352,8 +2357,6 @@ static int socket_distribute_fds(Unit *u, FDSet *fds) {
                         }
                 }
         }
-
-        return 0;
 }
 
 _pure_ static UnitActiveState socket_active_state(Unit *u) {
index f42d151075788d98920ed76b68efb87b39afaf21..ee0838e6762faf7a3435c3b5b9824b9cf90d9409 100644 (file)
 ***/
 
 #include <errno.h>
-#include <unistd.h>
 #include <sys/epoll.h>
 #include <sys/stat.h>
-#include <libudev.h>
+#include <unistd.h>
 
-#include "unit.h"
-#include "swap.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
 #include "dbus-swap.h"
-#include "special.h"
+#include "escape.h"
 #include "exit-status.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "fstab-util.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "virt.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "swap.h"
 #include "udev-util.h"
-#include "fstab-util.h"
-#include "formats-util.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "virt.h"
 
 static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
         [SWAP_DEAD] = UNIT_INACTIVE,
@@ -205,6 +213,9 @@ static int swap_add_device_links(Swap *s) {
 static int swap_add_default_dependencies(Swap *s) {
         assert(s);
 
+        if (!UNIT(s)->default_dependencies)
+                return 0;
+
         if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
                 return 0;
 
@@ -323,11 +334,9 @@ static int swap_load(Unit *u) {
                 if (r < 0)
                         return r;
 
-                if (UNIT(s)->default_dependencies) {
-                        r = swap_add_default_dependencies(s);
-                        if (r < 0)
-                                return r;
-                }
+                r = swap_add_default_dependencies(s);
+                if (r < 0)
+                        return r;
         }
 
         return swap_verify(s);
@@ -520,16 +529,16 @@ static int swap_coldplug(Unit *u) {
         if (new_state == s->state)
                 return 0;
 
-        if (new_state == SWAP_ACTIVATING ||
-            new_state == SWAP_ACTIVATING_SIGTERM ||
-            new_state == SWAP_ACTIVATING_SIGKILL ||
-            new_state == SWAP_ACTIVATING_DONE ||
-            new_state == SWAP_DEACTIVATING ||
-            new_state == SWAP_DEACTIVATING_SIGTERM ||
-            new_state == SWAP_DEACTIVATING_SIGKILL) {
-
-                if (s->control_pid <= 0)
-                        return -EBADMSG;
+        if (s->control_pid > 0 &&
+            pid_is_unwaited(s->control_pid) &&
+            IN_SET(new_state,
+                   SWAP_ACTIVATING,
+                   SWAP_ACTIVATING_SIGTERM,
+                   SWAP_ACTIVATING_SIGKILL,
+                   SWAP_ACTIVATING_DONE,
+                   SWAP_DEACTIVATING,
+                   SWAP_DEACTIVATING_SIGTERM,
+                   SWAP_DEACTIVATING_SIGKILL)) {
 
                 r = unit_watch_pid(UNIT(s), s->control_pid);
                 if (r < 0)
@@ -1198,7 +1207,7 @@ static Unit *swap_following(Unit *u) {
                 if (other->from_fragment)
                         return UNIT(other);
 
-        /* Otherwise make everybody follow the unit that's named after
+        /* Otherwise, make everybody follow the unit that's named after
          * the swap device in the kernel */
 
         if (streq_ptr(s->what, s->devnode))
@@ -1260,26 +1269,36 @@ static void swap_shutdown(Manager *m) {
         m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
 }
 
-static int swap_enumerate(Manager *m) {
+static void swap_enumerate(Manager *m) {
         int r;
 
         assert(m);
 
         if (!m->proc_swaps) {
                 m->proc_swaps = fopen("/proc/swaps", "re");
-                if (!m->proc_swaps)
-                        return errno == ENOENT ? 0 : -errno;
+                if (!m->proc_swaps) {
+                        if (errno == ENOENT)
+                                log_debug("Not swap enabled, skipping enumeration");
+                        else
+                                log_error_errno(errno, "Failed to open /proc/swaps: %m");
+
+                        return;
+                }
 
                 r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to watch /proc/swaps: %m");
                         goto fail;
+                }
 
                 /* Dispatch this before we dispatch SIGCHLD, so that
                  * we always get the events from /proc/swaps before
                  * the SIGCHLD of /sbin/swapon. */
                 r = sd_event_source_set_priority(m->swap_event_source, -10);
-                if (r < 0)
+                if (r < 0) {
+                        log_error_errno(r, "Failed to change /proc/swaps priority: %m");
                         goto fail;
+                }
 
                 (void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
         }
@@ -1288,11 +1307,10 @@ static int swap_enumerate(Manager *m) {
         if (r < 0)
                 goto fail;
 
-        return 0;
+        return;
 
 fail:
         swap_shutdown(m);
-        return r;
 }
 
 int swap_process_device_new(Manager *m, struct udev_device *dev) {
index 7f29603c32ddc9c54d867282802281c2cf029ce4..303b926568298efbabea55b61a66beb21edd094c 100644 (file)
@@ -22,7 +22,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <libudev.h>
+#include "libudev.h"
 
 typedef struct Swap Swap;
 
index a905a1adf600c6d493fab626b071caf84de6ae47..14f9b2e26a56dc72b3c5f6a691fa9148ae01d404 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
-#include "unit.h"
-#include "target.h"
-#include "log.h"
 #include "dbus-target.h"
+#include "log.h"
 #include "special.h"
+#include "string-util.h"
 #include "unit-name.h"
+#include "unit.h"
+#include "target.h"
 
 static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
         [TARGET_DEAD] = UNIT_INACTIVE,
@@ -52,9 +52,7 @@ static int target_add_default_dependencies(Target *t) {
 
         static const UnitDependency deps[] = {
                 UNIT_REQUIRES,
-                UNIT_REQUIRES_OVERRIDABLE,
                 UNIT_REQUISITE,
-                UNIT_REQUISITE_OVERRIDABLE,
                 UNIT_WANTS,
                 UNIT_BINDS_TO,
                 UNIT_PART_OF
index 800e58261ccc2266610d9129d73d3037f11cfdc8..51b1d875beee1a977665ba1e5e447de235676de7 100644 (file)
 
 #include <errno.h>
 
-#include "unit.h"
-#include "unit-name.h"
-#include "timer.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
 #include "dbus-timer.h"
+#include "fs-util.h"
+#include "parse-util.h"
 #include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "timer.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "user-util.h"
+#include "virt.h"
 
 static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
         [TIMER_DEAD] = UNIT_INACTIVE,
@@ -95,6 +102,9 @@ static int timer_add_default_dependencies(Timer *t) {
 
         assert(t);
 
+        if (!UNIT(t)->default_dependencies)
+                return 0;
+
         r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
         if (r < 0)
                 return r;
@@ -185,11 +195,9 @@ static int timer_load(Unit *u) {
                 if (r < 0)
                         return r;
 
-                if (u->default_dependencies) {
-                        r = timer_add_default_dependencies(t);
-                        if (r < 0)
-                                return r;
-                }
+                r = timer_add_default_dependencies(t);
+                if (r < 0)
+                        return r;
         }
 
         return timer_verify(t);
@@ -353,10 +361,14 @@ static void timer_enter_waiting(Timer *t, bool initial) {
                                 break;
 
                         case TIMER_BOOT:
-                                /* CLOCK_MONOTONIC equals the uptime on Linux */
-                                base = 0;
-                                break;
-
+                                if (detect_container() <= 0) {
+                                        /* CLOCK_MONOTONIC equals the uptime on Linux */
+                                        base = 0;
+                                        break;
+                                }
+                                /* In a container we don't want to include the time the host
+                                 * was already up when the container started, so count from
+                                 * our own startup. Fall through. */
                         case TIMER_STARTUP:
                                 base = UNIT(t)->manager->userspace_timestamp.monotonic;
                                 break;
@@ -499,15 +511,14 @@ static void timer_enter_running(Timer *t) {
         if (unit_stop_pending(UNIT(t)))
                 return;
 
-        r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
-                            JOB_REPLACE, true, &error, NULL);
+        r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), JOB_REPLACE, &error, NULL);
         if (r < 0)
                 goto fail;
 
         dual_timestamp_get(&t->last_trigger);
 
         if (t->stamp_path)
-                touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
+                touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
 
         timer_set_state(t, TIMER_RUNNING);
         return;
@@ -543,7 +554,7 @@ static int timer_start(Unit *u) {
                         /* The timer has never run before,
                          * make sure a stamp file exists.
                          */
-                        touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
+                        touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
         }
 
         t->result = TIMER_SUCCESS;
index d1c1b9a3cd3320ad0caf6a3f669fa4c50d15040d..cf37b5eb7505bc3126474ca37bc4c01001500656 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
+#include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
-#include "transaction.h"
 #include "terminal-util.h"
+#include "transaction.h"
 
 static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
 
@@ -98,9 +99,7 @@ static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other
 
         j->type = t;
         j->state = JOB_WAITING;
-        j->override = j->override || other->override;
         j->irreversible = j->irreversible || other->irreversible;
-
         j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
 
         /* Patch us in as new owner of the JobDependency objects */
@@ -744,7 +743,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
         return 0;
 }
 
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
+static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool *is_new) {
         Job *j, *f;
 
         assert(tr);
@@ -773,7 +772,6 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b
         j->generation = 0;
         j->marker = NULL;
         j->matters_to_anchor = false;
-        j->override = override;
         j->irreversible = tr->irreversible;
 
         LIST_PREPEND(transaction, f, j);
@@ -832,7 +830,6 @@ int transaction_add_job_and_dependencies(
                 Unit *unit,
                 Job *by,
                 bool matters,
-                bool override,
                 bool conflicts,
                 bool ignore_requirements,
                 bool ignore_order,
@@ -894,7 +891,7 @@ int transaction_add_job_and_dependencies(
 
 
         /* First add the job. */
-        ret = transaction_add_one_job(tr, type, unit, override, &is_new);
+        ret = transaction_add_one_job(tr, type, unit, &is_new);
         if (!ret)
                 return -ENOMEM;
 
@@ -917,7 +914,7 @@ int transaction_add_job_and_dependencies(
                  * add all dependencies of everybody following. */
                 if (unit_following_set(ret->unit, &following) > 0) {
                         SET_FOREACH(dep, following, i) {
-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
                                         sd_bus_error_free(e);
@@ -930,7 +927,7 @@ int transaction_add_job_and_dependencies(
                 /* Finally, recursively add in all dependencies. */
                 if (type == JOB_START || type == JOB_RESTART) {
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -940,7 +937,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -949,19 +946,8 @@ int transaction_add_job_and_dependencies(
                                 }
                         }
 
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
-                                if (r < 0) {
-                                        log_unit_full(dep,
-                                                      r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
-                                                      "Cannot add dependency job, ignoring: %s",
-                                                      bus_error_message(e, r));
-                                        sd_bus_error_free(e);
-                                }
-                        }
-
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_unit_full(dep,
                                                       r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
@@ -972,7 +958,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -981,19 +967,8 @@ int transaction_add_job_and_dependencies(
                                 }
                         }
 
-                        SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
-                                if (r < 0) {
-                                        log_unit_full(dep,
-                                                      r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
-                                                      "Cannot add dependency job, ignoring: %s",
-                                                      bus_error_message(e, r));
-                                        sd_bus_error_free(e);
-                                }
-                        }
-
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1003,7 +978,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_unit_warning(dep,
                                                          "Cannot add dependency job, ignoring: %s",
@@ -1038,7 +1013,7 @@ int transaction_add_job_and_dependencies(
                                         if (nt == JOB_NOP)
                                                 continue;
 
-                                        r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
+                                        r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e);
                                         if (r < 0) {
                                                 if (r != -EBADR)
                                                         goto fail;
@@ -1051,7 +1026,7 @@ int transaction_add_job_and_dependencies(
                 if (type == JOB_RELOAD) {
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_unit_warning(dep,
                                                          "Cannot add dependency reload job, ignoring: %s",
@@ -1096,7 +1071,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
                 if (hashmap_get(tr->jobs, u))
                         continue;
 
-                r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
+                r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, NULL);
                 if (r < 0)
                         log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
         }
index d949b21b8d42e63b4b13f5c45fa8e23893f813e2..f7aa3df085e2008f9b7fd498ebb0769977fc44b3 100644 (file)
@@ -44,7 +44,6 @@ int transaction_add_job_and_dependencies(
                 Unit *unit,
                 Job *by,
                 bool matters,
-                bool override,
                 bool conflicts,
                 bool ignore_requirements,
                 bool ignore_order,
index 22dbe67259acd5fe498a4aa34ee768c7752df0ee..9d1f7660db7bc11569cb87b2b9886775a305f4fd 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/dm-ioctl.h>
+#include <linux/loop.h>
 #include <string.h>
 #include <sys/mount.h>
 #include <sys/swap.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
 
+#include "libudev.h"
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fstab-util.h"
 #include "list.h"
 #include "mount-setup.h"
-#include "umount.h"
 #include "path-util.h"
+#include "string-util.h"
+#include "udev-util.h"
+#include "umount.h"
 #include "util.h"
 #include "virt.h"
-#include "libudev.h"
-#include "udev-util.h"
 
 typedef struct MountPoint {
         char *path;
+        char *options;
         dev_t devnum;
         LIST_FIELDS(struct MountPoint, mount_point);
 } MountPoint;
@@ -71,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) {
                 return -errno;
 
         for (i = 1;; i++) {
-                _cleanup_free_ char *path = NULL;
+                _cleanup_free_ char *path = NULL, *options = NULL;
                 char *p = NULL;
                 MountPoint *m;
                 int k;
@@ -82,15 +89,15 @@ static int mount_points_list_get(MountPoint **head) {
                            "%*s "       /* (3) major:minor */
                            "%*s "       /* (4) root */
                            "%ms "       /* (5) mount point */
-                           "%*s"        /* (6) mount options */
+                           "%*s"        /* (6) mount flags */
                            "%*[^-]"     /* (7) optional fields */
                            "- "         /* (8) separator */
                            "%*s "       /* (9) file system type */
                            "%*s"        /* (10) mount source */
-                           "%*s"        /* (11) mount options 2 */
+                           "%ms"        /* (11) mount options */
                            "%*[^\n]",   /* some rubbish at the end */
-                           &path);
-                if (k != 1) {
+                           &path, &options);
+                if (k != 2) {
                         if (k == EOF)
                                 break;
 
@@ -125,6 +132,9 @@ static int mount_points_list_get(MountPoint **head) {
                 }
 
                 m->path = p;
+                m->options = options;
+                options = NULL;
+
                 LIST_PREPEND(mount_point, *head, m);
         }
 
@@ -369,6 +379,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
                    benefits, but might confuse the host, as we remount
                    the superblock here, not the bind mound. */
                 if (detect_container() <= 0)  {
+                        _cleanup_free_ char *options = NULL;
+                        /* MS_REMOUNT requires that the data parameter
+                         * should be the same from the original mount
+                         * except for the desired changes. Since we want
+                         * to remount read-only, we should filter out
+                         * rw (and ro too, because it confuses the kernel) */
+                        (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
+
                         /* We always try to remount directories
                          * read-only first, before we go on and umount
                          * them.
@@ -385,7 +403,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
                          * alias read-only we hence should be
                          * relatively safe regarding keeping the fs we
                          * can otherwise not see dirty. */
-                        (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
+                        log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
+                        (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
                 }
 
                 /* Skip / and /usr since we cannot unmount that
index 0889769d0325717cde2745bb6a2f32667901573c..f587a5a14121523b45d718785f3f13ccd356c75e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "unit.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "formats-util.h"
+#include "macro.h"
 #include "specifier.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
 #include "unit-printf.h"
-#include "macro.h"
-#include "cgroup-util.h"
-#include "formats-util.h"
+#include "unit.h"
+#include "user-util.h"
 
 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
         Unit *u = userdata;
@@ -63,10 +66,7 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda
 
         assert(u);
 
-        if (!u->instance)
-                return -EINVAL;
-
-        return unit_name_unescape(u->instance, ret);
+        return unit_name_unescape(strempty(u->instance), ret);
 }
 
 static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
@@ -128,6 +128,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
                         n = unit_default_cgroup_path(slice);
         } else
                 n = strdup(u->manager->cgroup_root);
+        if (!n)
+                return -ENOMEM;
 
         *ret = n;
         return 0;
@@ -157,162 +159,43 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
 }
 
 static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
-        char *printed = NULL;
-        Unit *u = userdata;
-        ExecContext *c;
-        int r = 0;
-
-        assert(u);
-
-        c = unit_get_exec_context(u);
-        if (!c)
-                return -EINVAL;
-
-        if (u->manager->running_as == MANAGER_SYSTEM) {
-
-                /* We cannot use NSS from PID 1, hence try to make the
-                 * best of it in that case, and fail if we can't help
-                 * it */
+        char *t;
 
-                if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
-                        printed = strdup(specifier == 'u' ? "root" : "0");
-                else {
-                        if (specifier == 'u')
-                                printed = strdup(c->user);
-                        else {
-                                uid_t uid;
+        /* If we are UID 0 (root), this will not result in NSS,
+         * otherwise it might. This is good, as we want to be able to
+         * run this in PID 1, where our user ID is 0, but where NSS
+         * lookups are not allowed. */
 
-                                r = parse_uid(c->user, &uid);
-                                if (r < 0)
-                                        return -ENODATA;
-
-                                r = asprintf(&printed, UID_FMT, uid);
-                        }
-                }
-
-        } else {
-                _cleanup_free_ char *tmp = NULL;
-                const char *username = NULL;
-                uid_t uid;
-
-                if (c->user)
-                        username = c->user;
-                else
-                        /* get USER env from env or our own uid */
-                        username = tmp = getusername_malloc();
-
-                /* fish username from passwd */
-                r = get_user_creds(&username, &uid, NULL, NULL, NULL);
-                if (r < 0)
-                        return r;
-
-                if (specifier == 'u')
-                        printed = strdup(username);
-                else
-                        r = asprintf(&printed, UID_FMT, uid);
-        }
-
-        if (r < 0 || !printed)
+        t = getusername_malloc();
+        if (!t)
                 return -ENOMEM;
 
-        *ret = printed;
+        *ret = t;
         return 0;
 }
 
-static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
-        Unit *u = userdata;
-        ExecContext *c;
-        char *n;
-        int r;
-
-        assert(u);
-
-        c = unit_get_exec_context(u);
-        if (!c)
-                return -EOPNOTSUPP;
-
-        if (u->manager->running_as == MANAGER_SYSTEM) {
+static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
 
-                /* We cannot use NSS from PID 1, hence try to make the
-                 * best of it if we can, but fail if we can't */
-
-                if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
-                        n = strdup("/root");
-                else
-                        return -EOPNOTSUPP;
-
-        } else {
-
-                /* return HOME if set, otherwise from passwd */
-                if (!c || !c->user) {
-                        r = get_home_dir(&n);
-                        if (r < 0)
-                                return r;
-                } else {
-                        const char *username, *home;
-
-                        username = c->user;
-                        r = get_user_creds(&username, NULL, NULL, &home, NULL);
-                        if (r < 0)
-                                return r;
-
-                        n = strdup(home);
-                }
-        }
-
-        if (!n)
+        if (asprintf(ret, UID_FMT, getuid()) < 0)
                 return -ENOMEM;
 
-        *ret = n;
         return 0;
 }
 
-static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
-        Unit *u = userdata;
-        ExecContext *c;
-        char *n;
-        int r;
-
-        assert(u);
-
-        c = unit_get_exec_context(u);
-        if (!c)
-                return -EOPNOTSUPP;
-
-        if (u->manager->running_as == MANAGER_SYSTEM) {
-
-                /* We cannot use NSS from PID 1, hence try to make the
-                 * best of it if we can, but fail if we can't */
-
-                if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
-                        n = strdup("/bin/sh");
-                else
-                        return -EOPNOTSUPP;
-
-        } else {
+static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
 
-                /* return /bin/sh for root, otherwise the value from passwd */
-                if (!c->user) {
-                        r = get_shell(&n);
-                        if (r < 0)
-                                return r;
-                } else {
-                        const char *username, *shell;
+        /* On PID 1 (which runs as root) this will not result in NSS,
+         * which is good. See above */
 
-                        username = c->user;
-                        r = get_user_creds(&username, NULL, NULL, NULL, &shell);
-                        if (r < 0)
-                                return r;
+        return get_home_dir(ret);
+}
 
-                        n = strdup(shell);
-                }
-        }
+static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
 
-        if (!n)
-                return -ENOMEM;
+        /* On PID 1 (which runs as root) this will not result in NSS,
+         * which is good. See above */
 
-        *ret = n;
-        return 0;
+        return get_shell(ret);
 }
 
 int unit_name_printf(Unit *u, const char* format, char **ret) {
@@ -352,10 +235,10 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
          * %r where units in this slice are placed in the cgroup tree
          * %R the root of this systemd's instance tree
          * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
-         * %U the UID of the configured user or running user
-         * %u the username of the configured user or running user
-         * %h the homedir of the configured user or running user
-         * %s the shell of the configured user or running user
+         * %U the UID of the running user
+         * %u the username of the running user
+         * %h the homedir of the running user
+         * %s the shell of the running user
          * %m the machine ID of the running system
          * %H the host name of the running system
          * %b the boot ID of the running system
@@ -375,7 +258,8 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
                 { 'r', specifier_cgroup_slice,        NULL },
                 { 'R', specifier_cgroup_root,         NULL },
                 { 't', specifier_runtime,             NULL },
-                { 'U', specifier_user_name,           NULL },
+
+                { 'U', specifier_user_id,             NULL },
                 { 'u', specifier_user_name,           NULL },
                 { 'h', specifier_user_home,           NULL },
                 { 's', specifier_user_shell,          NULL },
index 39cd89f1e33069a67240b7f39269f878d001f2ba..f553f248295e0fde6d925b716ef52064e654f12b 100644 (file)
 ***/
 
 #include <errno.h>
-#include <string.h>
 #include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include "sd-id128.h"
 #include "sd-messages.h"
-#include "set.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "log.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
-#include "missing.h"
-#include "mkdir.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "dropin.h"
+#include "escape.h"
+#include "execute.h"
 #include "fileio-label.h"
 #include "formats-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "process-util.h"
-#include "virt.h"
-#include "bus-common-errors.h"
-#include "bus-util.h"
-#include "dropin.h"
-#include "unit-name.h"
+#include "set.h"
 #include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
 #include "unit.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "execute.h"
+#include "user-util.h"
+#include "virt.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
         [UNIT_SOCKET] = &socket_vtable,
         [UNIT_BUSNAME] = &busname_vtable,
         [UNIT_TARGET] = &target_vtable,
-        [UNIT_SNAPSHOT] = &snapshot_vtable,
         [UNIT_DEVICE] = &device_vtable,
         [UNIT_MOUNT] = &mount_vtable,
         [UNIT_AUTOMOUNT] = &automount_vtable,
@@ -412,12 +418,11 @@ static void unit_remove_transient(Unit *u) {
 
         STRV_FOREACH(i, u->dropin_paths) {
                 _cleanup_free_ char *p = NULL;
-                int r;
 
                 (void) unlink(*i);
 
-                r = path_get_parent(*i, &p);
-                if (r >= 0)
+                p = dirname_malloc(*i);
+                if (p)
                         (void) rmdir(p);
         }
 }
@@ -992,15 +997,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                         "%s\tRefuseManualStop: %s\n"
                         "%s\tDefaultDependencies: %s\n"
                         "%s\tOnFailureJobMode: %s\n"
-                        "%s\tIgnoreOnIsolate: %s\n"
-                        "%s\tIgnoreOnSnapshot: %s\n",
+                        "%s\tIgnoreOnIsolate: %s\n",
                         prefix, yes_no(u->stop_when_unneeded),
                         prefix, yes_no(u->refuse_manual_start),
                         prefix, yes_no(u->refuse_manual_stop),
                         prefix, yes_no(u->default_dependencies),
                         prefix, job_mode_to_string(u->on_failure_job_mode),
-                        prefix, yes_no(u->ignore_on_isolate),
-                        prefix, yes_no(u->ignore_on_snapshot));
+                        prefix, yes_no(u->ignore_on_isolate));
 
                 if (UNIT_VTABLE(u)->dump)
                         UNIT_VTABLE(u)->dump(u, f, prefix2);
@@ -1098,9 +1101,7 @@ static int unit_add_target_dependencies(Unit *u) {
 
         static const UnitDependency deps[] = {
                 UNIT_REQUIRED_BY,
-                UNIT_REQUIRED_BY_OVERRIDABLE,
                 UNIT_REQUISITE_OF,
-                UNIT_REQUISITE_OF_OVERRIDABLE,
                 UNIT_WANTED_BY,
                 UNIT_BOUND_BY
         };
@@ -1602,11 +1603,11 @@ bool unit_can_reload(Unit *u) {
 
 static void unit_check_unneeded(Unit *u) {
 
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
         static const UnitDependency needed_dependencies[] = {
                 UNIT_REQUIRED_BY,
-                UNIT_REQUIRED_BY_OVERRIDABLE,
                 UNIT_REQUISITE_OF,
-                UNIT_REQUISITE_OF_OVERRIDABLE,
                 UNIT_WANTED_BY,
                 UNIT_BOUND_BY,
         };
@@ -1643,12 +1644,13 @@ static void unit_check_unneeded(Unit *u) {
         log_unit_info(u, "Unit not needed anymore. Stopping.");
 
         /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
-        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
         if (r < 0)
-                log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
+                log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
 }
 
 static void unit_check_binds_to(Unit *u) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         bool stop = false;
         Unit *other;
         Iterator i;
@@ -1688,9 +1690,9 @@ static void unit_check_binds_to(Unit *u) {
         log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
 
         /* A unit we need to run is gone. Sniff. Let's stop this. */
-        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
         if (r < 0)
-                log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
+                log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
 }
 
 static void retroactively_start_dependencies(Unit *u) {
@@ -1703,30 +1705,25 @@ static void retroactively_start_dependencies(Unit *u) {
         SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
                 if (!set_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
 
         SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
                 if (!set_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!set_get(u->dependencies[UNIT_AFTER], other) &&
-                    !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
 
         SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
                 if (!set_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
 
         SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
 
         SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
 }
 
 static void retroactively_stop_dependencies(Unit *u) {
@@ -1739,7 +1736,7 @@ static void retroactively_stop_dependencies(Unit *u) {
         /* Pull down units which are bound to us recursively if enabled */
         SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
 }
 
 static void check_unneeded_dependencies(Unit *u) {
@@ -1753,18 +1750,12 @@ static void check_unneeded_dependencies(Unit *u) {
         SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
         SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_unneeded(other);
         SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_unneeded(other);
-        SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
-                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        unit_check_unneeded(other);
         SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_unneeded(other);
@@ -1784,7 +1775,7 @@ void unit_start_on_failure(Unit *u) {
         SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
                 int r;
 
-                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL);
+                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL);
                 if (r < 0)
                         log_unit_error_errno(u, r, "Failed to enqueue OnFailure= job: %m");
         }
@@ -2132,16 +2123,12 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
 
         static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
                 [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
-                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
                 [UNIT_WANTS] = UNIT_WANTED_BY,
                 [UNIT_REQUISITE] = UNIT_REQUISITE_OF,
-                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUISITE_OF_OVERRIDABLE,
                 [UNIT_BINDS_TO] = UNIT_BOUND_BY,
                 [UNIT_PART_OF] = UNIT_CONSISTS_OF,
                 [UNIT_REQUIRED_BY] = UNIT_REQUIRES,
-                [UNIT_REQUIRED_BY_OVERRIDABLE] = UNIT_REQUIRES_OVERRIDABLE,
                 [UNIT_REQUISITE_OF] = UNIT_REQUISITE,
-                [UNIT_REQUISITE_OF_OVERRIDABLE] = UNIT_REQUISITE_OVERRIDABLE,
                 [UNIT_WANTED_BY] = UNIT_WANTS,
                 [UNIT_BOUND_BY] = UNIT_BINDS_TO,
                 [UNIT_CONSISTS_OF] = UNIT_PART_OF,
@@ -2320,47 +2307,9 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
         return unit_add_two_dependencies(u, d, e, other, add_reference);
 }
 
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
-        _cleanup_free_ char *buf = NULL;
-        Unit *other;
-        int r;
-
-        assert(u);
-        assert(name || path);
-
-        r = resolve_template(u, name, path, &buf, &name);
-        if (r < 0)
-                return r;
-
-        r = manager_load_unit(u->manager, name, path, NULL, &other);
-        if (r < 0)
-                return r;
-
-        return unit_add_dependency(other, d, u, add_reference);
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
-        _cleanup_free_ char *buf = NULL;
-        Unit *other;
-        int r;
-
-        assert(u);
-        assert(name || path);
-
-        r  = resolve_template(u, name, path, &buf, &name);
-        if (r < 0)
-                return r;
-
-        r = manager_load_unit(u->manager, name, path, NULL, &other);
-        if (r < 0)
-                return r;
-
-        return unit_add_two_dependencies(other, d, e, u, add_reference);
-}
-
 int set_unit_path(const char *p) {
         /* This is mostly for debug purposes */
-        if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
+        if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0)
                 return -errno;
 
         return 0;
@@ -2508,26 +2457,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd
         return 0;
 }
 
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
-        _cleanup_free_ char *match = NULL;
-        Manager *m = u->manager;
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
+        const char *match;
 
-        assert(m);
+        assert(u);
+        assert(bus);
+        assert(name);
 
         if (u->match_bus_slot)
                 return -EBUSY;
 
-        match = strjoin("type='signal',"
+        match = strjoina("type='signal',"
                         "sender='org.freedesktop.DBus',"
                         "path='/org/freedesktop/DBus',"
                         "interface='org.freedesktop.DBus',"
                         "member='NameOwnerChanged',"
-                        "arg0='",
-                        name,
-                        "'",
+                        "arg0='", name, "'",
                         NULL);
-        if (!match)
-                return -ENOMEM;
 
         return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
 }
@@ -2544,9 +2490,9 @@ int unit_watch_bus_name(Unit *u, const char *name) {
         if (u->manager->api_bus) {
                 /* If the bus is already available, install the match directly.
                  * Otherwise, just put the name in the list. bus_setup_api() will take care later. */
-                r = unit_install_bus_match(u->manager->api_bus, u, name);
+                r = unit_install_bus_match(u, u->manager->api_bus, name);
                 if (r < 0)
-                        return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+                        return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
         }
 
         r = hashmap_put(u->manager->watch_bus, name, u);
@@ -2925,7 +2871,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
 }
 
 int unit_coldplug(Unit *u) {
-        int r;
+        int r = 0, q = 0;
 
         assert(u);
 
@@ -2936,17 +2882,16 @@ int unit_coldplug(Unit *u) {
 
         u->coldplugged = true;
 
-        if (UNIT_VTABLE(u)->coldplug) {
+        if (UNIT_VTABLE(u)->coldplug)
                 r = UNIT_VTABLE(u)->coldplug(u);
-                if (r < 0)
-                        return r;
-        }
 
-        if (u->job) {
-                r = job_coldplug(u->job);
-                if (r < 0)
-                        return r;
-        }
+        if (u->job)
+                q = job_coldplug(u->job);
+
+        if (r < 0)
+                return r;
+        if (q < 0)
+                return q;
 
         return 0;
 }
@@ -3187,12 +3132,19 @@ int unit_following_set(Unit *u, Set **s) {
 }
 
 UnitFileState unit_get_unit_file_state(Unit *u) {
+        int r;
+
         assert(u);
 
-        if (u->unit_file_state < 0 && u->fragment_path)
-                u->unit_file_state = unit_file_get_state(
+        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,
-                                NULL, basename(u->fragment_path));
+                                NULL,
+                                basename(u->fragment_path),
+                                &u->unit_file_state);
+                if (r < 0)
+                        u->unit_file_state = UNIT_FILE_BAD;
+        }
 
         return u->unit_file_state;
 }
@@ -3203,7 +3155,8 @@ 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,
-                                NULL, basename(u->fragment_path));
+                                NULL,
+                                basename(u->fragment_path));
 
         return u->unit_file_preset;
 }
@@ -3368,19 +3321,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
         return 0;
 }
 
-static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
-        _cleanup_free_ char *dir = NULL;
-        int r;
-
-        assert(u);
-
-        r = unit_drop_in_dir(u, mode, u->transient, &dir);
-        if (r < 0)
-                return r;
-
-        return drop_in_file(dir, u->id, 50, name, p, q);
-}
-
 int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
 
         _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
@@ -3479,28 +3419,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
         return unit_write_drop_in_private(u, mode, name, p);
 }
 
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
-        _cleanup_free_ char *p = NULL, *q = NULL;
-        int r;
-
-        assert(u);
-
-        if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
-                return 0;
-
-        r = unit_drop_in_file(u, mode, name, &p, &q);
-        if (r < 0)
-                return r;
-
-        if (unlink(q) < 0)
-                r = errno == ENOENT ? 0 : -errno;
-        else
-                r = 1;
-
-        rmdir(p);
-        return r;
-}
-
 int unit_make_transient(Unit *u) {
         assert(u);
 
index a4a1b011fcbac8c19e1a32b4ce9beff85e79ccb3..14e307214644755678a5aa49d68c42e62aa1ad6c 100644 (file)
@@ -203,9 +203,6 @@ struct Unit {
         /* Ignore this unit when isolating */
         bool ignore_on_isolate;
 
-        /* Ignore this unit when snapshotting */
-        bool ignore_on_snapshot;
-
         /* Did the last condition check succeed? */
         bool condition_result;
         bool assert_result;
@@ -248,7 +245,6 @@ typedef enum UnitSetPropertiesMode {
 #include "socket.h"
 #include "busname.h"
 #include "target.h"
-#include "snapshot.h"
 #include "device.h"
 #include "automount.h"
 #include "swap.h"
@@ -322,7 +318,7 @@ struct UnitVTable {
         int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
 
         /* Try to match up fds with what we need for this unit */
-        int (*distribute_fds)(Unit *u, FDSet *fds);
+        void (*distribute_fds)(Unit *u, FDSet *fds);
 
         /* Boils down the more complex internal state of this unit to
          * a simpler one that the engine can understand */
@@ -343,9 +339,6 @@ struct UnitVTable {
          * shall release its runtime resources */
         void (*release_resources)(Unit *u);
 
-        /* Return true when this unit is suitable for snapshotting */
-        bool (*check_snapshot)(Unit *u);
-
         /* Invoked on every child that died */
         void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
 
@@ -389,7 +382,7 @@ struct UnitVTable {
          * everything that is loaded here should still stay in
          * inactive state. It is the job of the coldplug() call above
          * to put the units into the initial state.  */
-        int (*enumerate)(Manager *m);
+        void (*enumerate)(Manager *m);
 
         /* Type specific cleanups. */
         void (*shutdown)(Manager *m);
@@ -443,7 +436,6 @@ DEFINE_CAST(SERVICE, Service);
 DEFINE_CAST(SOCKET, Socket);
 DEFINE_CAST(BUSNAME, BusName);
 DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(SNAPSHOT, Snapshot);
 DEFINE_CAST(DEVICE, Device);
 DEFINE_CAST(MOUNT, Mount);
 DEFINE_CAST(AUTOMOUNT, Automount);
@@ -464,9 +456,6 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit
 int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
 int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
 
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
 int unit_add_exec_dependencies(Unit *u, ExecContext *c);
 
 int unit_choose_id(Unit *u, const char *name);
@@ -520,7 +509,7 @@ void unit_unwatch_all_pids(Unit *u);
 
 void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
 
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name);
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name);
 int unit_watch_bus_name(Unit *u, const char *name);
 void unit_unwatch_bus_name(Unit *u, const char *name);
 
@@ -592,8 +581,6 @@ 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);
 int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
 
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name);
-
 int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
 
 int unit_make_transient(Unit *u);
index ab91afec4d1e96374faecd389d01d1744eb6fd8f..ae53bac60094f78dbef6a3b8c5338d7c74e0bdac 100644 (file)
 
 #include <errno.h>
 
+#include "alloc-util.h"
 #include "dropin.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
 #include "generator.h"
 #include "hashmap.h"
 #include "log.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "fstab-util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
 #include "util.h"
index cc03ad3ca8c7558c5d7a3ca49a9a3569bca87aa3..98fe52a81bbe81de5b715b8351920e2a1c031d75 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
-#include <sys/mman.h>
+#include <libcryptsetup.h>
 #include <mntent.h>
+#include <string.h>
+#include <sys/mman.h>
 
-#include <libcryptsetup.h>
+#include "sd-device.h"
 
+#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "device-util.h"
+#include "escape.h"
 #include "fileio.h"
 #include "log.h"
-#include "util.h"
+#include "mount-util.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "ask-password-api.h"
-#include "sd-device.h"
-#include "device-util.h"
+#include "util.h"
 
 static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
 static char *arg_cipher = NULL;
@@ -312,15 +317,16 @@ static char *disk_mount_point(const char *label) {
         return NULL;
 }
 
-static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) {
+static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) {
         _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
+        _cleanup_strv_free_erase_ char **passwords = NULL;
         const char *name = NULL;
         char **p, *id;
         int r = 0;
 
         assert(vol);
         assert(src);
-        assert(passwords);
+        assert(ret);
 
         description = disk_description(src);
         mount_point = disk_mount_point(vol);
@@ -360,14 +366,16 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
 
         id = strjoina("cryptsetup:", escaped_name);
 
-        r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE|(accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0), passwords);
+        r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
+                              ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
+                              &passwords);
         if (r < 0)
                 return log_error_errno(r, "Failed to query password: %m");
 
         if (arg_verify) {
-                _cleanup_strv_free_ char **passwords2 = NULL;
+                _cleanup_strv_free_erase_ char **passwords2 = NULL;
 
-                assert(strv_length(*passwords) == 1);
+                assert(strv_length(passwords) == 1);
 
                 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
                         return log_oom();
@@ -380,22 +388,23 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
 
                 assert(strv_length(passwords2) == 1);
 
-                if (!streq(*passwords[0], passwords2[0])) {
+                if (!streq(passwords[0], passwords2[0])) {
                         log_warning("Passwords did not match, retrying.");
                         return -EAGAIN;
                 }
         }
 
-        strv_uniq(*passwords);
+        strv_uniq(passwords);
 
-        STRV_FOREACH(p, *passwords) {
+        STRV_FOREACH(p, passwords) {
                 char *c;
 
                 if (strlen(*p)+1 >= arg_key_size)
                         continue;
 
                 /* Pad password if necessary */
-                if (!(c = new(char, arg_key_size)))
+                c = new(char, arg_key_size);
+                if (!c)
                         return log_oom();
 
                 strncpy(c, *p, arg_key_size);
@@ -403,14 +412,19 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
                 *p = c;
         }
 
+        *ret = passwords;
+        passwords = NULL;
+
         return 0;
 }
 
-static int attach_tcrypt(struct crypt_device *cd,
-                                const char *name,
-                                const char *key_file,
-                                char **passwords,
-                                uint32_t flags) {
+static int attach_tcrypt(
+                struct crypt_device *cd,
+                const char *name,
+                const char *key_file,
+                char **passwords,
+                uint32_t flags) {
+
         int r = 0;
         _cleanup_free_ char *passphrase = NULL;
         struct crypt_params_tcrypt params = {
@@ -520,8 +534,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                  * it just configures encryption
                  * parameters when used for plain
                  * mode. */
-                r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
-                                 NULL, NULL, arg_keyfile_size, &params);
+                r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
 
                 /* hash == NULL implies the user passed "plain" */
                 pass_volume_key = (params.hash == NULL);
@@ -537,9 +550,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                  crypt_get_device_name(cd));
 
         if (key_file) {
-                r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
-                                                     key_file, arg_keyfile_size,
-                                                     arg_keyfile_offset, flags);
+                r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
                 if (r < 0) {
                         log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
                         return -EAGAIN;
@@ -631,7 +642,6 @@ int main(int argc, char *argv[]) {
                         k = crypt_init(&cd, arg_header);
                 } else
                         k = crypt_init(&cd, argv[3]);
-
                 if (k) {
                         log_error_errno(k, "crypt_init() failed: %m");
                         goto finish;
@@ -669,7 +679,7 @@ int main(int argc, char *argv[]) {
                 }
 
                 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
-                        _cleanup_strv_free_ char **passwords = NULL;
+                        _cleanup_strv_free_erase_ char **passwords = NULL;
 
                         if (!key_file) {
                                 k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
index 7bbec5467ec316dac6bf95d4d972961fe0429cca..6861a592fe76f28ba59c042008e67905df0c5e59 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
 #include "conf-parser.h"
-#include "special.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "mkdir.h"
-#include "bus-util.h"
-#include "bus-internal.h"
+#include "special.h"
 #include "unit-name.h"
-#include "cgroup-util.h"
+#include "util.h"
 
 static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
 
@@ -223,8 +227,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
                 if (errno == -ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
         }
 
         r = 0;
@@ -242,8 +245,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
         return r;
 
 fail:
-        log_error_errno(errno, "Failed to read D-Bus services directory: %m");
-        return -errno;
+        return log_error_errno(errno, "Failed to read D-Bus services directory: %m");
 }
 
 static int link_busnames_target(const char *units) {
index 8b29e8fd09314dda37306b41f0b6817a6a3eba36..413cfd03889e7566bcc02bf2504dcf3c42f108d8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "special.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
-#include "mkdir.h"
+#include "util.h"
 
+static char *arg_default_unit = NULL;
 static const char *arg_dest = "/tmp";
 static char **arg_mask = NULL;
 static char **arg_wants = NULL;
@@ -76,6 +82,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
                                 arg_debug_shell = r;
                 } else
                         arg_debug_shell = true;
+        } else if (streq(key, "systemd.unit")) {
+
+                if (!value)
+                        log_error("Missing argument for systemd.unit= kernel command line parameter.");
+                else {
+                        r = free_and_strdup(&arg_default_unit, value);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to set default unit %s: %m", value);
+                }
+        } else if (!value) {
+                const char *target;
+
+                target = runlevel_to_target(key);
+                if (target) {
+                        r = free_and_strdup(&arg_default_unit, target);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to set default unit %s: %m", target);
+                }
         }
 
         return 0;
@@ -114,7 +138,7 @@ static int generate_wants_symlinks(void) {
         STRV_FOREACH(u, arg_wants) {
                 _cleanup_free_ char *p = NULL, *f = NULL;
 
-                p = strjoin(arg_dest, "/default.target.wants/", *u, NULL);
+                p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u, NULL);
                 if (!p)
                         return log_oom();
 
@@ -150,6 +174,12 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
+        r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
+        if (r < 0) {
+                log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
+                goto finish;
+        }
+
         r = parse_proc_cmdline(parse_proc_cmdline_item);
         if (r < 0)
                 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
index 4edafc7cdf7895d61888bbf1348cd7e193ffc98d..8bf678c28fb793062f53f57d6a06dd295e79aa46 100644 (file)
 #include <sys/prctl.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "hashmap.h"
+#include "locale-util.h"
 #include "log.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "util.h"
@@ -311,8 +319,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open %s: %m", path);
-                return -errno;
+                return log_error_errno(errno, "Failed to open %s: %m", path);
         }
 
         for (;;) {
index dcf4e9749e2b59ddce627e96db811b30397ae81c..0a256c29be1da7abb25450677c5d35a7a59ad125 100644 (file)
@@ -31,7 +31,8 @@ static bool arg_quiet = false;
 static enum {
         ANY_VIRTUALIZATION,
         ONLY_VM,
-        ONLY_CONTAINER
+        ONLY_CONTAINER,
+        ONLY_CHROOT,
 } arg_mode = ANY_VIRTUALIZATION;
 
 static void help(void) {
@@ -41,6 +42,7 @@ static void help(void) {
                "     --version          Show package version\n"
                "  -c --container        Only detect whether we are run in a container\n"
                "  -v --vm               Only detect whether we are run in a VM\n"
+               "  -r --chroot           Detect whether we are run in a chroot() environment\n"
                "  -q --quiet            Don't output anything, just set return value\n"
                , program_invocation_short_name);
 }
@@ -55,7 +57,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "help",      no_argument,       NULL, 'h'           },
                 { "version",   no_argument,       NULL, ARG_VERSION   },
                 { "container", no_argument,       NULL, 'c'           },
-                { "vm",        optional_argument, NULL, 'v'           },
+                { "vm",        no_argument,       NULL, 'v'           },
+                { "chroot",    no_argument,       NULL, 'r'           },
                 { "quiet",     no_argument,       NULL, 'q'           },
                 {}
         };
@@ -65,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hqcvr", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -88,6 +91,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_mode = ONLY_VM;
                         break;
 
+                case 'r':
+                        arg_mode = ONLY_CHROOT;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -137,6 +144,15 @@ int main(int argc, char *argv[]) {
 
                 break;
 
+        case ONLY_CHROOT:
+                r = running_in_chroot();
+                if (r < 0) {
+                        log_error_errno(r, "Failed to check for chroot() environment: %m");
+                        return EXIT_FAILURE;
+                }
+
+                return r ? EXIT_SUCCESS : EXIT_FAILURE;
+
         case ANY_VIRTUALIZATION:
         default:
                 r = detect_virtualization();
index a4bfeb5df53029a6ed04b9de73822716121f0843..e857affbc423830b4d2d76b785d9e2d430be9e09 100644 (file)
@@ -23,7 +23,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "alloc-util.h"
 #include "log.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
 
index 1562ccf0d79af1c31d780737e511e5692d73c772..642d36912ca2a1ed0b8d108b791b32cf26b7e9a2 100644 (file)
 #include <shadow.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "ask-password-api.h"
 #include "copy.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "hostname-util.h"
 #include "locale-util.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "random-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "time-util.h"
+#include "umask-util.h"
+#include "user-util.h"
 
 static char *arg_root = NULL;
 static char *arg_locale = NULL;  /* $LANG */
@@ -51,15 +58,6 @@ static bool arg_copy_locale = false;
 static bool arg_copy_timezone = false;
 static bool arg_copy_root_password = false;
 
-static void clear_string(char *x) {
-
-        if (!x)
-                return;
-
-        /* A delicious drop of snake-oil! */
-        memset(x, 'x', strlen(x));
-}
-
 static bool press_any_key(void) {
         char k = 0;
         bool need_nl = true;
@@ -464,7 +462,7 @@ static int prompt_root_password(void) {
         msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: ");
 
         for (;;) {
-                _cleanup_free_ char *a = NULL, *b = NULL;
+                _cleanup_string_free_erase_ char *a = NULL, *b = NULL;
 
                 r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a);
                 if (r < 0)
@@ -476,19 +474,14 @@ static int prompt_root_password(void) {
                 }
 
                 r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b);
-                if (r < 0) {
-                        clear_string(a);
+                if (r < 0)
                         return log_error_errno(r, "Failed to query root password: %m");
-                }
 
                 if (!streq(a, b)) {
                         log_error("Entered passwords did not match, please try again.");
-                        clear_string(a);
-                        clear_string(b);
                         continue;
                 }
 
-                clear_string(b);
                 arg_root_password = a;
                 a = NULL;
                 break;
@@ -547,7 +540,7 @@ static int process_root_password(void) {
 
         mkdir_parents(etc_shadow, 0755);
 
-        lock = take_password_lock(arg_root);
+        lock = take_etc_passwd_lock(arg_root);
         if (lock < 0)
                 return lock;
 
@@ -561,8 +554,7 @@ static int process_root_password(void) {
                                 if (!errno)
                                         errno = EIO;
 
-                                log_error_errno(errno, "Failed to find shadow entry for root: %m");
-                                return -errno;
+                                return log_error_errno(errno, "Failed to find shadow entry for root: %m");
                         }
 
                         r = write_root_shadow(etc_shadow, p);
@@ -597,10 +589,9 @@ static int process_root_password(void) {
         item.sp_pwdp = crypt(arg_root_password, salt);
         if (!item.sp_pwdp) {
                 if (!errno)
-                        errno = -EINVAL;
+                        errno = EINVAL;
 
-                log_error_errno(errno, "Failed to encrypt password: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to encrypt password: %m");
         }
 
         item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
@@ -704,16 +695,9 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case ARG_ROOT:
-                        free(arg_root);
-                        arg_root = path_make_absolute_cwd(optarg);
-                        if (!arg_root)
-                                return log_oom();
-
-                        path_kill_slashes(arg_root);
-
-                        if (path_equal(arg_root, "/"))
-                                arg_root = mfree(arg_root);
-
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case ARG_LOCALE:
@@ -881,7 +865,7 @@ finish:
         free(arg_locale_messages);
         free(arg_timezone);
         free(arg_hostname);
-        clear_string(arg_root_password);
+        string_erase(arg_root_password);
         free(arg_root_password);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
index 30c846f01d483048d094282f890c94b704bbfbf5..5b806a1e69168380db3eb29f1c4fa76132b5dce2 100644 (file)
 #include "sd-bus.h"
 #include "sd-device.h"
 
-#include "util.h"
-#include "process-util.h"
-#include "signal-util.h"
-#include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-util.h"
 #include "device-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "signal-util.h"
 #include "socket-util.h"
+#include "special.h"
+#include "stdio-util.h"
+#include "util.h"
 
 /* exit codes as defined in fsck(8) */
 enum {
@@ -366,12 +372,12 @@ int main(int argc, char *argv[]) {
         r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
         if (r >= 0) {
                 r = fsck_exists(type);
-                if (r == -ENOENT) {
-                        log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
-                        r = 0;
+                if (r < 0)
+                        log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device);
+                else if (r == 0) {
+                        log_info("fsck.%s doesn't exist, not checking file system on %s.", type, device);
                         goto finish;
-                } else if (r < 0)
-                        log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device);
+                }
         }
 
         if (arg_show_progress) {
index 3f8ea5647cddeb7610f05c31a1eb77d252025bc8..f7c8d11ace19b3a05e244de34425a8d24d80ba1f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <mntent.h>
 #include <errno.h>
+#include <mntent.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include "log.h"
-#include "util.h"
-#include "unit-name.h"
-#include "path-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "fstab-util.h"
+#include "generator.h"
+#include "log.h"
+#include "mkdir.h"
 #include "mount-setup.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
 #include "special.h"
-#include "mkdir.h"
-#include "generator.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "strv.h"
+#include "unit-name.h"
+#include "util.h"
 #include "virt.h"
 
 static const char *arg_dest = "/tmp";
index 9a4b038ef3d31e3e5e4957663eff061f569bc0be..03df7365b56d2683a0cf8cef5a23b10b11929c7d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
-#include <unistd.h>
 #include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "log.h"
-#include "util.h"
 #include "mkdir.h"
-#include "unit-name.h"
-#include "virt.h"
-#include "fileio.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "virt.h"
 
 static const char *arg_dest = "/tmp";
 
index 96425c5b07fabc6689bbcb40b5088cab9cf60b52..34852ce38183b3ce1285dd6dbca4cda8ca967866 100644 (file)
 #include <sys/statfs.h>
 #include <blkid/blkid.h>
 
-#include "sd-id128.h"
 #include "libudev.h"
-#include "path-util.h"
-#include "util.h"
-#include "mkdir.h"
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "blkid-util.h"
+#include "btrfs-util.h"
+#include "dirent-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
+#include "generator.h"
+#include "gpt.h"
 #include "missing.h"
-#include "udev-util.h"
+#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
 #include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "udev-util.h"
 #include "unit-name.h"
+#include "util.h"
 #include "virt.h"
-#include "generator.h"
-#include "gpt.h"
-#include "fileio.h"
-#include "efivars.h"
-#include "fstab-util.h"
-#include "blkid-util.h"
-#include "btrfs-util.h"
 
 static const char *arg_dest = "/tmp";
 static bool arg_enabled = true;
@@ -293,8 +302,7 @@ static int probe_and_add_mount(
         if (!b) {
                 if (errno == 0)
                         return log_oom();
-                log_error_errno(errno, "Failed to allocate prober: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to allocate prober: %m");
         }
 
         blkid_probe_enable_superblocks(b, 1);
@@ -493,8 +501,7 @@ static int add_boot(const char *what) {
         if (!b) {
                 if (errno == 0)
                         return log_oom();
-                log_error_errno(errno, "Failed to allocate prober: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to allocate prober: %m");
         }
 
         blkid_probe_enable_partitions(b, 1);
index 9fb6233336b544da23b52b7f69f81cfc681db519..da719f2a3064e1a096b3a4b911108908f5731944 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
 
+#include "alloc-util.h"
+#include "fstab-util.h"
 #include "log.h"
-#include "util.h"
-#include "special.h"
 #include "mkdir.h"
+#include "proc-cmdline.h"
+#include "special.h"
+#include "string-util.h"
 #include "unit-name.h"
+#include "util.h"
 
 static const char *arg_dest = "/tmp";
 static char *arg_resume_dev = NULL;
index 1f3b1699056dcb52014c11ad7fb325ff1cbf1fee..316a2803d31fb25ad3db8b91482df8885e7a0726 100644 (file)
 #include <errno.h>
 #include <sys/stat.h>
 
+#include "alloc-util.h"
+#include "fileio.h"
 #include "log.h"
 #include "util.h"
-#include "fileio.h"
 
 int main(int argc, char *argv[]) {
         struct stat st;
index 0724fcc16dbe88036596ebddc1e090c103e6bbc2..bf09fb8fbb31f7635f11d3154b00262a05101cb2 100644 (file)
@@ -28,6 +28,7 @@
 #include "sd-bus.h"
 #include "sd-id128.h"
 
+#include "alloc-util.h"
 #include "architecture.h"
 #include "bus-error.h"
 #include "bus-util.h"
index dd508aefb5f4a6893d3f9408f54d81dbe09f1407..92061532b8e2074d0d5a4c03889838656c96e79a 100644 (file)
 #include <unistd.h>
 #include <sys/utsname.h>
 
-#include "util.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "bus-util.h"
 #include "def.h"
-#include "virt.h"
 #include "env-util.h"
-#include "fileio-label.h"
-#include "bus-util.h"
 #include "event-util.h"
-#include "selinux-util.h"
+#include "fileio-label.h"
 #include "hostname-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
 
 #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
 
index 1e415db845c8fa579d6c8768a8ef040c787c33b9..de59b797a6e80288c09db2b2deecf1e3c21f7ab8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "hwdb-internal.h"
 #include "hwdb-util.h"
 #include "mkdir.h"
 #include "strbuf.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 #include "verbs.h"
index 18c42b8b6d1652db8cc6bcb3c2bf10351db6818d..7b1ac134a0d2116fced81d3168b7a8669ea70109 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <ftw.h>
 
-#include "util.h"
 #include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
 #include "aufs-util.h"
 
 static int nftw_cb(
index d390cfb1f3e5f0978bfdfb075a300cae3d22dcca..4278466df120ee1bac9077761f86cebf27c913b8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "curl-util.h"
+#include "fd-util.h"
+#include "string-util.h"
 
 static void curl_glue_check_finished(CurlGlue *g) {
         CURLMsg *msg;
index c249069ffacf5142d6ba10cacaada5a9161ff975..6a2aa81c76c056ec7344c4ea670d3974b3d07d68 100644 (file)
 #include <sys/types.h>
 #include <curl/curl.h>
 
-#include "hashmap.h"
 #include "sd-event.h"
 
+#include "hashmap.h"
+
 typedef struct CurlGlue CurlGlue;
 
 struct CurlGlue {
index 8f9c9bbc800cbcdc05dc049bde40d9aa37880569..103d45bf218b2028130253d320144d52814cb72b 100644 (file)
 #undef basename
 
 #include "sd-daemon.h"
-#include "util.h"
-#include "ratelimit.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
 #include "copy.h"
-#include "import-common.h"
 #include "export-raw.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "import-common.h"
+#include "ratelimit.h"
+#include "string-util.h"
+#include "util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
 
index 43fa9d1b03864d81ce70c563c22a696de830afcc..2bbec661e66be4e7ebf9aa450fc8a5af9db18e5a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/sendfile.h>
-
 #include "sd-daemon.h"
-#include "util.h"
-#include "ratelimit.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "import-common.h"
 #include "export-tar.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "import-common.h"
 #include "process-util.h"
+#include "ratelimit.h"
+#include "string-util.h"
+#include "util.h"
 
 #define COPY_BUFFER_SIZE (16*1024)
 
@@ -78,7 +81,7 @@ TarExport *tar_export_unref(TarExport *e) {
         }
 
         if (e->temp_path) {
-                (void) btrfs_subvol_remove(e->temp_path, false);
+                (void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA);
                 free(e->temp_path);
         }
 
@@ -283,7 +286,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
         if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
                 BtrfsQuotaInfo q;
 
-                r = btrfs_subvol_get_quota_fd(sfd, &q);
+                r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q);
                 if (r >= 0)
                         e->quota_referenced = q.referenced;
 
index d34105e4ca187e682ca050a00815bb1ad62f3ea4..2b33d778d3b4d8ef36f88e68a604ef5656f234cc 100644 (file)
 
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "event-util.h"
 #include "export-raw.h"
 #include "export-tar.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "hostname-util.h"
 #include "import-util.h"
 #include "machine-image.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "verbs.h"
 
 static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
index 9b86dbfa7986da7b9a709d308d14da7afd1ad71f..a8551ca9e8630a33499398136175ab94b00ff173 100644 (file)
 #include <unistd.h>
 
 #include "btrfs-util.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "fd-util.h"
+#include "import-common.h"
 #include "signal-util.h"
 #include "util.h"
-#include "import-common.h"
 
 int import_make_read_only_fd(int fd) {
         int r;
index d6b81330361199d9f3aef903831d20ff1756f0f1..d4ff178f60bbc68fc607999667467744b800d375 100644 (file)
@@ -19,8 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "import-compress.h"
+#include "string-table.h"
+#include "util.h"
 
 void import_compress_free(ImportCompress *c) {
         assert(c);
index 5f7d25d063e63e2dca668cfb921e49b23a324617..7593f064fc1d81cad85f2c89780dd7a533655994 100644 (file)
 
 #include "sd-daemon.h"
 #include "sd-event.h"
-#include "util.h"
-#include "path-util.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "hostname-util.h"
+#include "chattr-util.h"
 #include "copy.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "ratelimit.h"
-#include "machine-pool.h"
-#include "qcow2-util.h"
-#include "import-compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
 #include "import-common.h"
+#include "import-compress.h"
 #include "import-raw.h"
+#include "io-util.h"
+#include "machine-pool.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "qcow2-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
 
 struct RawImport {
         sd_event *event;
@@ -191,7 +199,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
 
         r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
+                log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
 
         log_info("Unpacking QCOW2 file.");
 
@@ -279,7 +287,7 @@ static int raw_import_open_disk(RawImport *i) {
 
         r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
+                log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
 
         return 0;
 }
index d2bfb3023841e755c217fe8318ce6c8cd19a7548..c7983c04bed0ed614bb2f5875698f1f0ba46f9b4 100644 (file)
 
 #include "sd-daemon.h"
 #include "sd-event.h"
-#include "util.h"
-#include "path-util.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "hostname-util.h"
 #include "copy.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "ratelimit.h"
-#include "machine-pool.h"
-#include "qcow2-util.h"
-#include "import-compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
 #include "import-common.h"
+#include "import-compress.h"
 #include "import-tar.h"
+#include "io-util.h"
+#include "machine-pool.h"
+#include "mkdir.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "qcow2-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
 
 struct TarImport {
         sd_event *event;
@@ -234,7 +241,9 @@ static int tar_import_fork_tar(TarImport *i) {
                 if (mkdir(i->temp_path, 0755) < 0)
                         return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
         } else if (r < 0)
-                return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
+                return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path);
+        else
+                (void) import_assign_pool_quota_and_warn(i->temp_path);
 
         i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
         if (i->tar_fd < 0)
index 1c92312585e7a2bb00ae261a1beef6b4603f137e..018b94d4c43a3fe09c9f744f532824ada7e181c9 100644 (file)
 
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "event-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "hostname-util.h"
 #include "import-raw.h"
 #include "import-tar.h"
 #include "import-util.h"
 #include "machine-image.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "verbs.h"
 
 static bool arg_force = false;
index a29e9d4bd5035237e9d1a9c28762e902d4431e90..4228681ceae3e17a2dd48e77a04b8e3dbd13cc02 100644 (file)
 #include <sys/prctl.h>
 
 #include "sd-bus.h"
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-common-errors.h"
-#include "socket-util.h"
-#include "mkdir.h"
+#include "bus-util.h"
 #include "def.h"
-#include "missing.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "import-util.h"
 #include "machine-pool.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
-#include "import-util.h"
 #include "process-util.h"
 #include "signal-util.h"
-#include "hostname-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "user-util.h"
+#include "util.h"
+#include "web-util.h"
 
 typedef struct Transfer Transfer;
 typedef struct Manager Manager;
index 1ddb48e03fd061fa0232cfde666f7d17509d6fd5..d6567ba7eec6c4f9c1991d65b5ddac4d176acd8c 100644 (file)
 
 #include <sys/prctl.h>
 
-#include "util.h"
-#include "strv.h"
-#include "copy.h"
-#include "rm-rf.h"
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "capability.h"
-#include "pull-job.h"
-#include "pull-common.h"
+#include "capability-util.h"
+#include "copy.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "pull-common.h"
+#include "pull-job.h"
+#include "rm-rf.h"
 #include "signal-util.h"
 #include "siphash24.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "web-util.h"
 
 #define FILENAME_ESCAPE "/.#\"\'"
 #define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16)
@@ -138,7 +146,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
         if (force_local)
                 (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
 
-        r = btrfs_subvol_snapshot(final, p, 0);
+        r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA);
         if (r == -ENOTTY) {
                 r = copy_tree(final, p, false);
                 if (r < 0)
@@ -366,9 +374,10 @@ int pull_verify(PullJob *main_job,
 
         log_info("SHA256 checksum of %s is valid.", main_job->url);
 
-        assert(!settings_job || settings_job->state == PULL_JOB_DONE);
+        assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
 
         if (settings_job &&
+            settings_job->state == PULL_JOB_DONE &&
             settings_job->error == 0 &&
             !settings_job->etag_exists) {
 
index 0dab184af12639f95252602d7c92b0a21720fe10..831470ff132f513e2769d3a21c7a209d75c0dfc5 100644 (file)
 #include <sys/prctl.h>
 
 #include "sd-daemon.h"
-#include "json.h"
-#include "strv.h"
+
+#include "alloc-util.h"
+#include "aufs-util.h"
 #include "btrfs-util.h"
-#include "utf8.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
+#include "json.h"
 #include "mkdir.h"
-#include "rm-rf.h"
 #include "path-util.h"
-#include "import-util.h"
-#include "curl-util.h"
-#include "aufs-util.h"
-#include "pull-job.h"
+#include "process-util.h"
 #include "pull-common.h"
-#include "import-common.h"
 #include "pull-dkr.h"
-#include "process-util.h"
-#include "hostname-util.h"
+#include "pull-job.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "web-util.h"
 
 typedef enum DkrProgress {
         DKR_SEARCHING,
@@ -476,13 +483,13 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
         if (!i->final_path) {
                 i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL);
                 if (!i->final_path)
-                        return log_oom();
+                        return -ENOMEM;
         }
 
         if (version == DKR_PULL_V2) {
-                r = path_get_parent(i->image_root, &p);
-                if (r < 0)
-                        return r;
+                p = dirname_malloc(i->image_root);
+                if (!p)
+                        return -ENOMEM;
         }
 
         r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local);
@@ -490,10 +497,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
                 return r;
 
         if (version == DKR_PULL_V2) {
-                char **k = NULL;
+                char **k;
+
                 STRV_FOREACH(k, i->ancestry) {
-                        _cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL);
-                        r = btrfs_subvol_remove(d, false);
+                        _cleanup_free_ char *d;
+
+                        d = strjoin(i->image_root, "/.dkr-", *k, NULL);
+                        if (!d)
+                                return -ENOMEM;
+
+                        r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA);
                         if (r < 0)
                                return r;
                 }
@@ -531,12 +544,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) {
                 const char *base_path;
 
                 base_path = strjoina(i->image_root, "/.dkr-", base);
-                r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
+                r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA);
         } else
                 r = btrfs_subvol_make(i->temp_path);
         if (r < 0)
                 return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
 
+        (void) import_assign_pool_quota_and_warn(i->temp_path);
+
         j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
         if (j->disk_fd < 0)
                 return j->disk_fd;
index 42939f21045d66c3d19829cfa130fba48e1c81e3..824fa246ec5486bab7c6e2129e11d7b5b93d4c64 100644 (file)
 
 #include <sys/xattr.h>
 
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
 #include "machine-pool.h"
+#include "parse-util.h"
 #include "pull-job.h"
+#include "string-util.h"
+#include "strv.h"
+#include "xattr-util.h"
 
 PullJob* pull_job_unref(PullJob *j) {
         if (!j)
index 0e77197e34e7048e05ccb5336164426eb4548a53..03bfb5175699c1af36c26d16fc69496b5a1f6bb9 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/xattr.h>
-#include <linux/fs.h>
 #include <curl/curl.h>
+#include <linux/fs.h>
+#include <sys/xattr.h>
 
 #include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "util.h"
+#include "chattr-util.h"
+#include "copy.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
 #include "macro.h"
 #include "mkdir.h"
-#include "rm-rf.h"
 #include "path-util.h"
-#include "hostname-util.h"
-#include "import-util.h"
-#include "import-common.h"
-#include "curl-util.h"
-#include "qcow2-util.h"
-#include "pull-job.h"
 #include "pull-common.h"
+#include "pull-job.h"
 #include "pull-raw.h"
+#include "qcow2-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "util.h"
+#include "web-util.h"
 
 typedef enum RawProgress {
         RAW_DOWNLOADING,
@@ -236,7 +244,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
 
         r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
+                log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
 
         log_info("Unpacking QCOW2 file.");
 
@@ -312,7 +320,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
          * writes. */
         r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp);
+                log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
 
         r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true);
         if (r < 0) {
@@ -327,8 +335,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
 
         r = rename(tp, p);
         if (r < 0)  {
+                r = log_error_errno(errno, "Failed to move writable image into place: %m");
                 unlink(tp);
-                return log_error_errno(errno, "Failed to move writable image into place: %m");
+                return r;
         }
 
         log_info("Created new local image '%s'.", i->local);
@@ -349,9 +358,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
                 if (r == -EEXIST)
                         log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
                 else if (r < 0 && r != -ENOENT)
-                        log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
-
-                log_info("Create new settings file '%s.nspawn'", i->local);
+                        log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
+                else
+                        log_info("Created new settings file '%s.nspawn'", i->local);
         }
 
         return 0;
@@ -503,7 +512,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
 
         r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
+                log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
 
         return 0;
 }
index 563765d83d1b3cc25f7a521998e9e2efba55a09a..e7fcd293f17eb8d4a3067936fbed018534a3119b 100644 (file)
 #include <curl/curl.h>
 
 #include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
+
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "util.h"
+#include "copy.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
 #include "macro.h"
 #include "mkdir.h"
-#include "rm-rf.h"
 #include "path-util.h"
 #include "process-util.h"
-#include "hostname-util.h"
-#include "import-util.h"
-#include "import-common.h"
-#include "curl-util.h"
-#include "pull-job.h"
 #include "pull-common.h"
+#include "pull-job.h"
 #include "pull-tar.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "util.h"
+#include "web-util.h"
 
 typedef enum TarProgress {
         TAR_DOWNLOADING,
@@ -247,9 +254,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
                 if (r == -EEXIST)
                         log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
                 else if (r < 0 && r != -ENOENT)
-                        log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
-
-                log_info("Create new settings file '%s.nspawn'", i->local);
+                        log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
+                else
+                        log_info("Created new settings file '%s.nspawn'", i->local);
         }
 
         return 0;
@@ -409,7 +416,9 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
                 if (mkdir(i->temp_path, 0755) < 0)
                         return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
         } else if (r < 0)
-                return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
+                return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path);
+        else
+                (void) import_assign_pool_quota_and_warn(i->temp_path);
 
         j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
         if (j->disk_fd < 0)
index 29e9424b52ddeb6b1cca476f5bb5d05b6ae5d11c..39f5b2d8e4415c93e7b8668730a1721ba84d205a 100644 (file)
 
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "event-util.h"
 #include "hostname-util.h"
 #include "import-util.h"
 #include "machine-image.h"
+#include "parse-util.h"
 #include "pull-dkr.h"
 #include "pull-raw.h"
 #include "pull-tar.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "verbs.h"
+#include "web-util.h"
 
 static bool arg_force = false;
 static const char *arg_image_root = "/var/lib/machines";
index fd3cf1b0e3bd5a8943a1d725d2aba7ce49830fb2..47dabaa86efaee93e0028a08ac4bba6aaf505d95 100644 (file)
 
 #include <zlib.h>
 
-#include "util.h"
-#include "sparse-endian.h"
-#include "qcow2-util.h"
+#include "alloc-util.h"
 #include "btrfs-util.h"
+#include "qcow2-util.h"
+#include "sparse-endian.h"
+#include "util.h"
 
 #define QCOW2_MAGIC 0x514649fb
 
index 9a6c3e8b35ae96bf81dde0b745c438f95567800a..4b600796194b74dda29032f6725ff196f8f8e3f5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "fd-util.h"
 #include "log.h"
-#include "util.h"
-
 #include "qcow2-util.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int sfd = -1, dfd = -1;
index 2d5f7501e7b013e7c04fe0c1746674adcf4bb848..d4f8673187c3de8ce14d906e14d20d4c4d796b5f 100644 (file)
 #include <sys/epoll.h>
 #include <ctype.h>
 
-#include "sd-daemon.h"
 #include "sd-bus.h"
+#include "sd-daemon.h"
 
-#include "util.h"
-#include "log.h"
-#include "list.h"
-#include "initreq.h"
-#include "special.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
+#include "bus-util.h"
 #include "def.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "initreq.h"
+#include "list.h"
+#include "log.h"
+#include "special.h"
+#include "util.h"
 
 #define SERVER_FD_MAX 16
 #define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
@@ -210,8 +212,7 @@ static int fifo_process(Fifo *f) {
                 if (errno == EAGAIN)
                         return 0;
 
-                log_warning_errno(errno, "Failed to read from fifo: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to read from fifo: %m");
         }
 
         f->bytes_read += l;
index b839e5979b1deb9234c30a97d347dc4e6b4847b8..6b93a758f65b3deb77630f710235b1285ad9d743 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include <getopt.h>
-#include <microhttpd.h>
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
 #endif
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
-#include "sd-journal.h"
-#include "sd-daemon.h"
 #include "sd-bus.h"
+#include "sd-daemon.h"
+#include "sd-journal.h"
 
+#include "alloc-util.h"
 #include "bus-util.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
 #include "log.h"
 #include "logs-show.h"
 #include "microhttpd-util.h"
+#include "parse-util.h"
 #include "sigbus.h"
 #include "util.h"
 
index 2e0f78701a5a9a1214b4f4e681d0ded6ffa001a1..3ff40228a0d3f6a395d5084099dea958349f3671 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "journal-remote-parse.h"
 #include "journald-native.h"
+#include "parse-util.h"
+#include "string-util.h"
 
 #define LINE_CHUNK 8*1024u
 
index 40f4ff8e58cf3238e68e95cc09c029f032c2f22c..d8250378b09508be738d83c00b2a5e4318cfedd3 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "journal-remote.h"
 
 int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
index c920ef76268759e2a31178016e8c181c3fc4dceb..b2f5fbf6b4caddaad2e0182893807ff563bf4594 100644 (file)
 
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
 #include "conf-parser.h"
+#include "def.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "journal-file.h"
+#include "journal-remote-write.h"
+#include "journal-remote.h"
 #include "journald-native.h"
 #include "macro.h"
+#include "parse-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
-#include "journal-remote-write.h"
-#include "journal-remote.h"
 
 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
 
@@ -137,7 +146,7 @@ static int spawn_curl(const char* url) {
 
         r = spawn_child("curl", argv);
         if (r < 0)
-                log_error_errno(errno, "Failed to spawn curl: %m");
+                log_error_errno(r, "Failed to spawn curl: %m");
         return r;
 }
 
@@ -156,7 +165,7 @@ static int spawn_getter(const char *getter, const char *url) {
 
         r = spawn_child(words[0], words);
         if (r < 0)
-                log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
+                log_error_errno(r, "Failed to spawn getter %s: %m", getter);
 
         return r;
 }
@@ -640,11 +649,12 @@ static int setup_microhttpd_server(RemoteServer *s,
                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
                 { MHD_OPTION_LISTEN_SOCKET, fd},
+                { MHD_OPTION_CONNECTION_MEMORY_LIMIT, DATA_SIZE_MAX},
                 { MHD_OPTION_END},
                 { MHD_OPTION_END},
                 { MHD_OPTION_END},
                 { MHD_OPTION_END}};
-        int opts_pos = 3;
+        int opts_pos = 4;
         int flags =
                 MHD_USE_DEBUG |
                 MHD_USE_DUAL_STACK |
@@ -1178,7 +1188,7 @@ static int parse_config(void) {
                 {}};
 
         return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
-                                 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
+                                 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
                                  "Remote\0", config_item_table_lookup, items,
                                  false, NULL);
 }
@@ -1407,18 +1417,21 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_GNUTLS_LOG: {
 #ifdef HAVE_GNUTLS
-                        const char *word, *state;
-                        size_t size;
+                        const char* p = optarg;
+                        for (;;) {
+                                _cleanup_free_ char *word = NULL;
 
-                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                char *cat;
+                                r = extract_first_word(&p, &word, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m");
 
-                                cat = strndup(word, size);
-                                if (!cat)
-                                        return log_oom();
+                                if (r == 0)
+                                        break;
 
-                                if (strv_consume(&arg_gnutls_log, cat) < 0)
+                                if (strv_push(&arg_gnutls_log, word) < 0)
                                         return log_oom();
+
+                                word = NULL;
                         }
                         break;
 #else
index 6b3ad924a736126b51b6580a6941fe1554fab1a2..3ee6d32bf72fb76750d3ca2a389dbf11d546b88e 100644 (file)
@@ -1,11 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2014 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 <stdbool.h>
 
 #include <curl/curl.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "journal-upload.h"
 #include "log.h"
 #include "utf8.h"
-#include "journal-upload.h"
+#include "util.h"
 
 /**
  * Write up to size bytes to buf. Return negative on error, and number of
index 92ce56805a6060bb7b07cd169fcb911067a224bf..6302266ccbf5c3faaa57043fc96e1e802c8e6971 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <curl/curl.h>
 #include <fcntl.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <sys/stat.h>
-#include <curl/curl.h>
 
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
 #include "conf-parser.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "glob-util.h"
+#include "journal-upload.h"
 #include "log.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "sigbus.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "util.h"
-#include "journal-upload.h"
 
 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
 #define CERT_FILE     CERTIFICATE_ROOT "/certs/journal-upload.pem"
@@ -536,7 +542,7 @@ static int parse_config(void) {
                 {}};
 
         return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
-                                 CONF_DIRS_NULSTR("systemd/journal-upload.conf"),
+                                 CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"),
                                  "Upload\0", config_item_table_lookup, items,
                                  false, NULL);
 }
index 9a8fb07c7fde0c5a01f09fbe4229232c1c209c59..fd6964e758269177423fc28e1af2f8acb653d6db 100755 (executable)
@@ -6,6 +6,8 @@ import argparse
 PARSER = argparse.ArgumentParser()
 PARSER.add_argument('n', type=int)
 PARSER.add_argument('--dots', action='store_true')
+PARSER.add_argument('--data-size', type=int, default=4000)
+PARSER.add_argument('--data-type', choices={'random', 'simple'})
 OPTIONS = PARSER.parse_args()
 
 template = """\
@@ -38,10 +40,16 @@ facility = 6
 src = open('/dev/urandom', 'rb')
 
 bytes = 0
+counter = 0
 
 for i in range(OPTIONS.n):
     message = repr(src.read(2000))
-    data = repr(src.read(4000))
+    if OPTIONS.data_type == 'random':
+        data = repr(src.read(OPTIONS.data_size))
+    else:
+        # keep the pattern non-repeating so we get a different blob every time
+        data = '{:0{}}'.format(counter, OPTIONS.data_size)
+        counter += 1
 
     entry = template.format(m=m,
                             realtime_ts=realtime_ts,
index 8a11fba04441953d7242c87e1e480920a295cf3e..b2c398a845b83e0baf7c33b66c2d5a1cf8e8cc24 100644 (file)
 #include <stdio.h>
 #include <string.h>
 
-#include "microhttpd-util.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "strv.h"
-
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
 #endif
 
+#include "alloc-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "microhttpd-util.h"
+
 void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
         char *f;
 
index f9b279d7de8ddb8e31a672f32e322199c78ebdf4..7fd4198df88b16efb46a0f24e59c8ba7a89fd599 100644 (file)
 
 #include "sd-journal.h"
 
+#include "fd-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
 #include "util.h"
 
 static char *arg_identifier = NULL;
index 4c43500ef5f320a045761d3c7308df2a713fb6ca..fcaa54aa0c9b2e8235535a52f9793aad64dfdd5b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <errno.h>
 #include <fcntl.h>
+#include <locale.h>
 #include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
 #include <string.h>
 #include <sys/mman.h>
-#include <locale.h>
+#include <unistd.h>
 
-#include "util.h"
-#include "log.h"
-#include "sparse-endian.h"
 #include "sd-id128.h"
-#include "hashmap.h"
-#include "strv.h"
-#include "strbuf.h"
+
+#include "alloc-util.h"
+#include "catalog.h"
 #include "conf-files.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "log.h"
 #include "mkdir.h"
-#include "catalog.h"
+#include "path-util.h"
 #include "siphash24.h"
+#include "sparse-endian.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 const char * const catalog_file_dirs[] = {
         "/usr/local/lib/systemd/catalog/",
@@ -202,7 +208,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
 
         r = catalog_file_lang(path, &deflang);
         if (r < 0)
-                log_error_errno(errno, "Failed to determine language for file %s: %m", path);
+                log_error_errno(r, "Failed to determine language for file %s: %m", path);
         if (r == 1)
                 log_debug("File %s has language %s.", path, deflang);
 
@@ -215,8 +221,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
                         if (feof(f))
                                 break;
 
-                        log_error_errno(errno, "Failed to read file %s: %m", path);
-                        return -errno;
+                        return log_error_errno(errno, "Failed to read file %s: %m", path);
                 }
 
                 n++;
@@ -313,8 +318,8 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
         return 0;
 }
 
-static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
-                          CatalogItem *items, size_t n) {
+static int64_t write_catalog(const char *database, struct strbuf *sb,
+                             CatalogItem *items, size_t n) {
         CatalogHeader header;
         _cleanup_fclose_ FILE *w = NULL;
         int r;
@@ -338,7 +343,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
         memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
         header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
         header.catalog_item_size = htole64(sizeof(CatalogItem));
-        header.n_items = htole64(hashmap_size(h));
+        header.n_items = htole64(n);
 
         r = -EIO;
 
@@ -373,7 +378,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
                 goto error;
         }
 
-        return ftell(w);
+        return ftello(w);
 
 error:
         (void) unlink(p);
@@ -389,7 +394,8 @@ int catalog_update(const char* database, const char* root, const char* const* di
         CatalogItem *i;
         Iterator j;
         unsigned n;
-        long r;
+        int r;
+        int64_t sz;
 
         h = hashmap_new(&catalog_hash_ops);
         sb = strbuf_new();
@@ -439,18 +445,19 @@ int catalog_update(const char* database, const char* root, const char* const* di
         assert(n == hashmap_size(h));
         qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
 
-        r = write_catalog(database, h, sb, items, n);
-        if (r < 0)
-                log_error_errno(r, "Failed to write %s: %m", database);
-        else
-                log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
-                          database, n, sb->len, r);
+        sz = write_catalog(database, sb, items, n);
+        if (sz < 0)
+                r = log_error_errno(sz, "Failed to write %s: %m", database);
+        else {
+                r = 0;
+                log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total size.",
+                          database, n, sb->len, sz);
+        }
 
 finish:
-        if (sb)
-                strbuf_cleanup(sb);
+        strbuf_cleanup(sb);
 
-        return r < 0 ? r : 0;
+        return r;
 }
 
 static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
index c66043e50364d65638d15e0fbcfa1cdbc076383c..e1ca0a8818edd6cbc6394e2ac1e8735b58f366cb 100644 (file)
 
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <unistd.h>
 
 #ifdef HAVE_XZ
-#  include <lzma.h>
+#include <lzma.h>
 #endif
 
 #ifdef HAVE_LZ4
-#  include <lz4.h>
+#include <lz4.h>
+#include <lz4frame.h>
 #endif
 
+#include "alloc-util.h"
 #include "compress.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "journal-def.h"
 #include "macro.h"
-#include "util.h"
 #include "sparse-endian.h"
-#include "journal-def.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+
+#ifdef HAVE_LZ4
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext);
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
+#endif
 
 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
 
@@ -50,10 +62,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_
 #ifdef HAVE_XZ
         static const lzma_options_lzma opt = {
                 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
-                LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4};
-        static const lzma_filter filters[2] = {
-                {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt},
-                {LZMA_VLI_UNKNOWN, NULL}
+                LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4
+        };
+        static const lzma_filter filters[] = {
+                { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt },
+                { LZMA_VLI_UNKNOWN, NULL }
         };
         lzma_ret ret;
         size_t out_pos = 0;
@@ -416,81 +429,96 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 #endif
 }
 
-#define LZ4_BUFSIZE (512*1024)
+#define LZ4_BUFSIZE (512*1024u)
 
 int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
 
 #ifdef HAVE_LZ4
+        LZ4F_errorCode_t c;
+        _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
+        _cleanup_free_ char *buf = NULL;
+        char *src = NULL;
+        size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size;
+        struct stat st;
+        int r;
+        static const LZ4F_compressOptions_t options = {
+                .stableSrc = 1,
+        };
+        static const LZ4F_preferences_t preferences = {
+                .frameInfo.blockSizeID = 5,
+        };
 
-        _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL;
-        char *buf;
-        LZ4_stream_t lz4_data = {};
-        le32_t header;
-        size_t total_in = 0, total_out = sizeof(header);
-        ssize_t n;
+        c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
+        if (LZ4F_isError(c))
+                return -ENOMEM;
 
-        assert(fdf >= 0);
-        assert(fdt >= 0);
+        if (fstat(fdf, &st) < 0)
+                return log_debug_errno(errno, "fstat() failed: %m");
 
-        buf1 = malloc(LZ4_BUFSIZE);
-        buf2 = malloc(LZ4_BUFSIZE);
-        out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE));
-        if (!buf1 || !buf2 || !out)
-                return log_oom();
+        frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences);
+        size =  frame_size + 64*1024; /* add some space for header and trailer */
+        buf = malloc(size);
+        if (!buf)
+                return -ENOMEM;
 
-        buf = buf1;
-        for (;;) {
-                size_t m;
-                int r;
+        n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences);
+        if (LZ4F_isError(n))
+                return -EINVAL;
 
-                m = LZ4_BUFSIZE;
-                if (max_bytes != (uint64_t) -1 && (uint64_t) m > (max_bytes - total_in))
-                        m = (size_t) (max_bytes - total_in);
+        src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0);
+        if (src == MAP_FAILED)
+                return -errno;
 
-                n = read(fdf, buf, m);
-                if (n < 0)
-                        return -errno;
-                if (n == 0)
-                        break;
+        log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n);
 
-                total_in += n;
+        while (total_in < (size_t) st.st_size) {
+                ssize_t k;
 
-                r = LZ4_compress_continue(&lz4_data, buf, out, n);
-                if (r == 0) {
-                        log_error("LZ4 compression failed.");
-                        return -EBADMSG;
+                k = MIN(LZ4_BUFSIZE, st.st_size - total_in);
+                n = LZ4F_compressUpdate(ctx, buf + offset, size - offset,
+                                        src + total_in, k, &options);
+                if (LZ4F_isError(n)) {
+                        r = -ENOTRECOVERABLE;
+                        goto cleanup;
                 }
 
-                header = htole32(r);
-                errno = 0;
-
-                n = write(fdt, &header, sizeof(header));
-                if (n < 0)
-                        return -errno;
-                if (n != sizeof(header))
-                        return errno ? -errno : -EIO;
+                total_in += k;
+                offset += n;
+                total_out += n;
 
-                n = loop_write(fdt, out, r, false);
-                if (n < 0)
-                        return n;
+                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+                        log_debug("Compressed stream longer than %zd bytes", max_bytes);
+                        return -EFBIG;
+                }
 
-                total_out += sizeof(header) + r;
+                if (size - offset < frame_size + 4) {
+                        k = loop_write(fdt, buf, offset, false);
+                        if (k < 0) {
+                                r = k;
+                                goto cleanup;
+                        }
+                        offset = 0;
+                }
+        }
 
-                buf = buf == buf1 ? buf2 : buf1;
+        n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options);
+        if (LZ4F_isError(n)) {
+                r = -ENOTRECOVERABLE;
+                goto cleanup;
         }
 
-        header = htole32(0);
-        n = write(fdt, &header, sizeof(header));
-        if (n < 0)
-                return -errno;
-        if (n != sizeof(header))
-                return errno ? -errno : -EIO;
+        offset += n;
+        total_out += n;
+        r = loop_write(fdt, buf, offset, false);
+        if (r < 0)
+                goto cleanup;
 
         log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
                   total_in, total_out,
                   (double) total_out / total_in * 100);
-
-        return 0;
+ cleanup:
+        munmap(src, st.st_size);
+        return r;
 #else
         return -EPROTONOSUPPORT;
 #endif
@@ -510,7 +538,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 
         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
         if (ret != LZMA_OK) {
-                log_error("Failed to initialize XZ decoder: code %u", ret);
+                log_debug("Failed to initialize XZ decoder: code %u", ret);
                 return -ENOMEM;
         }
 
@@ -536,7 +564,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 
                 ret = lzma_code(&s, action);
                 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
-                        log_error("Decompression failed: code %u", ret);
+                        log_debug("Decompression failed: code %u", ret);
                         return -EBADMSG;
                 }
 
@@ -566,14 +594,14 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
                 }
         }
 #else
-        log_error("Cannot decompress file. Compiled without XZ support.");
+        log_debug("Cannot decompress file. Compiled without XZ support.");
         return -EPROTONOSUPPORT;
 #endif
 }
 
-int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
-
 #ifdef HAVE_LZ4
+static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) {
+
         _cleanup_free_ char *buf = NULL, *out = NULL;
         size_t buf_size = 0;
         LZ4_streamDecode_t lz4_data = {};
@@ -585,7 +613,7 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
 
         out = malloc(4*LZ4_BUFSIZE);
         if (!out)
-                return log_oom();
+                return -ENOMEM;
 
         for (;;) {
                 ssize_t m;
@@ -606,22 +634,24 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
                  * not accept buffers compressed by newer binaries then.
                  */
                 if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
-                        log_error("Compressed stream block too big: %zd bytes", m);
-                        return -EBADMSG;
+                        log_debug("Compressed stream block too big: %zd bytes", m);
+                        return -ENOBUFS;
                 }
 
                 total_in += sizeof(header) + m;
 
                 if (!GREEDY_REALLOC(buf, buf_size, m))
-                        return log_oom();
+                        return -ENOMEM;
 
                 r = loop_read_exact(fdf, buf, m, false);
                 if (r < 0)
                         return r;
 
                 r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
-                if (r <= 0)
-                        log_error("LZ4 decompression failed.");
+                if (r <= 0) {
+                        log_debug("LZ4 decompression failed (legacy format).");
+                        return -EBADMSG;
+                }
 
                 total_out += r;
 
@@ -635,13 +665,80 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
                         return r;
         }
 
-        log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+        log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)",
                   total_in, total_out,
                   (double) total_out / total_in * 100);
 
         return 0;
+}
+
+static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) {
+        size_t c;
+        _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
+        _cleanup_free_ char *buf = NULL;
+        char *src;
+        struct stat st;
+        int r = 0;
+        size_t total_in = 0, total_out = 0;
+
+        c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
+        if (LZ4F_isError(c))
+                return -ENOMEM;
+
+        if (fstat(in, &st) < 0)
+                return log_debug_errno(errno, "fstat() failed: %m");
+
+        buf = malloc(LZ4_BUFSIZE);
+        if (!buf)
+                return -ENOMEM;
+
+        src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0);
+        if (src == MAP_FAILED)
+                return -errno;
+
+        while (total_in < (size_t) st.st_size) {
+                size_t produced = LZ4_BUFSIZE;
+                size_t used = st.st_size - total_in;
+
+                c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL);
+                if (LZ4F_isError(c)) {
+                        r = -EBADMSG;
+                        goto cleanup;
+                }
+
+                total_in += used;
+                total_out += produced;
+
+                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+                        log_debug("Decompressed stream longer than %zd bytes", max_bytes);
+                        r = -EFBIG;
+                        goto cleanup;
+                }
+
+                r = loop_write(out, buf, produced, false);
+                if (r < 0)
+                        goto cleanup;
+        }
+
+        log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+                  total_in, total_out,
+                  (double) total_out / total_in * 100);
+ cleanup:
+        munmap(src, st.st_size);
+        return r;
+}
+#endif
+
+int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
+#ifdef HAVE_LZ4
+        int r;
+
+        r = decompress_stream_lz4_v2(fdf, fdt, max_bytes);
+        if (r == -EBADMSG)
+                r = decompress_stream_lz4_v1(fdf, fdt, max_bytes);
+        return r;
 #else
-        log_error("Cannot decompress file. Compiled without LZ4 support.");
+        log_debug("Cannot decompress file. Compiled without LZ4 support.");
         return -EPROTONOSUPPORT;
 #endif
 }
index efe418615a6cd26c9bf5217e65bc4d15c7ecc8cd..39bc2e4270909cae4e240a911f5df5f71087a270 100644 (file)
 
 #include <sys/statvfs.h>
 
-#include "util.h"
-#include "time-util.h"
+#include "alloc-util.h"
+#include "coredump-vacuum.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "hashmap.h"
 #include "macro.h"
-
-#include "coredump-vacuum.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "user-util.h"
+#include "util.h"
 
 #define DEFAULT_MAX_USE_LOWER (uint64_t) (1ULL*1024ULL*1024ULL)           /* 1 MiB */
 #define DEFAULT_MAX_USE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL)   /* 4 GiB */
index e1e66b982623acdff0e324fc2e2b779ac371ddfa..f750ddfcbd625eb54a94d81bbfb39e8c1637db21 100644 (file)
 ***/
 
 #include <errno.h>
-#include <unistd.h>
 #include <stdio.h>
 #include <sys/prctl.h>
 #include <sys/xattr.h>
+#include <unistd.h>
 
 #ifdef HAVE_ELFUTILS
 #  include <dwarf.h>
 
 #include "sd-journal.h"
 #include "sd-login.h"
-#include "log.h"
-#include "util.h"
-#include "fileio.h"
-#include "strv.h"
-#include "macro.h"
-#include "mkdir.h"
-#include "special.h"
+
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "capability-util.h"
 #include "cgroup-util.h"
+#include "compress.h"
 #include "conf-parser.h"
 #include "copy.h"
-#include "stacktrace.h"
-#include "compress.h"
-#include "acl-util.h"
-#include "capability.h"
-#include "journald-native.h"
 #include "coredump-vacuum.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "journald-native.h"
+#include "log.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "special.h"
+#include "stacktrace.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 /* The maximum size up to which we process coredumps */
 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
@@ -115,8 +126,8 @@ static int parse_config(void) {
                 {}
         };
 
-        return config_parse_many("/etc/systemd/coredump.conf",
-                                 CONF_DIRS_NULSTR("systemd/coredump.conf"),
+        return config_parse_many(PKGSYSCONFDIR "/coredump.conf",
+                                 CONF_PATHS_NULSTR("systemd/coredump.conf.d"),
                                  "Coredump\0",
                                  config_item_table_lookup, items,
                                  false, NULL);
@@ -128,6 +139,7 @@ static int fix_acl(int fd, uid_t uid) {
         _cleanup_(acl_freep) acl_t acl = NULL;
         acl_entry_t entry;
         acl_permset_t permset;
+        int r;
 
         assert(fd >= 0);
 
@@ -149,11 +161,12 @@ static int fix_acl(int fd, uid_t uid) {
         }
 
         if (acl_get_permset(entry, &permset) < 0 ||
-            acl_add_perm(permset, ACL_READ) < 0 ||
-            calc_acl_mask_if_needed(&acl) < 0) {
-                log_warning_errno(errno, "Failed to patch ACL: %m");
-                return -errno;
-        }
+            acl_add_perm(permset, ACL_READ) < 0)
+                return log_warning_errno(errno, "Failed to patch ACL: %m");
+
+        r = calc_acl_mask_if_needed(&acl);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to patch ACL: %m");
 
         if (acl_set_fd(fd, acl) < 0)
                 return log_error_errno(errno, "Failed to apply ACL: %m");
index dde56008c152a00549146f96995f6eff65f53e11..1df28d774ad748a18a2fa6c423c1f7657701fe5a 100644 (file)
 
 #include "sd-journal.h"
 
+#include "alloc-util.h"
 #include "compress.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "journal-internal.h"
 #include "log.h"
 #include "macro.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "set.h"
 #include "sigbus.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "user-util.h"
 #include "util.h"
 
 static enum {
@@ -84,37 +90,35 @@ static Set *new_matches(void) {
 }
 
 static int add_match(Set *set, const char *match) {
-        int r = -ENOMEM;
-        unsigned pid;
-        const char* prefix;
-        char *pattern = NULL;
         _cleanup_free_ char *p = NULL;
+        char *pattern = NULL;
+        const char* prefix;
+        pid_t pid;
+        int r;
 
         if (strchr(match, '='))
                 prefix = "";
         else if (strchr(match, '/')) {
-                p = path_make_absolute_cwd(match);
-                if (!p)
+                r = path_make_absolute_cwd(match, &p);
+                if (r < 0)
                         goto fail;
-
                 match = p;
                 prefix = "COREDUMP_EXE=";
-        }
-        else if (safe_atou(match, &pid) == 0)
+        } else if (parse_pid(match, &pid) >= 0)
                 prefix = "COREDUMP_PID=";
         else
                 prefix = "COREDUMP_COMM=";
 
         pattern = strjoin(prefix, match, NULL);
-        if (!pattern)
+        if (!pattern) {
+                r = -ENOMEM;
                 goto fail;
+        }
 
         log_debug("Adding pattern: %s", pattern);
         r = set_consume(set, pattern);
-        if (r < 0) {
-                log_error_errno(r, "Failed to add pattern: %m");
+        if (r < 0)
                 goto fail;
-        }
 
         return 0;
 fail:
@@ -613,7 +617,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
 
                         fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
                         if (fdt < 0)
-                                return log_error_errno(errno, "Failed to create temporary file: %m");
+                                return log_error_errno(fdt, "Failed to create temporary file: %m");
                         log_debug("Created temporary file %s", temp);
 
                         fd = fdt;
@@ -772,7 +776,7 @@ static int run_gdb(sd_journal *j) {
 
         r = wait_for_terminate(pid, &st);
         if (r < 0) {
-                log_error_errno(errno, "Failed to wait for gdb: %m");
+                log_error_errno(r, "Failed to wait for gdb: %m");
                 goto finish;
         }
 
index 150d034828f329ab2b5672f4c75c1ba3b6d7b8ec..5959b1fed2f8e6a83d21567faf7afc26325801b4 100644 (file)
@@ -29,6 +29,7 @@
 #include <inttypes.h>
 
 #include "macro.h"
+#include "util.h"
 
 #ifdef __cplusplus
 extern "C" {
index cdc80e2d26fa89a81607e30eabfc2c53eb1d2659..0c4ac5cdc38d1b2f4c39cf6c29553a2b874b5a55 100644 (file)
 #include <fcntl.h>
 #include <sys/mman.h>
 
+#include "fd-util.h"
+#include "fsprg.h"
+#include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
-#include "journal-authenticate.h"
-#include "fsprg.h"
+#include "hexdecoct.h"
 
 static uint64_t journal_file_tag_seqnum(JournalFile *f) {
         uint64_t r;
index 39c9dd0dbfba65c5a29a856c7ffefc922fe97363..c003ac05dd027eeefaa2a1fe1688b31644ef7f2e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "sparse-endian.h"
-
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
 
 #include "macro.h"
+#include "sparse-endian.h"
 
 /*
  * If you change this file you probably should also change its documentation:
index 1071c6d6d73dfa34df64f026266b82ba08b53f1b..f9ff9545dddd7493e500ff32b2060ff53bfa3a7a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/mman.h>
 #include <errno.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <sys/statvfs.h>
 #include <fcntl.h>
-#include <stddef.h>
 #include <linux/fs.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/statvfs.h>
+#include <sys/uio.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
 #include "btrfs-util.h"
+#include "chattr-util.h"
+#include "compress.h"
+#include "fd-util.h"
+#include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
-#include "journal-authenticate.h"
 #include "lookup3.h"
-#include "compress.h"
+#include "parse-util.h"
 #include "random-util.h"
+#include "string-util.h"
+#include "xattr-util.h"
 
 #define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
 #define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
@@ -42,7 +48,7 @@
 #define COMPRESSION_SIZE_THRESHOLD (512ULL)
 
 /* This is the minimum journal file size */
-#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL)           /* 4 MiB */
+#define JOURNAL_FILE_SIZE_MIN (512ULL*1024ULL)                 /* 512 KiB */
 
 /* These are the lower and upper bounds if we deduce the max_use value
  * from the file system size */
@@ -1057,7 +1063,7 @@ static int journal_file_append_data(
         r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p);
         if (r < 0)
                 return r;
-        else if (r > 0) {
+        if (r > 0) {
 
                 if (ret)
                         *ret = o;
@@ -1076,23 +1082,24 @@ static int journal_file_append_data(
         o->data.hash = htole64(hash);
 
 #if defined(HAVE_XZ) || defined(HAVE_LZ4)
-        if (f->compress_xz &&
-            size >= COMPRESSION_SIZE_THRESHOLD) {
+        if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) {
                 size_t rsize = 0;
 
                 compression = compress_blob(data, size, o->data.payload, &rsize);
 
-                if (compression) {
+                if (compression >= 0) {
                         o->object.size = htole64(offsetof(Object, data.payload) + rsize);
                         o->object.flags |= compression;
 
                         log_debug("Compressed data object %"PRIu64" -> %zu using %s",
                                   size, rsize, object_compressed_to_string(compression));
-                }
+                } else
+                        /* Compression didn't work, we don't really care why, let's continue without compression */
+                        compression = 0;
         }
 #endif
 
-        if (!compression && size > 0)
+        if (compression == 0 && size > 0)
                 memcpy(o->data.payload, data, size);
 
         r = journal_file_link_data(f, o, p, hash);
@@ -2698,7 +2705,7 @@ int journal_file_open(
         }
 
         if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
-                r = -EIO;
+                r = -ENODATA;
                 goto fail;
         }
 
index f2c07356c82c543e2d21fdb8c5d24edb5e461c36..898d12d9924d331a0f70b4c5eebbb9d17727252f 100644 (file)
@@ -235,3 +235,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
 
 int journal_file_map_data_hash_table(JournalFile *f);
 int journal_file_map_field_hash_table(JournalFile *f);
+
+static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) {
+        assert(f);
+        return f->compress_xz || f->compress_lz4;
+}
index b51ecdb600a5a4c39793a6dc0b47f78b8113be3c..06847402e0c79216b2d9c35fc374e026f9b7afd0 100644 (file)
 #include <inttypes.h>
 #include <stdbool.h>
 
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
+#include "sd-journal.h"
 
+#include "hashmap.h"
 #include "journal-def.h"
+#include "journal-file.h"
 #include "list.h"
-#include "hashmap.h"
 #include "set.h"
-#include "journal-file.h"
-#include "sd-journal.h"
 
 typedef struct Match Match;
 typedef struct Location Location;
@@ -121,7 +121,7 @@ struct sd_journal {
         Hashmap *directories_by_path;
         Hashmap *directories_by_wd;
 
-        Set *errors;
+        Hashmap *errors;
 };
 
 char *journal_make_match_string(sd_journal *j);
index 3ff6a3ad4aee2291dfb8eba76bbd0d832322995e..7d14e8754b3526a4957aa0c3c48b55e1ffd4387e 100644 (file)
@@ -21,8 +21,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <inttypes.h>
 #include <stdio.h>
 
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
 
 int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine);
index dc1b2105dd1b2df862b84f2132ffc53be6a2e1d8..fa5dee73c31f027b58a8ac16feb9ec7482bca107 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
-#include <sys/un.h>
 #include <errno.h>
-#include <stddef.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include <printf.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
 
 #define SD_JOURNAL_SUPPRESS_LOCATION
 
 #include "sd-journal.h"
-#include "util.h"
-#include "socket-util.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "io-util.h"
 #include "memfd-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
index a394066cb4e2ef9322ee95520fae3568321a55b4..4b5fc76eb14f8ad9a62aee52ba88000eff428209 100644 (file)
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "journal-def.h"
 #include "journal-file.h"
 #include "journal-vacuum.h"
-#include "sd-id128.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "util.h"
+#include "xattr-util.h"
 
 struct vacuum_info {
         uint64_t usage;
@@ -217,13 +224,11 @@ int journal_directory_vacuum(
 
                         de->d_name[q-8-16-1-16-1] = 0;
                         if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
-                                free(p);
                                 n_active_files++;
                                 continue;
                         }
 
                         if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
-                                free(p);
                                 n_active_files++;
                                 continue;
                         }
@@ -253,7 +258,6 @@ int journal_directory_vacuum(
                         }
 
                         if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
-                                free(p);
                                 n_active_files ++;
                                 continue;
                         }
index 32d59c716fecccf3b1e2972401f618557ba06d7f..3676cb87887dbeca4067b5a8de19f43821b9b21b 100644 (file)
 #include <fcntl.h>
 #include <stddef.h>
 
-#include "util.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
-#include "journal-authenticate.h"
 #include "journal-verify.h"
 #include "lookup3.h"
-#include "compress.h"
+#include "macro.h"
 #include "terminal-util.h"
+#include "util.h"
 
 static void draw_progress(uint64_t p, usec_t *last_usec) {
         unsigned n, i, j, k;
@@ -839,19 +842,19 @@ int journal_file_verify(
 
         data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
         if (data_fd < 0) {
-                r = log_error_errno(errno, "Failed to create data file: %m");
+                r = log_error_errno(data_fd, "Failed to create data file: %m");
                 goto fail;
         }
 
         entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
         if (entry_fd < 0) {
-                r = log_error_errno(errno, "Failed to create entry file: %m");
+                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);
         if (entry_array_fd < 0) {
-                r = log_error_errno(errno,
+                r = log_error_errno(entry_array_fd,
                                     "Failed to create entry array file: %m");
                 goto fail;
         }
@@ -897,7 +900,7 @@ int journal_file_verify(
 
                 r = journal_file_object_verify(f, p, o);
                 if (r < 0) {
-                        error(p, "Envalid object contents: %s", strerror(-r));
+                        error(p, "Invalid object contents: %s", strerror(-r));
                         goto fail;
                 }
 
index d9851db36cb4e91de59b867bd276a6bbd935d8a2..75a48c761cc77ea3dc029c135a308c443c3e14e8 100644 (file)
 #include "sd-journal.h"
 
 #include "acl-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "catalog.h"
+#include "chattr-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "fsprg.h"
+#include "glob-util.h"
 #include "hostname-util.h"
+#include "io-util.h"
 #include "journal-def.h"
 #include "journal-internal.h"
 #include "journal-qrcode.h"
 #include "journal-vacuum.h"
 #include "journal-verify.h"
+#include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
 #include "mkdir.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "rlimit-util.h"
 #include "set.h"
 #include "sigbus.h"
 #include "strv.h"
+#include "syslog-util.h"
 #include "terminal-util.h"
 #include "unit-name.h"
+#include "user-util.h"
 
 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
 
@@ -104,7 +115,7 @@ static const char *arg_field = NULL;
 static bool arg_catalog = false;
 static bool arg_reverse = false;
 static int arg_journal_type = 0;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
 static const char *arg_machine = NULL;
 static uint64_t arg_vacuum_size = 0;
 static uint64_t arg_vacuum_n_files = 0;
@@ -122,6 +133,7 @@ static enum {
         ACTION_UPDATE_CATALOG,
         ACTION_LIST_BOOTS,
         ACTION_FLUSH,
+        ACTION_SYNC,
         ACTION_ROTATE,
         ACTION_VACUUM,
 } arg_action = ACTION_SHOW;
@@ -190,12 +202,12 @@ static void help(void) {
 
         printf("%s [OPTIONS...] [MATCHES...]\n\n"
                "Query the journal.\n\n"
-               "Flags:\n"
+               "Options:\n"
                "     --system              Show the system journal\n"
                "     --user                Show the user journal for the current user\n"
                "  -M --machine=CONTAINER   Operate on local container\n"
-               "     --since=DATE          Show entries not older than the specified date\n"
-               "     --until=DATE          Show entries not newer than the specified date\n"
+               "  -S --since=DATE          Show entries not older than the specified date\n"
+               "  -U --until=DATE          Show entries not newer than the specified date\n"
                "  -c --cursor=CURSOR       Show entries starting at the specified cursor\n"
                "     --after-cursor=CURSOR Show entries after the specified cursor\n"
                "     --show-cursor         Print the cursor after all the entries\n"
@@ -218,12 +230,12 @@ static void help(void) {
                "  -x --catalog             Add message explanations where available\n"
                "     --no-full             Ellipsize fields\n"
                "  -a --all                 Show all fields, including long and unprintable\n"
-               "  -q --quiet               Do not show privilege warning\n"
+               "  -q --quiet               Do not show info messages and privilege warning\n"
                "     --no-pager            Do not pipe output into a pager\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"
-               "     --root=ROOT           Operate on catalog files underneath the root ROOT\n"
+               "     --root=ROOT           Operate on catalog files below a root directory\n"
 #ifdef HAVE_GCRYPT
                "     --interval=TIME       Time interval for changing the FSS sealing key\n"
                "     --verify-key=KEY      Specify FSS verification key\n"
@@ -233,20 +245,21 @@ static void help(void) {
                "  -h --help                Show this help text\n"
                "     --version             Show package version\n"
                "  -F --field=FIELD         List all values that a specified field takes\n"
-               "     --new-id128           Generate a new 128-bit ID\n"
                "     --disk-usage          Show total disk usage of all journal files\n"
                "     --vacuum-size=BYTES   Reduce disk usage below specified size\n"
                "     --vacuum-files=INT    Leave only the specified number of journal files\n"
                "     --vacuum-time=TIME    Remove journal files older than specified time\n"
+               "     --verify              Verify journal file consistency\n"
+               "     --sync                Synchronize unwritten journal messages to disk\n"
                "     --flush               Flush all journal data from /run into /var\n"
                "     --rotate              Request immediate rotation of the journal files\n"
                "     --header              Show journal header information\n"
                "     --list-catalog        Show all message IDs in the catalog\n"
                "     --dump-catalog        Show entries in the message catalog\n"
                "     --update-catalog      Update the message catalog database\n"
+               "     --new-id128           Generate a new 128-bit ID\n"
 #ifdef HAVE_GCRYPT
                "     --setup-keys          Generate a new FSS key pair\n"
-               "     --verify              Verify journal file consistency\n"
 #endif
                , program_invocation_short_name);
 }
@@ -270,8 +283,6 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERIFY,
                 ARG_VERIFY_KEY,
                 ARG_DISK_USAGE,
-                ARG_SINCE,
-                ARG_UNTIL,
                 ARG_AFTER_CURSOR,
                 ARG_SHOW_CURSOR,
                 ARG_USER_UNIT,
@@ -280,6 +291,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_UPDATE_CATALOG,
                 ARG_FORCE,
                 ARG_UTC,
+                ARG_SYNC,
                 ARG_FLUSH,
                 ARG_ROTATE,
                 ARG_VACUUM_SIZE,
@@ -323,8 +335,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "cursor",         required_argument, NULL, 'c'                },
                 { "after-cursor",   required_argument, NULL, ARG_AFTER_CURSOR   },
                 { "show-cursor",    no_argument,       NULL, ARG_SHOW_CURSOR    },
-                { "since",          required_argument, NULL, ARG_SINCE          },
-                { "until",          required_argument, NULL, ARG_UNTIL          },
+                { "since",          required_argument, NULL, 'S'                },
+                { "until",          required_argument, NULL, 'U'                },
                 { "unit",           required_argument, NULL, 'u'                },
                 { "user-unit",      required_argument, NULL, ARG_USER_UNIT      },
                 { "field",          required_argument, NULL, 'F'                },
@@ -336,6 +348,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "machine",        required_argument, NULL, 'M'                },
                 { "utc",            no_argument,       NULL, ARG_UTC            },
                 { "flush",          no_argument,       NULL, ARG_FLUSH          },
+                { "sync",           no_argument,       NULL, ARG_SYNC           },
                 { "rotate",         no_argument,       NULL, ARG_ROTATE         },
                 { "vacuum-size",    required_argument, NULL, ARG_VACUUM_SIZE    },
                 { "vacuum-files",   required_argument, NULL, ARG_VACUUM_FILES   },
@@ -348,7 +361,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -507,7 +520,9 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case 'c':
@@ -646,7 +661,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_SINCE:
+                case 'S':
                         r = parse_timestamp(optarg, &arg_since);
                         if (r < 0) {
                                 log_error("Failed to parse timestamp: %s", optarg);
@@ -655,7 +670,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_since_set = true;
                         break;
 
-                case ARG_UNTIL:
+                case 'U':
                         r = parse_timestamp(optarg, &arg_until);
                         if (r < 0) {
                                 log_error("Failed to parse timestamp: %s", optarg);
@@ -718,6 +733,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_ROTATE;
                         break;
 
+                case ARG_SYNC:
+                        arg_action = ACTION_SYNC;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -748,7 +767,7 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (arg_action != ACTION_SHOW && optind < argc) {
+        if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
                 log_error("Extraneous arguments starting with '%s'", argv[optind]);
                 return -EINVAL;
         }
@@ -1472,7 +1491,7 @@ static int setup_keys(void) {
         safe_close(fd);
         fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
         if (fd < 0) {
-                r = log_error_errno(errno, "Failed to open %s: %m", k);
+                r = log_error_errno(fd, "Failed to open %s: %m", k);
                 goto finish;
         }
 
@@ -1480,7 +1499,7 @@ static int setup_keys(void) {
          * writing and in-place updating */
         r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
         if (r < 0)
-                log_warning_errno(errno, "Failed to set file attributes: %m");
+                log_warning_errno(r, "Failed to set file attributes: %m");
 
         zero(h);
         memcpy(h.signature, "KSHHRHLP", 8);
@@ -1697,36 +1716,50 @@ static int access_check_var_log_journal(sd_journal *j) {
 static int access_check(sd_journal *j) {
         Iterator it;
         void *code;
+        char *path;
         int r = 0;
 
         assert(j);
 
-        if (set_isempty(j->errors)) {
+        if (hashmap_isempty(j->errors)) {
                 if (ordered_hashmap_isempty(j->files))
                         log_notice("No journal files were found.");
 
                 return 0;
         }
 
-        if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
+        if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) {
                 (void) access_check_var_log_journal(j);
 
                 if (ordered_hashmap_isempty(j->files))
                         r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
         }
 
-        SET_FOREACH(code, j->errors, it) {
+        HASHMAP_FOREACH_KEY(path, code, j->errors, it) {
                 int err;
 
-                err = -PTR_TO_INT(code);
-                assert(err > 0);
+                err = abs(PTR_TO_INT(code));
 
-                if (err == EACCES)
+                switch (err) {
+                case EACCES:
                         continue;
 
-                log_warning_errno(err, "Error was encountered while opening journal files: %m");
-                if (r == 0)
-                        r = -err;
+                case ENODATA:
+                        log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
+                        break;
+
+                case EPROTONOSUPPORT:
+                        log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
+                        break;
+
+                case EBADMSG:
+                        log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
+                        break;
+
+                default:
+                        log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+                        break;
+                }
         }
 
         return r;
@@ -1738,6 +1771,11 @@ static int flush_to_var(void) {
         _cleanup_close_ int watch_fd = -1;
         int r;
 
+        if (arg_machine) {
+                log_error("--flush is not supported in conjunction with --machine=.");
+                return -EOPNOTSUPP;
+        }
+
         /* Quick exit */
         if (access("/run/systemd/journal/flushed", F_OK) >= 0)
                 return 0;
@@ -1757,10 +1795,8 @@ static int flush_to_var(void) {
                         &error,
                         NULL,
                         "ssi", "systemd-journald.service", "main", SIGUSR1);
-        if (r < 0) {
-                log_error("Failed to kill journal service: %s", bus_error_message(&error, r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
 
         mkdir_p("/run/systemd/journal", 0755);
 
@@ -1791,30 +1827,97 @@ static int flush_to_var(void) {
         return 0;
 }
 
-static int rotate(void) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+static int send_signal_and_wait(int sig, const char *watch_path) {
         _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        _cleanup_close_ int watch_fd = -1;
+        usec_t start;
         int r;
 
-        r = bus_connect_system_systemd(&bus);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get D-Bus connection: %m");
+        if (arg_machine) {
+                log_error("--sync and --rotate are not supported in conjunction with --machine=.");
+                return -EOPNOTSUPP;
+        }
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "KillUnit",
-                        &error,
-                        NULL,
-                        "ssi", "systemd-journald.service", "main", SIGUSR2);
-        if (r < 0)
-                return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
+        start = now(CLOCK_MONOTONIC);
+
+        /* This call sends the specified signal to journald, and waits
+         * for acknowledgment by watching the mtime of the specified
+         * flag file. This is used to trigger syncing or rotation and
+         * then wait for the operation to complete. */
+
+        for (;;) {
+                usec_t tstamp;
+
+                /* See if a sync happened by now. */
+                r = read_timestamp_file(watch_path, &tstamp);
+                if (r < 0 && r != -ENOENT)
+                        return log_error_errno(errno, "Failed to read %s: %m", watch_path);
+                if (r >= 0 && tstamp >= start)
+                        return 0;
+
+                /* Let's ask for a sync, but only once. */
+                if (!bus) {
+                        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
+                        r = bus_connect_system_systemd(&bus);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+                        r = sd_bus_call_method(
+                                        bus,
+                                        "org.freedesktop.systemd1",
+                                        "/org/freedesktop/systemd1",
+                                        "org.freedesktop.systemd1.Manager",
+                                        "KillUnit",
+                                        &error,
+                                        NULL,
+                                        "ssi", "systemd-journald.service", "main", sig);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
+
+                        continue;
+                }
+
+                /* Let's install the inotify watch, if we didn't do that yet. */
+                if (watch_fd < 0) {
+
+                        mkdir_p("/run/systemd/journal", 0755);
+
+                        watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+                        if (watch_fd < 0)
+                                return log_error_errno(errno, "Failed to create inotify watch: %m");
+
+                        r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
+                        if (r < 0)
+                                return log_error_errno(errno, "Failed to watch journal directory: %m");
+
+                        /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
+                        continue;
+                }
+
+                /* OK, all preparatory steps done, let's wait until
+                 * inotify reports an event. */
+
+                r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to wait for event: %m");
+
+                r = flush_fd(watch_fd);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to flush inotify events: %m");
+        }
 
         return 0;
 }
 
+static int rotate(void) {
+        return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
+}
+
+static int sync_journal(void) {
+        return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
+}
+
 int main(int argc, char *argv[]) {
         int r;
         _cleanup_journal_close_ sd_journal *j = NULL;
@@ -1840,30 +1943,19 @@ int main(int argc, char *argv[]) {
          * be split up into many files. */
         setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
 
-        if (arg_action == ACTION_NEW_ID128) {
-                r = generate_new_id128();
-                goto finish;
-        }
-
-        if (arg_action == ACTION_FLUSH) {
-                r = flush_to_var();
-                goto finish;
-        }
+        switch (arg_action) {
 
-        if (arg_action == ACTION_ROTATE) {
-                r = rotate();
+        case ACTION_NEW_ID128:
+                r = generate_new_id128();
                 goto finish;
-        }
 
-        if (arg_action == ACTION_SETUP_KEYS) {
+        case ACTION_SETUP_KEYS:
                 r = setup_keys();
                 goto finish;
-        }
-
-        if (arg_action == ACTION_UPDATE_CATALOG ||
-            arg_action == ACTION_LIST_CATALOG ||
-            arg_action == ACTION_DUMP_CATALOG) {
 
+        case ACTION_LIST_CATALOG:
+        case ACTION_DUMP_CATALOG:
+        case ACTION_UPDATE_CATALOG: {
                 _cleanup_free_ char *database;
 
                 database = path_join(arg_root, CATALOG_DATABASE, NULL);
@@ -1879,9 +1971,10 @@ int main(int argc, char *argv[]) {
                 } else {
                         bool oneline = arg_action == ACTION_LIST_CATALOG;
 
+                        pager_open_if_enabled();
+
                         if (optind < argc)
-                                r = catalog_list_items(stdout, database,
-                                                       oneline, argv + optind);
+                                r = catalog_list_items(stdout, database, oneline, argv + optind);
                         else
                                 r = catalog_list(stdout, database, oneline);
                         if (r < 0)
@@ -1891,6 +1984,31 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        case ACTION_FLUSH:
+                r = flush_to_var();
+                goto finish;
+
+        case ACTION_SYNC:
+                r = sync_journal();
+                goto finish;
+
+        case ACTION_ROTATE:
+                r = rotate();
+                goto finish;
+
+        case ACTION_SHOW:
+        case ACTION_PRINT_HEADER:
+        case ACTION_VERIFY:
+        case ACTION_DISK_USAGE:
+        case ACTION_LIST_BOOTS:
+        case ACTION_VACUUM:
+                /* These ones require access to the journal files, continue below. */
+                break;
+
+        default:
+                assert_not_reached("Unknown action");
+        }
+
         if (arg_directory)
                 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
         else if (arg_file)
@@ -1900,8 +2018,7 @@ int main(int argc, char *argv[]) {
         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_directory : arg_file ? "files" : "journal");
+                log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
                 goto finish;
         }
 
@@ -1909,18 +2026,28 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        if (arg_action == ACTION_VERIFY) {
-                r = verify(j);
-                goto finish;
-        }
+        switch (arg_action) {
 
-        if (arg_action == ACTION_PRINT_HEADER) {
+        case ACTION_NEW_ID128:
+        case ACTION_SETUP_KEYS:
+        case ACTION_LIST_CATALOG:
+        case ACTION_DUMP_CATALOG:
+        case ACTION_UPDATE_CATALOG:
+        case ACTION_FLUSH:
+        case ACTION_SYNC:
+        case ACTION_ROTATE:
+                assert_not_reached("Unexpected action.");
+
+        case ACTION_PRINT_HEADER:
                 journal_print_header(j);
                 r = 0;
                 goto finish;
-        }
 
-        if (arg_action == ACTION_DISK_USAGE) {
+        case ACTION_VERIFY:
+                r = verify(j);
+                goto finish;
+
+        case ACTION_DISK_USAGE: {
                 uint64_t bytes = 0;
                 char sbytes[FORMAT_BYTES_MAX];
 
@@ -1933,7 +2060,11 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_action == ACTION_VACUUM) {
+        case ACTION_LIST_BOOTS:
+                r = list_boots(j);
+                goto finish;
+
+        case ACTION_VACUUM: {
                 Directory *d;
                 Iterator i;
 
@@ -1953,9 +2084,11 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        if (arg_action == ACTION_LIST_BOOTS) {
-                r = list_boots(j);
-                goto finish;
+        case ACTION_SHOW:
+                break;
+
+        default:
+                assert_not_reached("Unknown action");
         }
 
         /* add_boot() must be called first!
@@ -2248,5 +2381,7 @@ finish:
         strv_free(arg_system_units);
         strv_free(arg_user_units);
 
+        free(arg_root);
+
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index fe8ae194c9d145cc81a24b6ccd9b87b0f1fe3531..3c13fe0d675c56a654709ba9b64348d0d376977c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "missing.h"
-#include "journald-audit.h"
+#include "alloc-util.h"
 #include "audit-type.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
+#include "journald-audit.h"
+#include "missing.h"
+#include "string-util.h"
 
 typedef struct MapField {
         const char *audit_field;
index 307bdc3949e8d334b5eec68dc00fd758d0892320..89f3d4b42f1bd468cb4a7301be61872565c2c35c 100644 (file)
 #include <fcntl.h>
 #include <sys/socket.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "journald-server.h"
-#include "journald-console.h"
 #include "formats-util.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-server.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "stdio-util.h"
 #include "terminal-util.h"
 
 static bool prefix_timestamp(void) {
@@ -101,7 +106,7 @@ void server_forward_console(
 
         fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
         if (fd < 0) {
-                log_debug_errno(errno, "Failed to open %s for logging: %m", tty);
+                log_debug_errno(fd, "Failed to open %s for logging: %m", tty);
                 return;
         }
 
index 51fe3aa50af40a314dccd9131235fc5946a01e01..e048e04716b4cbda59722f4bd4afd00fa38f79de 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
-#include <sys/epoll.h>
 #include <fcntl.h>
+#include <sys/epoll.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
+#include <unistd.h>
 
-#include "systemd/sd-messages.h"
-#include <libudev.h>
+#include "libudev.h"
+#include "sd-messages.h"
 
-#include "journald-server.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
 #include "journald-kmsg.h"
+#include "journald-server.h"
 #include "journald-syslog.h"
-#include "formats-util.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
 
 void server_forward_kmsg(
         Server *s,
@@ -341,8 +347,7 @@ static int server_read_dev_kmsg(Server *s) {
                 if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
                         return 0;
 
-                log_error_errno(errno, "Failed to read from kernel: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to read from kernel: %m");
         }
 
         dev_kmsg_record(s, buffer, l);
@@ -436,6 +441,7 @@ fail:
 int server_open_kernel_seqnum(Server *s) {
         _cleanup_close_ int fd;
         uint64_t *p;
+        int r;
 
         assert(s);
 
@@ -449,8 +455,9 @@ int server_open_kernel_seqnum(Server *s) {
                 return 0;
         }
 
-        if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
-                log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m");
+        r = posix_fallocate(fd, 0, sizeof(uint64_t));
+        if (r != 0) {
+                log_error_errno(r, "Failed to allocate sequential number file, ignoring: %m");
                 return 0;
         }
 
index 3e8a7a05f617d5810bb786675ac3a93f399d665a..69a685c06f26201139049ff9c295375595de6722 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <stddef.h>
 #include <sys/epoll.h>
 #include <sys/mman.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
 
-#include "socket-util.h"
-#include "path-util.h"
-#include "selinux-util.h"
-#include "journald-server.h"
-#include "journald-native.h"
-#include "journald-kmsg.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "io-util.h"
 #include "journald-console.h"
+#include "journald-kmsg.h"
+#include "journald-native.h"
+#include "journald-server.h"
 #include "journald-syslog.h"
 #include "journald-wall.h"
 #include "memfd-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "string-util.h"
 
 bool valid_user_field(const char *p, size_t l, bool allow_protected) {
         const char *a;
@@ -338,7 +345,7 @@ void server_process_native_file(
 
                 r = readlink_malloc(sl, &k);
                 if (r < 0) {
-                        log_error_errno(errno, "readlink(%s) failed: %m", sl);
+                        log_error_errno(r, "readlink(%s) failed: %m", sl);
                         return;
                 }
 
@@ -393,8 +400,37 @@ void server_process_native_file(
                 assert_se(munmap(p, ps) >= 0);
         } else {
                 _cleanup_free_ void *p = NULL;
+                struct statvfs vfs;
                 ssize_t n;
 
+                if (fstatvfs(fd, &vfs) < 0) {
+                        log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
+                        return;
+                }
+
+                /* Refuse operating on file systems that have
+                 * mandatory locking enabled, see:
+                 *
+                 * https://github.com/systemd/systemd/issues/1822
+                 */
+                if (vfs.f_flag & ST_MANDLOCK) {
+                        log_error("Received file descriptor from file system with mandatory locking enable, refusing.");
+                        return;
+                }
+
+                /* Make the fd non-blocking. On regular files this has
+                 * the effect of bypassing mandatory locking. Of
+                 * course, this should normally not be necessary given
+                 * the check above, but let's better be safe than
+                 * sorry, after all NFS is pretty confusing regarding
+                 * file system flags, and we better don't trust it,
+                 * and so is SMB. */
+                r = fd_nonblock(fd, true);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
+                        return;
+                }
+
                 /* The file is not sealed, we can't map the file here, since
                  * clients might then truncate it and trigger a SIGBUS for
                  * us. So let's stupidly read it */
@@ -407,7 +443,7 @@ void server_process_native_file(
 
                 n = pread(fd, p, st.st_size, 0);
                 if (n < 0)
-                        log_error_errno(n, "Failed to read file, ignoring: %m");
+                        log_error_errno(errno, "Failed to read file, ignoring: %m");
                 else if (n > 0)
                         server_process_native_message(s, p, n, ucred, tv, label, label_len);
         }
index 8afd493b50f6d60917515568949ea54082fe2a58..434ddc8ac91e7815242cfacdc4076685ad55a098 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
+#include <string.h>
 
-#include "journald-rate-limit.h"
-#include "list.h"
-#include "util.h"
+#include "alloc-util.h"
 #include "hashmap.h"
+#include "list.h"
 #include "random-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "journald-rate-limit.h"
 
 #define POOLS_MAX 5
 #define BUCKETS_MAX 127
index fb172b7f5dada047f5deb3877b9cc361aeead17e..be913d26ef465af049f8ad2ca8971ce80fc61a23 100644 (file)
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <linux/sockios.h>
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 #endif
@@ -27,6 +26,7 @@
 #include <sys/mman.h>
 #include <sys/signalfd.h>
 #include <sys/statvfs.h>
+#include <linux/sockios.h>
 
 #include "libudev.h"
 #include "sd-daemon.h"
 #include "sd-messages.h"
 
 #include "acl-util.h"
+#include "alloc-util.h"
+#include "audit-util.h"
 #include "cgroup-util.h"
 #include "conf-parser.h"
+#include "dirent-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "hashmap.h"
 #include "hostname-util.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "process-util.h"
-#include "rm-rf.h"
-#include "selinux-util.h"
-#include "signal-util.h"
-#include "socket-util.h"
+#include "io-util.h"
 #include "journal-authenticate.h"
 #include "journal-file.h"
 #include "journal-internal.h"
 #include "journald-server.h"
 #include "journald-stream.h"
 #include "journald-syslog.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "rm-rf.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
 
 #define USER_JOURNALS_MAX 1024
 
@@ -67,6 +79,8 @@
 
 #define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
 
+#define NOTIFY_SNDBUF_SIZE (8*1024*1024)
+
 static int determine_space_for(
                 Server *s,
                 JournalMetrics *metrics,
@@ -227,12 +241,17 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
         /* We do not recalculate the mask unconditionally here,
          * so that the fchmod() mask above stays intact. */
         if (acl_get_permset(entry, &permset) < 0 ||
-            acl_add_perm(permset, ACL_READ) < 0 ||
-            calc_acl_mask_if_needed(&acl) < 0) {
+            acl_add_perm(permset, ACL_READ) < 0) {
                 log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
                 return;
         }
 
+        r = calc_acl_mask_if_needed(&acl);
+        if (r < 0) {
+                log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path);
+                return;
+        }
+
         if (acl_set_fd(f->fd, acl) < 0)
                 log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
 
@@ -930,7 +949,7 @@ finish:
 
 static int system_journal_open(Server *s, bool flush_requested) {
         const char *fn;
-        int r;
+        int r = 0;
 
         if (!s->system_journal &&
             (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) &&
@@ -1222,29 +1241,38 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
 
 static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
         Server *s = userdata;
+        int r;
 
         assert(s);
 
-        log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid);
+        log_info("Received request to flush runtime journal from PID " PID_FMT, si->ssi_pid);
 
         server_flush_to_var(s);
         server_sync(s);
         server_vacuum(s, false, false);
 
-        touch("/run/systemd/journal/flushed");
+        r = touch("/run/systemd/journal/flushed");
+        if (r < 0)
+                log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m");
 
         return 0;
 }
 
 static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
         Server *s = userdata;
+        int r;
 
         assert(s);
 
-        log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid);
+        log_info("Received request to rotate journal from PID " PID_FMT, si->ssi_pid);
         server_rotate(s);
         server_vacuum(s, true, true);
 
+        /* Let clients know when the most recent rotation happened. */
+        r = write_timestamp_file_atomic("/run/systemd/journal/rotated", now(CLOCK_MONOTONIC));
+        if (r < 0)
+                log_warning_errno(r, "Failed to write /run/systemd/journal/rotated, ignoring: %m");
+
         return 0;
 }
 
@@ -1259,12 +1287,30 @@ static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *
         return 0;
 }
 
+static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
+        Server *s = userdata;
+        int r;
+
+        assert(s);
+
+        log_debug("Received request to sync from PID " PID_FMT, si->ssi_pid);
+
+        server_sync(s);
+
+        /* Let clients know when the most recent sync happened. */
+        r = write_timestamp_file_atomic("/run/systemd/journal/synced", now(CLOCK_MONOTONIC));
+        if (r < 0)
+                log_warning_errno(r, "Failed to write /run/systemd/journal/synced, ignoring: %m");
+
+        return 0;
+}
+
 static int setup_signals(Server *s) {
         int r;
 
         assert(s);
 
-        assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1) >= 0);
+        assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
 
         r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
         if (r < 0)
@@ -1278,17 +1324,41 @@ static int setup_signals(Server *s) {
         if (r < 0)
                 return r;
 
+        /* Let's process SIGTERM late, so that we flush all queued
+         * messages to disk before we exit */
+        r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
+        if (r < 0)
+                return r;
+
+        /* When journald is invoked on the terminal (when debugging),
+         * it's useful if C-c is handled equivalent to SIGTERM. */
         r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
         if (r < 0)
                 return r;
 
+        r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20);
+        if (r < 0)
+                return r;
+
+        /* SIGRTMIN+1 causes an immediate sync. We process this very
+         * late, so that everything else queued at this point is
+         * really written to disk. Clients can watch
+         * /run/systemd/journal/synced with inotify until its mtime
+         * changes to see when a sync happened. */
+        r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
+        if (r < 0)
+                return r;
+
+        r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
 static int server_parse_proc_cmdline(Server *s) {
         _cleanup_free_ char *line = NULL;
-        const char *w, *state;
-        size_t l;
+        const char *p;
         int r;
 
         r = proc_cmdline(&line);
@@ -1297,12 +1367,16 @@ static int server_parse_proc_cmdline(Server *s) {
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(w, l, line, state) {
+        p = line;
+        for(;;) {
                 _cleanup_free_ char *word;
 
-                word = strndup(w, l);
-                if (!word)
-                        return -ENOMEM;
+                r = extract_first_word(&p, &word, NULL, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse journald syntax \"%s\": %m", line);
+
+                if (r == 0)
+                        break;
 
                 if (startswith(word, "systemd.journald.forward_to_syslog=")) {
                         r = parse_boolean(word + 35);
@@ -1339,8 +1413,8 @@ static int server_parse_proc_cmdline(Server *s) {
 static int server_parse_config_file(Server *s) {
         assert(s);
 
-        return config_parse_many("/etc/systemd/journald.conf",
-                                 CONF_DIRS_NULSTR("systemd/journald.conf"),
+        return config_parse_many(PKGSYSCONFDIR "/journald.conf",
+                                 CONF_PATHS_NULSTR("systemd/journald.conf.d"),
                                  "Journal\0",
                                  config_item_perf_lookup, journald_gperf_lookup,
                                  false, s);
@@ -1443,17 +1517,184 @@ static int server_open_hostname(Server *s) {
         return 0;
 }
 
+static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+        Server *s = userdata;
+        int r;
+
+        assert(s);
+        assert(s->notify_event_source == es);
+        assert(s->notify_fd == fd);
+
+        /* The $NOTIFY_SOCKET is writable again, now send exactly one
+         * message on it. Either it's the wtachdog event, the initial
+         * READY=1 event or an stdout stream event. If there's nothing
+         * to write anymore, turn our event source off. The next time
+         * there's something to send it will be turned on again. */
+
+        if (!s->sent_notify_ready) {
+                static const char p[] =
+                        "READY=1\n"
+                        "STATUS=Processing requests...";
+                ssize_t l;
+
+                l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+                if (l < 0) {
+                        if (errno == EAGAIN)
+                                return 0;
+
+                        return log_error_errno(errno, "Failed to send READY=1 notification message: %m");
+                }
+
+                s->sent_notify_ready = true;
+                log_debug("Sent READY=1 notification.");
+
+        } else if (s->send_watchdog) {
+
+                static const char p[] =
+                        "WATCHDOG=1";
+
+                ssize_t l;
+
+                l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+                if (l < 0) {
+                        if (errno == EAGAIN)
+                                return 0;
+
+                        return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m");
+                }
+
+                s->send_watchdog = false;
+                log_debug("Sent WATCHDOG=1 notification.");
+
+        } else if (s->stdout_streams_notify_queue)
+                /* Dispatch one stream notification event */
+                stdout_stream_send_notify(s->stdout_streams_notify_queue);
+
+        /* Leave us enabled if there's still more to to do. */
+        if (s->send_watchdog || s->stdout_streams_notify_queue)
+                return 0;
+
+        /* There was nothing to do anymore, let's turn ourselves off. */
+        r = sd_event_source_set_enabled(es, SD_EVENT_OFF);
+        if (r < 0)
+                return log_error_errno(r, "Failed to turn off notify event source: %m");
+
+        return 0;
+}
+
+static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) {
+        Server *s = userdata;
+        int r;
+
+        assert(s);
+
+        s->send_watchdog = true;
+
+        r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON);
+        if (r < 0)
+                log_warning_errno(r, "Failed to turn on notify event source: %m");
+
+        r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2);
+        if (r < 0)
+                return log_error_errno(r, "Failed to restart watchdog event source: %m");
+
+        r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON);
+        if (r < 0)
+                return log_error_errno(r, "Failed to enable watchdog event source: %m");
+
+        return 0;
+}
+
+static int server_connect_notify(Server *s) {
+        union sockaddr_union sa = {
+                .un.sun_family = AF_UNIX,
+        };
+        const char *e;
+        int r;
+
+        assert(s);
+        assert(s->notify_fd < 0);
+        assert(!s->notify_event_source);
+
+        /*
+          So here's the problem: we'd like to send notification
+          messages to PID 1, but we cannot do that via sd_notify(),
+          since that's synchronous, and we might end up blocking on
+          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
+          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
+          send anything. This should efficiently avoid any deadlocks,
+          as we'll never block on PID 1, hence PID 1 can safely block
+          on dbus-daemon which can safely block on us again.
+
+          Don't think that this issue is real? It is, see:
+          https://github.com/systemd/systemd/issues/1505
+        */
+
+        e = getenv("NOTIFY_SOCKET");
+        if (!e)
+                return 0;
+
+        if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+                log_error("NOTIFY_SOCKET set to an invalid value: %s", e);
+                return -EINVAL;
+        }
+
+        if (strlen(e) > sizeof(sa.un.sun_path)) {
+                log_error("NOTIFY_SOCKET path too long: %s", e);
+                return -EINVAL;
+        }
+
+        s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        if (s->notify_fd < 0)
+                return log_error_errno(errno, "Failed to create notify socket: %m");
+
+        (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE);
+
+        strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path));
+        if (sa.un.sun_path[0] == '@')
+                sa.un.sun_path[0] = 0;
+
+        r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+        if (r < 0)
+                return log_error_errno(errno, "Failed to connect to notify socket: %m");
+
+        r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
+        if (r < 0)
+                return log_error_errno(r, "Failed to watch notification socket: %m");
+
+        if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) {
+                s->send_watchdog = true;
+
+                r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec/4, dispatch_watchdog, s);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add watchdog time event: %m");
+        }
+
+        /* This should fire pretty soon, which we'll use to send the
+         * READY=1 event. */
+
+        return 0;
+}
+
 int server_init(Server *s) {
         _cleanup_fdset_free_ FDSet *fds = NULL;
         int n, r, fd;
+        bool no_sockets;
 
         assert(s);
 
         zero(*s);
-        s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
+        s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
         s->compress = true;
         s->seal = true;
 
+        s->watchdog_usec = USEC_INFINITY;
+
         s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
         s->sync_scheduled = false;
 
@@ -1496,8 +1737,6 @@ int server_init(Server *s) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create event loop: %m");
 
-        sd_event_set_watchdog(s->event, true);
-
         n = sd_listen_fds(true);
         if (n < 0)
                 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
@@ -1555,30 +1794,44 @@ int server_init(Server *s) {
                 }
         }
 
-        r = server_open_stdout_socket(s, fds);
-        if (r < 0)
-                return r;
+        /* Try to restore streams, but don't bother if this fails */
+        (void) server_restore_streams(s, fds);
 
         if (fdset_size(fds) > 0) {
                 log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds));
                 fds = fdset_free(fds);
         }
 
+        no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0;
+
+        /* always open stdout, syslog, native, and kmsg sockets */
+
+        /* systemd-journald.socket: /run/systemd/journal/stdout */
+        r = server_open_stdout_socket(s);
+        if (r < 0)
+                return r;
+
+        /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */
         r = server_open_syslog_socket(s);
         if (r < 0)
                 return r;
 
+        /* systemd-journald.socket: /run/systemd/journal/socket */
         r = server_open_native_socket(s);
         if (r < 0)
                 return r;
 
+        /* /dev/ksmg */
         r = server_open_dev_kmsg(s);
         if (r < 0)
                 return r;
 
-        r = server_open_audit(s);
-        if (r < 0)
-                return r;
+        /* Unless we got *some* sockets and not audit, open audit socket */
+        if (s->audit_fd >= 0 || no_sockets) {
+                r = server_open_audit(s);
+                if (r < 0)
+                        return r;
+        }
 
         r = server_open_kernel_seqnum(s);
         if (r < 0)
@@ -1608,6 +1861,8 @@ int server_init(Server *s) {
         server_cache_boot_id(s);
         server_cache_machine_id(s);
 
+        (void) server_connect_notify(s);
+
         return system_journal_open(s, false);
 }
 
@@ -1655,7 +1910,10 @@ void server_done(Server *s) {
         sd_event_source_unref(s->sigusr2_event_source);
         sd_event_source_unref(s->sigterm_event_source);
         sd_event_source_unref(s->sigint_event_source);
+        sd_event_source_unref(s->sigrtmin1_event_source);
         sd_event_source_unref(s->hostname_event_source);
+        sd_event_source_unref(s->notify_event_source);
+        sd_event_source_unref(s->watchdog_event_source);
         sd_event_unref(s->event);
 
         safe_close(s->syslog_fd);
@@ -1664,6 +1922,7 @@ void server_done(Server *s) {
         safe_close(s->dev_kmsg_fd);
         safe_close(s->audit_fd);
         safe_close(s->hostname_fd);
+        safe_close(s->notify_fd);
 
         if (s->rate_limit)
                 journal_rate_limit_free(s->rate_limit);
index 535c0ab9ab25525f70ca4b4c9720f313dc8eda18..dcc21bb7c3db57f4a6c161665d610888c7b8ddf0 100644 (file)
 #include <sys/types.h>
 
 #include "sd-event.h"
-#include "journal-file.h"
+
+typedef struct Server Server;
+
 #include "hashmap.h"
-#include "audit.h"
+#include "journal-file.h"
 #include "journald-rate-limit.h"
+#include "journald-stream.h"
 #include "list.h"
 
 typedef enum Storage {
@@ -48,15 +51,14 @@ typedef enum SplitMode {
         _SPLIT_INVALID = -1
 } SplitMode;
 
-typedef struct StdoutStream StdoutStream;
-
-typedef struct Server {
+struct Server {
         int syslog_fd;
         int native_fd;
         int stdout_fd;
         int dev_kmsg_fd;
         int audit_fd;
         int hostname_fd;
+        int notify_fd;
 
         sd_event *event;
 
@@ -70,7 +72,10 @@ typedef struct Server {
         sd_event_source *sigusr2_event_source;
         sd_event_source *sigterm_event_source;
         sd_event_source *sigint_event_source;
+        sd_event_source *sigrtmin1_event_source;
         sd_event_source *hostname_event_source;
+        sd_event_source *notify_event_source;
+        sd_event_source *watchdog_event_source;
 
         JournalFile *runtime_journal;
         JournalFile *system_journal;
@@ -111,6 +116,7 @@ typedef struct Server {
         usec_t oldest_file_usec;
 
         LIST_HEAD(StdoutStream, stdout_streams);
+        LIST_HEAD(StdoutStream, stdout_streams_notify_queue);
         unsigned n_stdout_streams;
 
         char *tty_path;
@@ -126,13 +132,14 @@ typedef struct Server {
 
         MMapCache *mmap;
 
-        bool dev_kmsg_readable;
+        struct udev *udev;
 
         uint64_t *kernel_seqnum;
+        bool dev_kmsg_readable:1;
 
-        struct udev *udev;
-
-        bool sync_scheduled;
+        bool send_watchdog:1;
+        bool sent_notify_ready:1;
+        bool sync_scheduled:1;
 
         char machine_id_field[sizeof("_MACHINE_ID=") + 32];
         char boot_id_field[sizeof("_BOOT_ID=") + 32];
@@ -140,7 +147,9 @@ typedef struct Server {
 
         /* Cached cgroup root, so that we don't have to query that all the time */
         char *cgroup_root;
-} Server;
+
+        usec_t watchdog_usec;
+};
 
 #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
 
index 69e2d41863748c521742110a6f7ae97f5d940c97..fb800782fb688eab716663e20f398ee7370e6570 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <stddef.h>
+#include <unistd.h>
 
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 #endif
 
-#include "sd-event.h"
 #include "sd-daemon.h"
-#include "socket-util.h"
-#include "selinux-util.h"
-#include "mkdir.h"
+#include "sd-event.h"
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-kmsg.h"
 #include "journald-server.h"
 #include "journald-stream.h"
 #include "journald-syslog.h"
-#include "journald-kmsg.h"
-#include "journald-console.h"
 #include "journald-wall.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
 
 #define STDOUT_STREAMS_MAX 4096
 
@@ -69,6 +79,7 @@ struct StdoutStream {
         bool forward_to_console:1;
 
         bool fdstore:1;
+        bool in_notify_queue:1;
 
         char buffer[LINE_MAX+1];
         size_t length;
@@ -78,6 +89,7 @@ struct StdoutStream {
         char *state_file;
 
         LIST_FIELDS(StdoutStream, stdout_stream);
+        LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
 };
 
 void stdout_stream_free(StdoutStream *s) {
@@ -88,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) {
                 assert(s->server->n_stdout_streams > 0);
                 s->server->n_stdout_streams --;
                 LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
+
+                if (s->in_notify_queue)
+                        LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
         }
 
         if (s->event_source) {
@@ -111,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) {
                 return;
 
         if (s->state_file)
-                unlink(s->state_file);
+                (void) unlink(s->state_file);
 
         stdout_stream_free(s);
 }
@@ -190,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) {
                 goto fail;
         }
 
-        /* Store the connection fd in PID 1, so that we get it passed
-         * in again on next start */
-        if (!s->fdstore) {
-                sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
-                s->fdstore = true;
+        if (!s->fdstore && !s->in_notify_queue) {
+                LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+                s->in_notify_queue = true;
+
+                if (s->server->notify_event_source) {
+                        r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to enable notify event source: %m");
+                }
         }
 
         return 0;
@@ -519,8 +538,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
                 if (errno == EAGAIN)
                         return 0;
 
-                log_error_errno(errno, "Failed to accept stdout connection: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to accept stdout connection: %m");
         }
 
         if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
@@ -627,7 +645,7 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) {
         return 0;
 }
 
-static int server_restore_streams(Server *s, FDSet *fds) {
+int server_restore_streams(Server *s, FDSet *fds) {
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
         int r;
@@ -681,7 +699,7 @@ fail:
         return log_error_errno(errno, "Failed to read streams directory: %m");
 }
 
-int server_open_stdout_socket(Server *s, FDSet *fds) {
+int server_open_stdout_socket(Server *s) {
         int r;
 
         assert(s);
@@ -717,8 +735,52 @@ int server_open_stdout_socket(Server *s, FDSet *fds) {
         if (r < 0)
                 return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
 
-        /* Try to restore streams, but don't bother if this fails */
-        (void) server_restore_streams(s, fds);
-
         return 0;
 }
+
+void stdout_stream_send_notify(StdoutStream *s) {
+        struct iovec iovec = {
+                .iov_base = (char*) "FDSTORE=1",
+                .iov_len = strlen("FDSTORE=1"),
+        };
+        struct msghdr msghdr = {
+                .msg_iov = &iovec,
+                .msg_iovlen = 1,
+        };
+        struct cmsghdr *cmsg;
+        ssize_t l;
+
+        assert(s);
+        assert(!s->fdstore);
+        assert(s->in_notify_queue);
+        assert(s->server);
+        assert(s->server->notify_fd >= 0);
+
+        /* Store the connection fd in PID 1, so that we get it passed
+         * in again on next start */
+
+        msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
+        msghdr.msg_control = alloca0(msghdr.msg_controllen);
+
+        cmsg = CMSG_FIRSTHDR(&msghdr);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+        memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int));
+
+        l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL);
+        if (l < 0) {
+                if (errno == EAGAIN)
+                        return;
+
+                log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m");
+        } else {
+                log_debug("Successfully sent stream file descriptor to service manager.");
+                s->fdstore = 1;
+        }
+
+        LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+        s->in_notify_queue = false;
+
+}
index 94bf955d782e398fb4d3c6d1fea93f79abc68178..e3497f0dedb02c64209030a338cc1628bc77f32e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+typedef struct StdoutStream StdoutStream;
+
 #include "fdset.h"
 #include "journald-server.h"
 
-int server_open_stdout_socket(Server *s, FDSet *fds);
+int server_open_stdout_socket(Server *s);
+int server_restore_streams(Server *s, FDSet *fds);
 
 void stdout_stream_free(StdoutStream *s);
+void stdout_stream_send_notify(StdoutStream *s);
index ffba451955fd5833031ac328af44e038894bfeda..f3ac1a7ae061b4a9315e2e8c891517fef1cf21ec 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <stddef.h>
 #include <sys/epoll.h>
+#include <unistd.h>
 
-#include "systemd/sd-messages.h"
-#include "socket-util.h"
-#include "selinux-util.h"
+#include "sd-messages.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-kmsg.h"
 #include "journald-server.h"
 #include "journald-syslog.h"
-#include "journald-kmsg.h"
-#include "journald-console.h"
 #include "journald-wall.h"
-#include "formats-util.h"
 #include "process-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
 
 /* Warn once every 30s if we missed syslog message */
 #define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
index 7863766ae7f689d67f67535ac64b70aae54afbdb..69540f11416b727bb5d9fc8ddb2524a3a79daa37 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "utmp-wtmp.h"
-#include "journald-server.h"
-#include "journald-wall.h"
+#include "alloc-util.h"
 #include "formats-util.h"
+#include "journald-server.h"
 #include "process-util.h"
+#include "string-util.h"
+#include "utmp-wtmp.h"
+#include "journald-wall.h"
 
 void server_forward_wall(
                 Server *s,
index 83236ceba9b46cc653784ac4638686be7a6eff4d..b137e3c7beadbd85dcd4166c095ac0f3bc767ee4 100644 (file)
@@ -61,10 +61,6 @@ int main(int argc, char *argv[]) {
         log_debug("systemd-journald running as pid "PID_FMT, getpid());
         server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started");
 
-        sd_notify(false,
-                  "READY=1\n"
-                  "STATUS=Processing requests...");
-
         for (;;) {
                 usec_t t = USEC_INFINITY, n;
 
@@ -117,10 +113,6 @@ int main(int argc, char *argv[]) {
         server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped");
 
 finish:
-        sd_notify(false,
-                  "STOPPING=1\n"
-                  "STATUS=Shutting down...");
-
         server_done(&server);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
index 22f75540b83f948d0d7e3604b4317c22ed809baa..3cb1dfa986a5189976398fac9a1fe718fff6f189 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <sys/mman.h>
 
+#include "alloc-util.h"
 #include "hashmap.h"
 #include "list.h"
 #include "log.h"
index 13fa9b52fc49cf59e6f2a61cd715da0b8ce4713b..5cde7f17f7d34dad34879a607cf941241cfc7aa1 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/magic.h>
+#include <poll.h>
 #include <stddef.h>
-#include <unistd.h>
 #include <sys/inotify.h>
-#include <poll.h>
 #include <sys/vfs.h>
-#include <linux/magic.h>
+#include <unistd.h>
 
 #include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "catalog.h"
+#include "compress.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "fs-util.h"
+#include "hashmap.h"
+#include "hostname-util.h"
+#include "io-util.h"
 #include "journal-def.h"
 #include "journal-file.h"
-#include "hashmap.h"
+#include "journal-internal.h"
 #include "list.h"
-#include "strv.h"
-#include "path-util.h"
 #include "lookup3.h"
-#include "compress.h"
-#include "journal-internal.h"
 #include "missing.h"
-#include "catalog.h"
+#include "path-util.h"
 #include "replace-var.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "hostname-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
 
 #define JOURNAL_FILES_MAX 7168
 
@@ -64,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) {
         return j->original_pid != getpid();
 }
 
-/* We return an error here only if we didn't manage to
-   memorize the real error. */
-static int set_put_error(sd_journal *j, int r) {
+static int journal_put_error(sd_journal *j, int r, const char *path) {
+        char *copy;
         int k;
 
+        /* Memorize an error we encountered, and store which
+         * file/directory it was generated from. Note that we store
+         * only *one* path per error code, as the error code is the
+         * key into the hashmap, and the path is the value. This means
+         * we keep track only of all error kinds, but not of all error
+         * locations. This has the benefit that the hashmap cannot
+         * grow beyond bounds.
+         *
+         * We return an error here only if we didn't manage to
+         * memorize the real error. */
+
         if (r >= 0)
                 return r;
 
-        k = set_ensure_allocated(&j->errors, NULL);
+        k = hashmap_ensure_allocated(&j->errors, NULL);
         if (k < 0)
                 return k;
 
-        return set_put(j->errors, INT_TO_PTR(r));
+        if (path) {
+                copy = strdup(path);
+                if (!copy)
+                        return -ENOMEM;
+        } else
+                copy = NULL;
+
+        k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
+        if (k < 0) {
+                free(copy);
+
+                if (k == -EEXIST)
+                        return 0;
+
+                return k;
+        }
+
+        return 0;
 }
 
 static void detach_location(sd_journal *j) {
@@ -1016,8 +1052,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
 
 _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         int r;
-        const char *word, *state;
-        size_t l;
         Object *o;
 
         assert_return(j, -EINVAL);
@@ -1031,20 +1065,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
         if (r < 0)
                 return r;
 
-        FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
+        for(;;) {
                 _cleanup_free_ char *item = NULL;
-                sd_id128_t id;
                 unsigned long long ll;
+                sd_id128_t id;
                 int k = 0;
 
-                if (l < 2 || word[1] != '=')
-                        return -EINVAL;
+                r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
+                if (r < 0)
+                        return r;
 
-                item = strndup(word, l);
-                if (!item)
-                        return -ENOMEM;
+                if (r == 0)
+                        break;
 
-                switch (word[0]) {
+                if (strlen(item) < 2 || item[1] != '=')
+                        return -EINVAL;
+
+                switch (item[0]) {
 
                 case 's':
                         k = sd_id128_from_string(item+2, &id);
@@ -1173,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
 }
 
 static bool file_type_wanted(int flags, const char *filename) {
+        assert(filename);
+
         if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
                 return false;
 
@@ -1197,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) {
 
 static int add_any_file(sd_journal *j, const char *path) {
         JournalFile *f = NULL;
-        int r;
+        int r, k;
 
         assert(j);
         assert(path);
@@ -1206,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) {
                 return 0;
 
         if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
-                log_warning("Too many open journal files, not adding %s.", path);
-                return set_put_error(j, -ETOOMANYREFS);
+                log_debug("Too many open journal files, not adding %s.", path);
+                r = -ETOOMANYREFS;
+                goto fail;
         }
 
         r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
-        if (r < 0)
-                return r;
+        if (r < 0) {
+                log_debug_errno(r, "Failed to open journal file %s: %m", path);
+                goto fail;
+        }
 
         /* journal_file_dump(f); */
 
         r = ordered_hashmap_put(j->files, f->path, f);
         if (r < 0) {
                 journal_file_close(f);
-                return r;
+                goto fail;
         }
 
         log_debug("File %s added.", f->path);
@@ -1229,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) {
         j->current_invalidate_counter ++;
 
         return 0;
+
+fail:
+        k = journal_put_error(j, r, path);
+        if (k < 0)
+                return k;
+
+        return r;
 }
 
 static int add_file(sd_journal *j, const char *prefix, const char *filename) {
-        _cleanup_free_ char *path = NULL;
-        int r;
+        const char *path;
 
         assert(j);
         assert(prefix);
@@ -1243,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
             !file_type_wanted(j->flags, filename))
                 return 0;
 
-        path = strjoin(prefix, "/", filename, NULL);
-        if (!path)
-                return -ENOMEM;
-
-        r = add_any_file(j, path);
-        if (r == -ENOENT)
-                return 0;
-        return r;
+        path = strjoina(prefix, "/", filename);
+        return add_any_file(j, path);
 }
 
-static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
-        _cleanup_free_ char *path;
+static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
+        const char *path;
         JournalFile *f;
 
         assert(j);
         assert(prefix);
         assert(filename);
 
-        path = strjoin(prefix, "/", filename, NULL);
-        if (!path)
-                return -ENOMEM;
-
+        path = strjoina(prefix, "/", filename);
         f = ordered_hashmap_get(j->files, path);
         if (!f)
-                return 0;
+                return;
 
         remove_file_real(j, f);
-        return 0;
 }
 
 static void remove_file_real(sd_journal *j, JournalFile *f) {
@@ -1299,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
         j->current_invalidate_counter ++;
 }
 
+static int dirname_is_machine_id(const char *fn) {
+        sd_id128_t id, machine;
+        int r;
+
+        r = sd_id128_get_machine(&machine);
+        if (r < 0)
+                return r;
+
+        r = sd_id128_from_string(fn, &id);
+        if (r < 0)
+                return r;
+
+        return sd_id128_equal(id, machine);
+}
+
 static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
         _cleanup_free_ char *path = NULL;
-        int r;
         _cleanup_closedir_ DIR *d = NULL;
-        sd_id128_t id, mid;
+        struct dirent *de = NULL;
         Directory *m;
+        int r, k;
 
         assert(j);
         assert(prefix);
@@ -1313,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
         log_debug("Considering %s/%s.", prefix, dirname);
 
         if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
-            (sd_id128_from_string(dirname, &id) < 0 ||
-             sd_id128_get_machine(&mid) < 0 ||
-             !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
+            !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
             return 0;
 
         path = strjoin(prefix, "/", dirname, NULL);
-        if (!path)
-                return -ENOMEM;
+        if (!path) {
+                r = -ENOMEM;
+                goto fail;
+        }
 
         d = opendir(path);
         if (!d) {
-                log_debug_errno(errno, "Failed to open %s: %m", path);
-                if (errno == ENOENT)
-                        return 0;
-                return -errno;
+                r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
+                goto fail;
         }
 
         m = hashmap_get(j->directories_by_path, path);
         if (!m) {
                 m = new0(Directory, 1);
-                if (!m)
-                        return -ENOMEM;
+                if (!m) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
 
                 m->is_root = false;
                 m->path = path;
 
                 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
                         free(m);
-                        return -ENOMEM;
+                        r = -ENOMEM;
+                        goto fail;
                 }
 
                 path = NULL; /* avoid freeing in cleanup */
@@ -1363,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
                         inotify_rm_watch(j->inotify_fd, m->wd);
         }
 
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0) {
-                        r = -errno;
-                        log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
-                        return r;
-                }
-                if (!de)
-                        break;
+        FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
 
                 if (dirent_is_file_with_suffix(de, ".journal") ||
-                    dirent_is_file_with_suffix(de, ".journal~")) {
-                        r = add_file(j, m->path, de->d_name);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                m->path, de->d_name);
-                                r = set_put_error(j, r);
-                                if (r < 0)
-                                        return r;
-                        }
-                }
+                    dirent_is_file_with_suffix(de, ".journal~"))
+                        (void) add_file(j, m->path, de->d_name);
         }
 
         check_network(j, dirfd(d));
 
         return 0;
+
+fail:
+        k = journal_put_error(j, r, path ?: dirname);
+        if (k < 0)
+                return k;
+
+        return r;
 }
 
-static int add_root_directory(sd_journal *j, const char *p) {
+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;
+        int r, k;
 
         assert(j);
         assert(p);
@@ -1410,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) {
                 p = strjoina(j->prefix, p);
 
         d = opendir(p);
-        if (!d)
-                return -errno;
+        if (!d) {
+                if (errno == ENOENT && missing_ok)
+                        return 0;
+
+                r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+                goto fail;
+        }
 
         m = hashmap_get(j->directories_by_path, p);
         if (!m) {
                 m = new0(Directory, 1);
-                if (!m)
-                        return -ENOMEM;
+                if (!m) {
+                        r = -ENOMEM;
+                        goto fail;
+                }
 
                 m->is_root = true;
                 m->path = strdup(p);
                 if (!m->path) {
                         free(m);
-                        return -ENOMEM;
+                        r = -ENOMEM;
+                        goto fail;
                 }
 
                 if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
                         free(m->path);
                         free(m);
-                        return -ENOMEM;
+                        r = -ENOMEM;
+                        goto fail;
                 }
 
                 j->current_invalidate_counter ++;
@@ -1452,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) {
         if (j->no_new_files)
                 return 0;
 
-        for (;;) {
-                struct dirent *de;
+        FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
                 sd_id128_t id;
 
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0) {
-                        r = -errno;
-                        log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
-                        return r;
-                }
-                if (!de)
-                        break;
-
                 if (dirent_is_file_with_suffix(de, ".journal") ||
-                    dirent_is_file_with_suffix(de, ".journal~")) {
-                        r = add_file(j, m->path, de->d_name);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                m->path, de->d_name);
-                                r = set_put_error(j, r);
-                                if (r < 0)
-                                        return r;
-                        }
-                } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
-                           sd_id128_from_string(de->d_name, &id) >= 0) {
-
-                        r = add_directory(j, m->path, de->d_name);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
-                }
+                    dirent_is_file_with_suffix(de, ".journal~"))
+                        (void) add_file(j, m->path, de->d_name);
+                else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
+                         sd_id128_from_string(de->d_name, &id) >= 0)
+                        (void) add_directory(j, m->path, de->d_name);
         }
 
         check_network(j, dirfd(d));
 
         return 0;
+
+fail:
+        k = journal_put_error(j, r, p);
+        if (k < 0)
+                return k;
+
+        return r;
 }
 
 static void remove_directory(sd_journal *j, Directory *d) {
@@ -1512,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) {
 }
 
 static int add_search_paths(sd_journal *j) {
-        int r;
-        const char search_paths[] =
+
+        static const char search_paths[] =
                 "/run/log/journal\0"
                 "/var/log/journal\0";
         const char *p;
@@ -1523,14 +1560,8 @@ static int add_search_paths(sd_journal *j) {
         /* We ignore most errors here, since the idea is to only open
          * what's actually accessible, and ignore the rest. */
 
-        NULSTR_FOREACH(p, search_paths) {
-                r = add_root_directory(j, p);
-                if (r < 0 && r != -ENOENT) {
-                        r = set_put_error(j, r);
-                        if (r < 0)
-                                return r;
-                }
-        }
+        NULSTR_FOREACH(p, search_paths)
+                (void) add_root_directory(j, p, true);
 
         return 0;
 }
@@ -1554,17 +1585,14 @@ static int add_current_paths(sd_journal *j) {
                 if (!dir)
                         return -ENOMEM;
 
-                r = add_root_directory(j, dir);
-                if (r < 0) {
-                        set_put_error(j, r);
+                r = add_root_directory(j, dir, true);
+                if (r < 0)
                         return r;
-                }
         }
 
         return 0;
 }
 
-
 static int allocate_inotify(sd_journal *j) {
         assert(j);
 
@@ -1692,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
         if (!j)
                 return -ENOMEM;
 
-        r = add_root_directory(j, path);
-        if (r < 0) {
-                set_put_error(j, r);
+        r = add_root_directory(j, path, false);
+        if (r < 0)
                 goto fail;
-        }
 
         *ret = j;
         return 0;
@@ -1721,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
 
         STRV_FOREACH(path, paths) {
                 r = add_any_file(j, *path);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to open %s: %m", *path);
+                if (r < 0)
                         goto fail;
-                }
         }
 
         j->no_new_files = true;
@@ -1741,6 +1765,7 @@ fail:
 _public_ void sd_journal_close(sd_journal *j) {
         Directory *d;
         JournalFile *f;
+        char *p;
 
         if (!j)
                 return;
@@ -1768,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) {
                 mmap_cache_unref(j->mmap);
         }
 
+        while ((p = hashmap_steal_first(j->errors)))
+                free(p);
+        hashmap_free(j->errors);
+
         free(j->path);
         free(j->prefix);
         free(j->unique_field);
-        set_free(j->errors);
         free(j);
 }
 
@@ -2064,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
         if (j->no_new_files)
                 r = add_current_paths(j);
         else if (j->path)
-                r = add_root_directory(j, j->path);
+                r = add_root_directory(j, j->path, true);
         else
                 r = add_search_paths(j);
         if (r < 0)
@@ -2111,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
 
 static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
         Directory *d;
-        int r;
 
         assert(j);
         assert(e);
@@ -2127,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
 
                         /* Event for a journal file */
 
-                        if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
-                                r = add_file(j, d->path, e->name);
-                                if (r < 0) {
-                                        log_debug_errno(r, "Failed to add file %s/%s: %m",
-                                                        d->path, e->name);
-                                        set_put_error(j, r);
-                                }
-
-                        } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
-
-                                r = remove_file(j, d->path, e->name);
-                                if (r < 0)
-                                        log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
-                        }
+                        if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+                                (void) add_file(j, d->path, e->name);
+                        else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
+                                remove_file(j, d->path, e->name);
 
                 } else if (!d->is_root && e->len == 0) {
 
@@ -2153,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
 
                         /* Event for root directory */
 
-                        if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
-                                r = add_directory(j, d->path, e->name);
-                                if (r < 0)
-                                        log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
-                        }
+                        if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+                                (void) add_directory(j, d->path, e->name);
                 }
 
                 return;
@@ -2166,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
         if (e->mask & IN_IGNORED)
                 return;
 
-        log_warning("Unknown inotify event.");
+        log_debug("Unknown inotify event.");
 }
 
 static int determine_change(sd_journal *j) {
index 98a54ff269f112d5e9e3042fc416f3e791467469..4305462f809dc1ea01b5996cd1dbb0b5d90f932a 100644 (file)
 #include <dwarf.h>
 #include <elfutils/libdwfl.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
 #include "macro.h"
 #include "stacktrace.h"
-#include "formats-util.h"
+#include "string-util.h"
+#include "util.h"
 
 #define FRAMES_MAX 64
 #define THREADS_MAX 64
index dbfdea609dc7751a8f0522e9496d4eed652e7a85..aea8fd15e6a1647c51db5520b6d9b52fae76ec75 100644 (file)
 #include <errno.h>
 #include <fcntl.h>
 
-#include "util.h"
-#include "log.h"
-#include "macro.h"
 #include "sd-messages.h"
+
+#include "alloc-util.h"
 #include "catalog.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "util.h"
 
 static const char *catalog_dirs[] = {
         CATALOG_DIR,
index c8e5b76c6ce29e234d8a8d2b2e6c7602e6ed9864..93ea9c6318fb4437b7ee7f2a2fa17d492cbe64c8 100644 (file)
@@ -1,3 +1,5 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
 /***
   This file is part of systemd
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "compress.h"
-#include "util.h"
 #include "macro.h"
+#include "parse-util.h"
+#include "random-util.h"
+#include "string-util.h"
+#include "util.h"
 
 typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size);
 typedef int (decompress_t)(const void *src, uint64_t src_size,
                            void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max);
 
+static usec_t arg_duration = 2 * USEC_PER_SEC;
+static size_t arg_start;
+
 #define MAX_SIZE (1024*1024LU)
+#define PRIME 1048571  /* A prime close enough to one megabyte that mod 4 == 3 */
+
+static size_t _permute(size_t x) {
+        size_t residue;
+
+        if (x >= PRIME)
+                return x;
+
+        residue = x*x % PRIME;
+        if (x <= PRIME / 2)
+                return residue;
+        else
+                return PRIME - residue;
+}
+
+static size_t permute(size_t x) {
+        return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345);
+}
 
-static char* make_buf(size_t count) {
+static char* make_buf(size_t count, const char *type) {
         char *buf;
         size_t i;
 
         buf = malloc(count);
         assert_se(buf);
 
-        for (i = 0; i < count; i++)
-                buf[i] = 'a' + i % ('z' - 'a' + 1);
+        if (streq(type, "zeros"))
+                memzero(buf, count);
+        else if (streq(type, "simple"))
+                for (i = 0; i < count; i++)
+                        buf[i] = 'a' + i % ('z' - 'a' + 1);
+        else if (streq(type, "random")) {
+                size_t step = count / 10;
+
+                random_bytes(buf, step);
+                memzero(buf + 1*step, step);
+                random_bytes(buf + 2*step, step);
+                memzero(buf + 3*step, step);
+                random_bytes(buf + 4*step, step);
+                memzero(buf + 5*step, step);
+                random_bytes(buf + 6*step, step);
+                memzero(buf + 7*step, step);
+                random_bytes(buf + 8*step, step);
+                memzero(buf + 9*step, step);
+        } else
+                assert_not_reached("here");
 
         return buf;
 }
 
-static void test_compress_decompress(const char* label,
+static void test_compress_decompress(const char* label, const char* type,
                                      compress_t compress, decompress_t decompress) {
         usec_t n, n2 = 0;
         float dt;
@@ -50,64 +95,85 @@ static void test_compress_decompress(const char* label,
         size_t buf2_allocated = 0;
         size_t skipped = 0, compressed = 0, total = 0;
 
-        text = make_buf(MAX_SIZE);
+        text = make_buf(MAX_SIZE, type);
         buf = calloc(MAX_SIZE + 1, 1);
         assert_se(text && buf);
 
         n = now(CLOCK_MONOTONIC);
 
-        for (size_t i = 1; i <= MAX_SIZE; i += (i < 2048 ? 1 : 217)) {
-                size_t j = 0, k = 0;
+        for (size_t i = 0; i <= MAX_SIZE; i++) {
+                size_t j = 0, k = 0, size;
                 int r;
 
-                r = compress(text, i, buf, &j);
+                size = permute(i);
+
+                log_debug("%s %zu %zu", type, i, size);
+
+                memzero(buf, MIN(size + 1000, MAX_SIZE));
+
+                r = compress(text, size, buf, &j);
                 /* assume compression must be successful except for small inputs */
-                assert_se(r == 0 || (i < 2048 && r == -ENOBUFS));
+                assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
+
                 /* check for overwrites */
-                assert_se(buf[i] == 0);
+                assert_se(buf[size] == 0);
                 if (r != 0) {
-                        skipped += i;
+                        skipped += size;
                         continue;
                 }
 
                 assert_se(j > 0);
-                if (j >= i)
-                        log_error("%s \"compressed\" %zu -> %zu", label, i, j);
+                if (j >= size)
+                        log_error("%s \"compressed\" %zu -> %zu", label, size, j);
 
                 r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0);
                 assert_se(r == 0);
                 assert_se(buf2_allocated >= k);
-                assert_se(k == i);
+                assert_se(k == size);
 
-                assert_se(memcmp(text, buf2, i) == 0);
+                assert_se(memcmp(text, buf2, size) == 0);
 
-                total += i;
+                total += size;
                 compressed += j;
 
                 n2 = now(CLOCK_MONOTONIC);
-                if (n2 - n > 60 * USEC_PER_SEC)
+                if (n2 - n > arg_duration)
                         break;
         }
 
         dt = (n2-n) / 1e6;
 
-        log_info("%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
+        log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
                  "mean compresion %.2f%%, skipped %zu bytes",
-                 label, total, dt,
+                 label, type, total, dt,
                  total / 1024. / 1024 / dt,
                  100 - compressed * 100. / total,
                  skipped);
 }
 
 int main(int argc, char *argv[]) {
+        const char *i;
 
-        log_set_max_level(LOG_DEBUG);
+        log_set_max_level(LOG_INFO);
 
+        if (argc >= 2) {
+                unsigned x;
+
+                assert_se(safe_atou(argv[1], &x) >= 0);
+                arg_duration = x * USEC_PER_SEC;
+        }
+        if (argc == 3)
+                (void) safe_atolu(argv[2], &arg_start);
+        else
+                arg_start = getpid();
+
+        NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
 #ifdef HAVE_XZ
-        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz);
+                test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
 #endif
 #ifdef HAVE_LZ4
-        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4);
+                test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
 #endif
+        }
         return 0;
 }
index f17c00e60dc36a08bad306ec14761725b6a0390f..b9d90a89887f976d8cf685600187ca060bd4615d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "compress.h"
-#include "util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "macro.h"
 #include "random-util.h"
+#include "util.h"
 
 #ifdef HAVE_XZ
 # define XZ_OK 0
@@ -144,8 +147,8 @@ static void test_compress_stream(int compression,
                                  const char *srcfile) {
 
         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
-        char pattern[] = "/tmp/systemd-test.xz.XXXXXX",
-             pattern2[] = "/tmp/systemd-test.xz.XXXXXX";
+        char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
+             pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
         int r;
         _cleanup_free_ char *cmd = NULL, *cmd2;
         struct stat st = {};
@@ -185,7 +188,7 @@ static void test_compress_stream(int compression,
 
         assert_se(lseek(dst, 1, SEEK_SET) == 1);
         r = decompress(dst, dst2, st.st_size);
-        assert_se(r == -EBADMSG);
+        assert_se(r == -EBADMSG || r == 0);
 
         assert_se(lseek(dst, 0, SEEK_SET) == 0);
         assert_se(lseek(dst2, 0, SEEK_SET) == 0);
@@ -236,8 +239,7 @@ int main(int argc, char *argv[]) {
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    data, sizeof(data), true);
 
-        /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */
-        test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL,
+        test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
                              compress_stream_lz4, decompress_stream_lz4, argv[0]);
 #else
         log_info("/* LZ4 test skipped */");
index cde2025ae951e6ea0ae85fb7479a4b2fce55302d..040c7d58fb5150eb6d2c504a4ef9cea37bc0b3ea 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <stdio.h>
 
-#include "log.h"
 #include "sd-journal.h"
+
+#include "log.h"
 #include "macro.h"
 #include "journal-internal.h"
 
index 2d4f531e9bf7b521775c89cde4b68fbe5d7799fc..03d1522e235b2536ac37ab156d1a3f23f0285647 100644 (file)
 #include <fcntl.h>
 
 #include "sd-journal.h"
-#include "macro.h"
+
+#include "alloc-util.h"
 #include "journal-file.h"
 #include "journal-internal.h"
+#include "macro.h"
+#include "string-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_free_ char *fn = NULL;
index e6599f366d90be1342313287a8da7b41b88b8d9d..142da85041f6df4fe6e32cd880f015832fc26a43 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
 
 #include "log.h"
-#include "util.h"
+#include "parse-util.h"
 #include "rm-rf.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         sd_journal *j;
index 8069339c1f485c7956b8980ece9d58371940343e..4ad89fe4b6a33126953c5cea351a5dea857a3fa4 100644 (file)
 #include <fcntl.h>
 
 #include "sd-journal.h"
+
+#include "alloc-util.h"
 #include "journal-file.h"
 #include "journal-vacuum.h"
-#include "util.h"
 #include "log.h"
+#include "parse-util.h"
 #include "rm-rf.h"
+#include "util.h"
 
 /* This program tests skipping around in a multi-file journal.
  */
index a3187053c9c62993a82972ddd80f6fc33dc3b0a0..abefedb992f1a07a4f1e6d705150add83a018752 100644 (file)
 
 #include <stdio.h>
 
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
 
+#include "alloc-util.h"
 #include "journal-internal.h"
-#include "util.h"
 #include "log.h"
+#include "string-util.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_journal_close_ sd_journal*j;
index 81ca47ed8deb58927cc29fecc385f150c3c6ac61..694376670d069750a604417141d5dcea5083eb9a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "systemd/sd-journal.h"
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "sd-journal.h"
+
 #include "log.h"
 
 int main(int argc, char *argv[]) {
index b5ecf2f375c8d614a8b80ce8fb87978123072c30..0cbef4b8c56c70297bfce1af743fe8b9bb96f569 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <fcntl.h>
+#include <unistd.h>
 
 #include "sd-journal.h"
-#include "util.h"
+
+#include "alloc-util.h"
+#include "journal-file.h"
+#include "journal-internal.h"
 #include "log.h"
 #include "macro.h"
+#include "parse-util.h"
 #include "rm-rf.h"
-#include "journal-file.h"
-#include "journal-internal.h"
+#include "util.h"
 
 #define N_ENTRIES 200
 
index c99ca0654bb732c32648855214477672428eedc9..1784187fe9317be0c720c23195b81450820373b0 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "journald-syslog.h"
 #include "macro.h"
+#include "string-util.h"
 
 static void test_syslog_parse_identifier(const char* str,
                                          const char *ident, const char*pid, int ret) {
index d89123dc6449dc525c3890a55745a10d984c72e9..887a83efe1de9edf73defd9600c90bbc85845fb0 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "util.h"
-#include "log.h"
-#include "rm-rf.h"
+#include "fd-util.h"
 #include "journal-file.h"
 #include "journal-verify.h"
+#include "log.h"
+#include "rm-rf.h"
 #include "terminal-util.h"
+#include "util.h"
 
 #define N_ENTRIES 6000
 #define RANDOM_RANGE 77
index 3258b227022a719e671f40e366814219726fea9b..fdd48e531c16be16b4f3782149f9b7f953910e9d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <fcntl.h>
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <unistd.h>
-#include <fcntl.h>
 
+#include "fd-util.h"
+#include "fileio.h"
 #include "macro.h"
-#include "util.h"
 #include "mmap-cache.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         int x, y, z, r;
index 2f5b9b37318691b4136baa2df4df9228d5e8a907..4660c7ea096eeb47c2c0576e9e762879970e5019 100644 (file)
@@ -21,8 +21,9 @@
 #include <linux/filter.h>
 #include <arpa/inet.h>
 
-#include "util.h"
 #include "arp-util.h"
+#include "fd-util.h"
+#include "util.h"
 
 int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
         struct sock_filter filter[] = {
index 7d9cad2a708edbe2cc7d2ad2c6a6847ad5b0a6b0..51ee7bcce471dffa360daf3a963e64365b93db70 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
-#include "sd-id128.h"
 #include "libudev.h"
-#include "udev-util.h"
-
-#include "virt.h"
-#include "sparse-endian.h"
-#include "siphash24.h"
+#include "sd-id128.h"
 
-#include "dhcp6-protocol.h"
 #include "dhcp-identifier.h"
+#include "dhcp6-protocol.h"
 #include "network-internal.h"
+#include "siphash24.h"
+#include "sparse-endian.h"
+#include "udev-util.h"
+#include "virt.h"
 
 #define SYSTEMD_PEN 43793
 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
@@ -58,7 +56,6 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
         return 0;
 }
 
-
 int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
         /* name is a pointer to memory in the udev_device struct, so must
            have the same scope */
index 95117915f46f0627c44966fa8b238135b4fa036c..2291736f8b05f6af3a9863bc925613748e1250fd 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "sd-id128.h"
 
 #include "macro.h"
 #include "sparse-endian.h"
 #include "unaligned.h"
-#include "sd-id128.h"
 
 /* RFC 3315 section 9.1:
  *      A DUID can be no more than 128 octets long (not including the type code).
index df6f882af5a14cbf19dfdf085f216d269697da8e..a5daaa543a8ee8040cd3ea8308ebbc1e3cfcaa4f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdint.h>
 #include <linux/if_packet.h>
-#include <net/if_arp.h>
 #include <net/ethernet.h>
-
-#include "socket-util.h"
+#include <net/if_arp.h>
+#include <stdint.h>
 
 #include "sd-dhcp-client.h"
+
 #include "dhcp-protocol.h"
+#include "socket-util.h"
 
 int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
                                  uint32_t xid, const uint8_t *mac_addr,
index 7f10838de147aa46b70059828060de95d3486e25..fac25e0fa2e059047cdb54c17ba2a99862ea7d14 100644 (file)
 ***/
 
 #include <errno.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <linux/if_packet.h>
-#include <linux/if_infiniband.h>
 #include <net/ethernet.h>
 #include <net/if_arp.h>
 #include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
 #include <linux/filter.h>
-
-#include "socket-util.h"
+#include <linux/if_infiniband.h>
+#include <linux/if_packet.h>
 
 #include "dhcp-internal.h"
+#include "fd-util.h"
+#include "socket-util.h"
 
 static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
                             uint32_t xid, const uint8_t *mac_addr,
index 83e8192f58494bd196db70561d353ad4f3ca6cf8..ecc220f2f67616805ece792197fc0fee2bfccaf9 100644 (file)
 #include <net/ethernet.h>
 #include <netinet/in.h>
 
-#include "sparse-endian.h"
 #include "sd-event.h"
+
 #include "list.h"
 #include "macro.h"
+#include "sparse-endian.h"
 
 typedef struct DHCP6Address DHCP6Address;
 
@@ -58,9 +59,6 @@ typedef struct DHCP6IA DHCP6IA;
 
 #define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
 
-int dhcp_network_icmp6_bind_router_solicitation(int index);
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
-
 int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
                         size_t optlen, const void *optval);
 int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
index 187975364b5aefe19c675cd0f241e71e3634420e..318ee9c4b40e7eb896c073427913e681ca657052 100644 (file)
 ***/
 
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <linux/if_packet.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
 #include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/in.h>
-
-#include "socket-util.h"
+#include <linux/if_packet.h>
 
 #include "dhcp6-internal.h"
 #include "dhcp6-protocol.h"
-
-#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
-        { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
-
-#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
-        { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
-              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
-
-int dhcp_network_icmp6_bind_router_solicitation(int index) {
-        struct icmp6_filter filter = { };
-        struct ipv6_mreq mreq = {
-                .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
-                .ipv6mr_interface = index,
-        };
-        _cleanup_close_ int s = -1;
-        int r, zero = 0, hops = 255;
-
-        s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                   IPPROTO_ICMPV6);
-        if (s < 0)
-                return -errno;
-
-        ICMP6_FILTER_SETBLOCKALL(&filter);
-        ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
-        r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
-                       sizeof(filter));
-        if (r < 0)
-                return -errno;
-
-        /* RFC 3315, section 6.7, bullet point 2 may indicate that an
-           IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
-           Empirical experiments indicates otherwise and therefore an
-           IPV6_MULTICAST_IF socket option is used here instead */
-        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
-                       sizeof(index));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
-                       sizeof(zero));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
-                       sizeof(hops));
-        if (r < 0)
-                return -errno;
-
-        r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
-                       sizeof(mreq));
-        if (r < 0)
-                return -errno;
-
-        r = s;
-        s = -1;
-        return r;
-}
-
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
-        struct sockaddr_in6 dst = {
-                .sin6_family = AF_INET6,
-                .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
-        };
-        struct {
-                struct nd_router_solicit rs;
-                struct nd_opt_hdr rs_opt;
-                struct ether_addr rs_opt_mac;
-        } _packed_ rs = {
-                .rs.nd_rs_type = ND_ROUTER_SOLICIT,
-        };
-        struct iovec iov[1] = {
-                { &rs, },
-        };
-        struct msghdr msg = {
-                .msg_name = &dst,
-                .msg_namelen = sizeof(dst),
-                .msg_iov = iov,
-                .msg_iovlen = 1,
-        };
-        int r;
-
-        if (ether_addr) {
-                memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
-                rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
-                rs.rs_opt.nd_opt_len = 1;
-                iov[0].iov_len = sizeof(rs);
-        } else
-                iov[0].iov_len = sizeof(rs.rs);
-
-        r = sendmsg(s, &msg, 0);
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
+#include "fd-util.h"
+#include "socket-util.h"
 
 int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
         struct in6_pktinfo pktinfo = {
index f41bebced0f1583a0c6e603e40c3b3380cdd7e5d..0f46df6a1b93056d2faa8112f6c36b681e62b1a8 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "sparse-endian.h"
-#include "unaligned.h"
-#include "util.h"
-#include "strv.h"
-
+#include "alloc-util.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-protocol.h"
 #include "dns-domain.h"
+#include "sparse-endian.h"
+#include "strv.h"
+#include "unaligned.h"
+#include "util.h"
 
 #define DHCP6_OPTION_IA_NA_LEN                  12
 #define DHCP6_OPTION_IA_TA_LEN                  4
@@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
         int r;
 
         assert_return(optlen > 1, -ENODATA);
-        assert_return(optval[optlen] == '\0', -EINVAL);
+        assert_return(optval[optlen - 1] == '\0', -EINVAL);
 
         while (pos < optlen) {
                 _cleanup_free_ char *ret = NULL;
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
new file mode 100644 (file)
index 0000000..91308bf
--- /dev/null
@@ -0,0 +1,129 @@
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  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 <errno.h>
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/if_packet.h>
+
+#include "fd-util.h"
+#include "icmp6-util.h"
+#include "socket-util.h"
+
+#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
+        { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
+
+#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
+        { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
+
+int icmp6_bind_router_solicitation(int index) {
+        struct icmp6_filter filter = { };
+        struct ipv6_mreq mreq = {
+                .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
+                .ipv6mr_interface = index,
+        };
+        _cleanup_close_ int s = -1;
+        int r, zero = 0, hops = 255;
+
+        s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                   IPPROTO_ICMPV6);
+        if (s < 0)
+                return -errno;
+
+        ICMP6_FILTER_SETBLOCKALL(&filter);
+        ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+        r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+                       sizeof(filter));
+        if (r < 0)
+                return -errno;
+
+        /* RFC 3315, section 6.7, bullet point 2 may indicate that an
+           IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
+           Empirical experiments indicates otherwise and therefore an
+           IPV6_MULTICAST_IF socket option is used here instead */
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
+                       sizeof(index));
+        if (r < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
+                       sizeof(zero));
+        if (r < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
+                       sizeof(hops));
+        if (r < 0)
+                return -errno;
+
+        r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
+                       sizeof(mreq));
+        if (r < 0)
+                return -errno;
+
+        r = s;
+        s = -1;
+        return r;
+}
+
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+        struct sockaddr_in6 dst = {
+                .sin6_family = AF_INET6,
+                .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
+        };
+        struct {
+                struct nd_router_solicit rs;
+                struct nd_opt_hdr rs_opt;
+                struct ether_addr rs_opt_mac;
+        } _packed_ rs = {
+                .rs.nd_rs_type = ND_ROUTER_SOLICIT,
+        };
+        struct iovec iov[1] = {
+                { &rs, },
+        };
+        struct msghdr msg = {
+                .msg_name = &dst,
+                .msg_namelen = sizeof(dst),
+                .msg_iov = iov,
+                .msg_iovlen = 1,
+        };
+        int r;
+
+        if (ether_addr) {
+                memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
+                rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+                rs.rs_opt.nd_opt_len = 1;
+                iov[0].iov_len = sizeof(rs);
+        } else
+                iov[0].iov_len = sizeof(rs.rs);
+
+        r = sendmsg(s, &msg, 0);
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/libsystemd-network/icmp6-util.h b/src/libsystemd-network/icmp6-util.h
new file mode 100644 (file)
index 0000000..4eb17e1
--- /dev/null
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014-2015 Intel Corporation. All rights reserved.
+
+  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 <net/ethernet.h>
+
+int icmp6_bind_router_solicitation(int index);
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
index 4012cd483b3b0aae94551e8c1cc2eca4234d07f4..583be2f55d9b0adcf82d44684ce91bf1b322b19b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "lldp-internal.h"
 #include "sd-lldp.h"
 
+#include "alloc-util.h"
+#include "lldp-internal.h"
+
 /* We store maximum 1K chassis entries */
 #define LLDP_MIB_MAX_CHASSIS 1024
 
index 284cc6720e2db0ee5fa06ef82a2f3cb598fba0ba..5d19fa0fea3a1ded1ff71fd239470695fe8ef21d 100644 (file)
 
 #pragma once
 
-#include "log.h"
+#include "sd-event.h"
+
 #include "list.h"
 #include "lldp-tlv.h"
+#include "log.h"
 #include "prioq.h"
-#include "sd-event.h"
 
 typedef struct lldp_neighbour_port lldp_neighbour_port;
 typedef struct lldp_chassis lldp_chassis;
index 12a6599ff1db8ddbd5793d5707068de4a6963e97..f483cd9c8ec2692263b7fadba07299cfa8559656 100644 (file)
 #include <linux/filter.h>
 #include <linux/if_ether.h>
 
-#include "socket-util.h"
-#include "lldp-tlv.h"
-#include "lldp-network.h"
+#include "fd-util.h"
 #include "lldp-internal.h"
+#include "lldp-network.h"
+#include "lldp-tlv.h"
+#include "socket-util.h"
 
 int lldp_network_bind_raw_socket(int ifindex) {
         typedef struct LLDPFrame {
index 7486b4c38f24d83cb4dd1bef8cf915f7cfaaddea..97b6b485d264310c75914f403fdb857c72e6b7d8 100644 (file)
@@ -20,6 +20,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "async.h"
 #include "lldp-port.h"
 #include "lldp-network.h"
index 66af22e37dd7fd64a8dffb4fdf2980eb176589fb..789016049773f263f700878fe1fba44a28b120e0 100644 (file)
@@ -23,8 +23,9 @@
 #include <net/ethernet.h>
 #include <arpa/inet.h>
 
-#include "macro.h"
+#include "alloc-util.h"
 #include "lldp-tlv.h"
+#include "macro.h"
 
 int tlv_section_new(tlv_section **ret) {
         tlv_section *s;
@@ -277,7 +278,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
 
         p = m->pdu;
 
-        /* extract ethernet header */
+        /* extract Ethernet header */
         memcpy(&m->mac, p, ETH_ALEN);
         p += sizeof(struct ether_header);
 
@@ -386,12 +387,11 @@ static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t
 
         r = lldp_tlv_packet_enter_container(tlv, type);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u16(tlv, value);
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
@@ -428,18 +428,18 @@ int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
 
         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
         if (r < 0)
-                goto out2;
+                return r;
 
         r = tlv_packet_read_u8(tlv, &subtype);
         if (r < 0)
-                goto out1;
+                goto out;
 
         switch (subtype) {
         case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
 
                 r = tlv_packet_read_bytes(tlv, data, length);
                 if (r < 0)
-                        goto out1;
+                        goto out;
 
                 break;
         default:
@@ -449,10 +449,9 @@ int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
 
         *type = subtype;
 
- out1:
+ out:
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out2:
         return r < 0 ? r : r2;
 }
 
@@ -468,11 +467,11 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv,
 
         r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
         if (r < 0)
-                goto out2;
+                return r;
 
         r = tlv_packet_read_u8(tlv, &subtype);
         if (r < 0)
-                goto out1;
+                goto out;
 
         switch (subtype) {
         case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
@@ -482,7 +481,7 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv,
 
                 r = tlv_packet_read_string(tlv, &s, length);
                 if (r < 0)
-                        goto out1;
+                        goto out;
 
                 *data = (uint8_t *) s;
 
@@ -491,7 +490,7 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv,
 
                 r = tlv_packet_read_bytes(tlv, data, length);
                 if (r < 0)
-                        goto out1;
+                        goto out;
 
                 break;
         default:
@@ -501,10 +500,9 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv,
 
         *type = subtype;
 
- out1:
+ out:
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out2:
         return r < 0 ? r : r2;
 }
 
@@ -541,12 +539,11 @@ int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
 
         r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u16(tlv, id);
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
@@ -557,7 +554,7 @@ int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flag
 
         r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u8(tlv, flags);
         if (r >= 0)
@@ -565,7 +562,6 @@ int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flag
 
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
@@ -577,7 +573,7 @@ int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **nam
 
         r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u16(tlv, vlan_id);
         if (r >= 0)
@@ -590,7 +586,6 @@ int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **nam
 
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
@@ -601,12 +596,11 @@ int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
 
         r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u16(tlv, id);
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
@@ -617,7 +611,7 @@ int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, u
 
         r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
         if (r < 0)
-                goto out;
+                return r;
 
         r = tlv_packet_read_u8(tlv, status);
         if (r >= 0)
@@ -625,7 +619,6 @@ int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, u
 
         r2 = lldp_tlv_packet_exit_container(tlv);
 
- out:
         return r < 0 ? r : r2;
 }
 
index 2a62af2fd47936058f4311dd53cec9412377176e..52d76e443ec5ad25562fcbbdda9daeb369faa3b1 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <netinet/ether.h>
-#include <linux/if.h>
 #include <arpa/inet.h>
+#include <linux/if.h>
+#include <netinet/ether.h>
 
-#include "strv.h"
-#include "siphash24.h"
+#include "sd-ndisc.h"
+
+#include "alloc-util.h"
+#include "condition.h"
+#include "conf-parser.h"
 #include "dhcp-lease-internal.h"
 #include "log.h"
+#include "network-internal.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "siphash24.h"
+#include "string-util.h"
+#include "strv.h"
 #include "utf8.h"
 #include "util.h"
-#include "conf-parser.h"
-#include "condition.h"
-#include "network-internal.h"
-#include "sd-icmp6-nd.h"
 
 const char *net_get_name(struct udev_device *device) {
         const char *name, *field;
@@ -390,8 +395,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
         assert(size);
 
         for (i = 0; i < size; i++)
-                fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
-                        SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
+                fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
+                        SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
                         (i < (size - 1)) ? " ": "");
 }
 
index 141b836a0d78f3b3acc45e7a32b798de276d7f94..137537253a4aad9a9cfb034c31a11050204f429d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
-#include <string.h>
-#include <stdio.h>
 #include <net/ethernet.h>
 #include <net/if_arp.h>
-#include <linux/if_infiniband.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
+#include <linux/if_infiniband.h>
 
-#include "util.h"
-#include "random-util.h"
-#include "async.h"
+#include "sd-dhcp-client.h"
 
-#include "dhcp-protocol.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "dhcp-identifier.h"
 #include "dhcp-internal.h"
 #include "dhcp-lease-internal.h"
-#include "dhcp-identifier.h"
-#include "sd-dhcp-client.h"
+#include "dhcp-protocol.h"
+#include "random-util.h"
+#include "string-util.h"
+#include "util.h"
 
 #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN)  /* Arbitrary limit */
 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -1265,8 +1267,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
                 return r;
 
         log_dhcp_client(client, "lease expires in %s",
-                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                        lifetime_timeout - time_now, 0));
+                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
 
         /* don't arm earlier timeouts if this has already expired */
         if (lifetime_timeout <= time_now)
@@ -1292,8 +1293,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
                 return r;
 
         log_dhcp_client(client, "T2 expires in %s",
-                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                        t2_timeout - time_now, 0));
+                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
 
         /* don't arm earlier timeout if this has already expired */
         if (t2_timeout <= time_now)
@@ -1318,8 +1318,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
                 return r;
 
         log_dhcp_client(client, "T1 expires in %s",
-                        format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                        t1_timeout - time_now, 0));
+                        format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
 
         return 0;
 }
@@ -1518,7 +1517,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
                 expected_hlen = ETH_ALEN;
                 expected_chaddr = (const struct ether_addr *) &client->mac_addr;
         } else {
-               /* Non-ethernet links expect zero chaddr */
+               /* Non-Ethernet links expect zero chaddr */
                expected_hlen = 0;
                expected_chaddr = &zero_mac;
         }
index df3d8e6e3c7ce95d10ded41106f5f1ec31dd04e5..8befedc5002cacc57e9ef792912211da9201f08f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
+#include <arpa/inet.h>
 #include <errno.h>
-#include <string.h>
 #include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-dhcp-lease.h"
 
+#include "alloc-util.h"
+#include "dhcp-lease-internal.h"
+#include "dhcp-protocol.h"
+#include "dns-domain.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "unaligned.h"
-#include "in-addr-util.h"
+#include "hexdecoct.h"
 #include "hostname-util.h"
-#include "dns-domain.h"
+#include "in-addr-util.h"
 #include "network-internal.h"
-#include "dhcp-protocol.h"
-#include "dhcp-lease-internal.h"
-#include "sd-dhcp-lease.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "unaligned.h"
 
 int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
         assert_return(lease, -EINVAL);
@@ -945,19 +951,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
         if (address) {
                 r = inet_pton(AF_INET, address, &lease->address);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address);
+                        log_debug("Failed to parse address %s, ignoring.", address);
         }
 
         if (router) {
                 r = inet_pton(AF_INET, router, &lease->router);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router);
+                        log_debug("Failed to parse router %s, ignoring.", router);
         }
 
         if (netmask) {
                 r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask);
+                        log_debug("Failed to parse netmask %s, ignoring.", netmask);
                 else
                         lease->have_subnet_mask = true;
         }
@@ -965,19 +971,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
         if (server_address) {
                 r = inet_pton(AF_INET, server_address, &lease->server_address);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address);
+                        log_debug("Failed to parse server address %s, ignoring.", server_address);
         }
 
         if (next_server) {
                 r = inet_pton(AF_INET, next_server, &lease->next_server);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server);
+                        log_debug("Failed to parse next server %s, ignoring.", next_server);
         }
 
         if (broadcast) {
                 r = inet_pton(AF_INET, broadcast, &lease->broadcast);
                 if (r <= 0)
-                        log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast);
+                        log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
                 else
                         lease->have_broadcast = true;
         }
index d27bb561cacbf01333b44f296de95d20ed72fed5..8d0d9955c332d14aac09d816c819ac6c86ae3146 100644 (file)
 
 #include <sys/ioctl.h>
 
-#include "in-addr-util.h"
-#include "siphash24.h"
-
 #include "sd-dhcp-server.h"
-#include "dhcp-server-internal.h"
+
+#include "alloc-util.h"
 #include "dhcp-internal.h"
+#include "dhcp-server-internal.h"
+#include "fd-util.h"
+#include "in-addr-util.h"
+#include "siphash24.h"
+#include "string-util.h"
 
 #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
 #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
@@ -93,7 +96,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
         return 0;
 }
 
-bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
+int sd_dhcp_server_is_running(sd_dhcp_server *server) {
         assert_return(server, false);
 
         return !!server->receive_message;
index acb31a16c29c9e5fdfe7da71387d0e378f6a4d9b..a443bb3a7a20b03aa5816fef1b15d616d171d52b 100644 (file)
 #include <sys/ioctl.h>
 #include <linux/if_infiniband.h>
 
-#include "udev.h"
-#include "udev-util.h"
-#include "util.h"
-#include "random-util.h"
-
-#include "network-internal.h"
 #include "sd-dhcp6-client.h"
-#include "dhcp6-protocol.h"
+
+#include "alloc-util.h"
+#include "dhcp-identifier.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-lease-internal.h"
-#include "dhcp-identifier.h"
+#include "dhcp6-protocol.h"
+#include "fd-util.h"
+#include "network-internal.h"
+#include "random-util.h"
+#include "string-table.h"
+#include "util.h"
 
 #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
 
@@ -208,9 +209,8 @@ int sd_dhcp6_client_set_duid(
         return 0;
 }
 
-int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) {
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
         assert_return(client, -EINVAL);
-
         assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
 
         client->information_request = enabled;
@@ -218,7 +218,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable
         return 0;
 }
 
-int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) {
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
         assert_return(client, -EINVAL);
         assert_return(enabled, -EINVAL);
 
@@ -259,12 +259,12 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
 
 int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) {
         assert_return(client, -EINVAL);
-        assert_return(ret, -EINVAL);
 
         if (!client->lease)
                 return -ENOMSG;
 
-        *ret = client->lease;
+        if (ret)
+                *ret = client->lease;
 
         return 0;
 }
@@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
         }
 
         log_dhcp6_client(client, "Next retransmission in %s",
-                         format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                                         client->retransmit_time, 0));
+                         format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
 
         r = sd_event_add_time(client->event, &client->timeout_resend,
                               clock_boottime_or_monotonic(),
@@ -1048,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
                 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
 
                 log_dhcp6_client(client, "T1 expires in %s",
-                                 format_timespan(time_string,
-                                                 FORMAT_TIMESPAN_MAX,
-                                                 timeout, 0));
+                                 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
 
                 r = sd_event_add_time(client->event,
                                       &client->lease->ia.timeout_t1,
@@ -1072,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
                 timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
 
                 log_dhcp6_client(client, "T2 expires in %s",
-                                 format_timespan(time_string,
-                                                 FORMAT_TIMESPAN_MAX,
-                                                 timeout, 0));
+                                 format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
 
                 r = sd_event_add_time(client->event,
                                       &client->lease->ia.timeout_t2,
@@ -1120,11 +1115,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
 }
 
 int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
+        assert_return(client, -EINVAL);
+
         client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
 
         return 0;
 }
 
+int sd_dhcp6_client_is_running(sd_dhcp6_client *client) {
+        assert_return(client, -EINVAL);
+
+        return client->state != DHCP6_STATE_STOPPED;
+}
+
 int sd_dhcp6_client_start(sd_dhcp6_client *client) {
         int r = 0;
         enum DHCP6State state = DHCP6_STATE_SOLICITATION;
index f34af6eabaa56f68dd7fcea59bdb21791249697a..3f32ba35e7f300ed68ee2042f4e4f40b92ba35be 100644 (file)
 
 #include <errno.h>
 
-#include "strv.h"
-#include "util.h"
-
+#include "alloc-util.h"
 #include "dhcp6-lease-internal.h"
 #include "dhcp6-protocol.h"
+#include "strv.h"
+#include "util.h"
 
 int dhcp6_lease_clear_timers(DHCP6IA *ia) {
         assert_return(ia, -EINVAL);
diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c
deleted file mode 100644 (file)
index bedcac8..0000000
+++ /dev/null
@@ -1,722 +0,0 @@
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Intel Corporation. All rights reserved.
-
-  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 <netinet/icmp6.h>
-#include <netinet/ip6.h>
-#include <string.h>
-#include <stdbool.h>
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-
-#include "socket-util.h"
-#include "async.h"
-
-#include "dhcp6-internal.h"
-#include "sd-icmp6-nd.h"
-
-#define ICMP6_ROUTER_SOLICITATION_INTERVAL      4 * USEC_PER_SEC
-#define ICMP6_MAX_ROUTER_SOLICITATIONS          3
-
-enum icmp6_nd_state {
-        ICMP6_NEIGHBOR_DISCOVERY_IDLE           = 0,
-        ICMP6_ROUTER_SOLICITATION_SENT          = 10,
-        ICMP6_ROUTER_ADVERTISMENT_LISTEN        = 11,
-};
-
-#define IP6_MIN_MTU (unsigned)1280
-#define ICMP6_ND_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
-#define ICMP6_OPT_LEN_UNITS 8
-
-typedef struct ICMP6Prefix ICMP6Prefix;
-
-struct ICMP6Prefix {
-        unsigned n_ref;
-
-        LIST_FIELDS(ICMP6Prefix, prefixes);
-
-        uint8_t len;
-        sd_event_source *timeout_valid;
-        struct in6_addr addr;
-};
-
-struct sd_icmp6_nd {
-        unsigned n_ref;
-
-        enum icmp6_nd_state state;
-        sd_event *event;
-        int event_priority;
-        int index;
-        struct ether_addr mac_addr;
-        uint32_t mtu;
-        ICMP6Prefix *expired_prefix;
-        LIST_HEAD(ICMP6Prefix, prefixes);
-        int fd;
-        sd_event_source *recv;
-        sd_event_source *timeout;
-        int nd_sent;
-        sd_icmp6_nd_callback_t callback;
-        void *userdata;
-};
-
-#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__)
-
-static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) {
-
-        if (!prefix)
-                return NULL;
-
-        assert(prefix->n_ref > 0);
-        prefix->n_ref--;
-
-        if (prefix->n_ref > 0)
-                return NULL;
-
-        prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
-        free(prefix);
-        return NULL;
-}
-
-static int icmp6_prefix_new(ICMP6Prefix **ret) {
-        _cleanup_free_ ICMP6Prefix *prefix = NULL;
-
-        assert(ret);
-
-        prefix = new0(ICMP6Prefix, 1);
-        if (!prefix)
-                return -ENOMEM;
-
-        prefix->n_ref = 1;
-        LIST_INIT(prefixes, prefix);
-
-        *ret = prefix;
-        prefix = NULL;
-
-        return 0;
-}
-
-static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) {
-        if (nd->callback)
-                nd->callback(nd, event, nd->userdata);
-}
-
-int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback,
-                             void *userdata) {
-        assert(nd);
-
-        nd->callback = callback;
-        nd->userdata = userdata;
-
-        return 0;
-}
-
-int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) {
-        assert(nd);
-        assert(interface_index >= -1);
-
-        nd->index = interface_index;
-
-        return 0;
-}
-
-int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) {
-        assert(nd);
-
-        if (mac_addr)
-                memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr));
-        else
-                zero(nd->mac_addr);
-
-        return 0;
-
-}
-
-int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) {
-        int r;
-
-        assert_return(nd, -EINVAL);
-        assert_return(!nd->event, -EBUSY);
-
-        if (event)
-                nd->event = sd_event_ref(event);
-        else {
-                r = sd_event_default(&nd->event);
-                if (r < 0)
-                        return 0;
-        }
-
-        nd->event_priority = priority;
-
-        return 0;
-}
-
-int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) {
-        assert_return(nd, -EINVAL);
-
-        nd->event = sd_event_unref(nd->event);
-
-        return 0;
-}
-
-sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) {
-        assert(nd);
-
-        return nd->event;
-}
-
-sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) {
-
-        if (!nd)
-                return NULL;
-
-        assert(nd->n_ref > 0);
-        nd->n_ref++;
-
-        return nd;
-}
-
-static int icmp6_nd_init(sd_icmp6_nd *nd) {
-        assert(nd);
-
-        nd->recv = sd_event_source_unref(nd->recv);
-        nd->fd = asynchronous_close(nd->fd);
-        nd->timeout = sd_event_source_unref(nd->timeout);
-
-        return 0;
-}
-
-sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) {
-        ICMP6Prefix *prefix, *p;
-
-        if (!nd)
-                return NULL;
-
-        assert(nd->n_ref > 0);
-        nd->n_ref--;
-
-        if (nd->n_ref > 0)
-                return NULL;
-
-        icmp6_nd_init(nd);
-        sd_icmp6_nd_detach_event(nd);
-
-        LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
-                LIST_REMOVE(prefixes, nd->prefixes, prefix);
-
-                prefix = icmp6_prefix_unref(prefix);
-        }
-
-        free(nd);
-
-        return NULL;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_icmp6_nd*, sd_icmp6_nd_unref);
-#define _cleanup_sd_icmp6_nd_free_ _cleanup_(sd_icmp6_nd_unrefp)
-
-int sd_icmp6_nd_new(sd_icmp6_nd **ret) {
-        _cleanup_sd_icmp6_nd_free_ sd_icmp6_nd *nd = NULL;
-
-        assert(ret);
-
-        nd = new0(sd_icmp6_nd, 1);
-        if (!nd)
-                return -ENOMEM;
-
-        nd->n_ref = 1;
-
-        nd->index = -1;
-        nd->fd = -1;
-
-        LIST_HEAD_INIT(nd->prefixes);
-
-        *ret = nd;
-        nd = NULL;
-
-        return 0;
-}
-
-int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) {
-        assert_return(nd, -EINVAL);
-        assert_return(mtu, -EINVAL);
-
-        if (nd->mtu == 0)
-                return -ENOMSG;
-
-        *mtu = nd->mtu;
-
-        return 0;
-}
-
-static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec,
-                                   void *userdata) {
-        sd_icmp6_nd *nd = userdata;
-        ICMP6Prefix *prefix, *p;
-
-        assert(nd);
-
-        LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
-                if (prefix->timeout_valid != s)
-                        continue;
-
-                log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d",
-                             SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
-                             prefix->len);
-
-                LIST_REMOVE(prefixes, nd->prefixes, prefix);
-
-                nd->expired_prefix = prefix;
-                icmp6_nd_notify(nd,
-                                SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED);
-                nd->expired_prefix = NULL;
-
-                prefix = icmp6_prefix_unref(prefix);
-
-                break;
-        }
-
-        return 0;
-}
-
-static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd,
-                                       ICMP6Prefix *prefix,
-                                       usec_t valid) {
-        usec_t time_now;
-        int r;
-
-        assert_return(prefix, -EINVAL);
-
-        r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
-        if (r < 0)
-                return r;
-
-        prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
-
-        r = sd_event_add_time(nd->event, &prefix->timeout_valid,
-                        clock_boottime_or_monotonic(), time_now + valid,
-                        USEC_PER_SEC, icmp6_ra_prefix_timeout, nd);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_priority(prefix->timeout_valid,
-                                        nd->event_priority);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_description(prefix->timeout_valid,
-                                        "icmp6-prefix-timeout");
-
-error:
-        if (r < 0)
-                prefix->timeout_valid =
-                        sd_event_source_unref(prefix->timeout_valid);
-
-        return r;
-}
-
-static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
-                              const struct in6_addr *addr,
-                              uint8_t addr_prefixlen) {
-        uint8_t bytes, mask, len;
-
-        assert_return(prefix, -EINVAL);
-        assert_return(addr, -EINVAL);
-
-        len = MIN(prefixlen, addr_prefixlen);
-
-        bytes = len / 8;
-        mask = 0xff << (8 - len % 8);
-
-        if (memcmp(prefix, addr, bytes) != 0 ||
-            (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask))
-                return -EADDRNOTAVAIL;
-
-        return 0;
-}
-
-static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr,
-                                 uint8_t addr_len, ICMP6Prefix **result) {
-        ICMP6Prefix *prefix;
-
-        LIST_FOREACH(prefixes, prefix, head) {
-                if (icmp6_prefix_match(&prefix->addr, prefix->len, addr,
-                                       addr_len) >= 0) {
-                        *result = prefix;
-                        return 0;
-                }
-        }
-
-        return -EADDRNOTAVAIL;
-}
-
-int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
-                          struct in6_addr *addr) {
-        return icmp6_prefix_match(prefix, prefixlen, addr,
-                                  sizeof(addr->s6_addr) * 8);
-}
-
-int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
-                              uint8_t *prefixlen) {
-        int r;
-        ICMP6Prefix *prefix;
-
-        assert_return(nd, -EINVAL);
-        assert_return(addr, -EINVAL);
-        assert_return(prefixlen, -EINVAL);
-
-        r = icmp6_ra_prefix_match(nd->prefixes, addr,
-                                  sizeof(addr->s6_addr) * 8, &prefix);
-        if (r < 0)
-                return r;
-
-        *prefixlen = prefix->len;
-
-        return 0;
-}
-
-int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) {
-        assert_return(nd, -EINVAL);
-        assert_return(addr, -EINVAL);
-        assert_return(prefixlen, -EINVAL);
-
-        if (!nd->expired_prefix)
-                return -EADDRNOTAVAIL;
-
-        *addr = &nd->expired_prefix->addr;
-        *prefixlen = nd->expired_prefix->len;
-
-        return 0;
-}
-
-static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
-                                  const struct nd_opt_prefix_info *prefix_opt) {
-        int r;
-        ICMP6Prefix *prefix;
-        uint32_t lifetime;
-        char time_string[FORMAT_TIMESPAN_MAX];
-
-        assert_return(nd, -EINVAL);
-        assert_return(prefix_opt, -EINVAL);
-
-        if (len < prefix_opt->nd_opt_pi_len)
-                return -ENOMSG;
-
-        if (!(prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK))
-                return 0;
-
-        lifetime = be32toh(prefix_opt->nd_opt_pi_valid_time);
-
-        r = icmp6_ra_prefix_match(nd->prefixes,
-                                  &prefix_opt->nd_opt_pi_prefix,
-                                  prefix_opt->nd_opt_pi_prefix_len, &prefix);
-
-        if (r < 0 && r != -EADDRNOTAVAIL)
-                return r;
-
-        /* if router advertisment prefix valid timeout is zero, the timeout
-           callback will be called immediately to clean up the prefix */
-
-        if (r == -EADDRNOTAVAIL) {
-                r = icmp6_prefix_new(&prefix);
-                if (r < 0)
-                        return r;
-
-                prefix->len = prefix_opt->nd_opt_pi_prefix_len;
-
-                memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
-                        sizeof(prefix->addr));
-
-                log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
-                             SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
-                             prefix->len, lifetime,
-                             format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                                             lifetime * USEC_PER_SEC, 0));
-
-                LIST_PREPEND(prefixes, nd->prefixes, prefix);
-
-        } else {
-                if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) {
-                        uint8_t prefixlen;
-
-                        prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len);
-
-                        log_icmp6_nd(nd, "Prefix length mismatch %d/%d using %d",
-                                     prefix->len,
-                                     prefix_opt->nd_opt_pi_prefix_len,
-                                     prefixlen);
-
-                        prefix->len = prefixlen;
-                }
-
-                log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
-                             SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
-                             prefix->len, lifetime,
-                             format_timespan(time_string, FORMAT_TIMESPAN_MAX,
-                                             lifetime * USEC_PER_SEC, 0));
-        }
-
-        r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC);
-
-        return r;
-}
-
-static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
-                          ssize_t len) {
-        void *opt;
-        struct nd_opt_hdr *opt_hdr;
-
-        assert_return(nd, -EINVAL);
-        assert_return(ra, -EINVAL);
-
-        len -= sizeof(*ra);
-        if (len < ICMP6_OPT_LEN_UNITS) {
-                log_icmp6_nd(nd, "Router Advertisement below minimum length");
-
-                return -ENOMSG;
-        }
-
-        opt = ra + 1;
-        opt_hdr = opt;
-
-        while (len != 0 && len >= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS) {
-                struct nd_opt_mtu *opt_mtu;
-                uint32_t mtu;
-                struct nd_opt_prefix_info *opt_prefix;
-
-                if (opt_hdr->nd_opt_len == 0)
-                        return -ENOMSG;
-
-                switch (opt_hdr->nd_opt_type) {
-                case ND_OPT_MTU:
-                        opt_mtu = opt;
-
-                        mtu = be32toh(opt_mtu->nd_opt_mtu_mtu);
-
-                        if (mtu != nd->mtu) {
-                                nd->mtu = MAX(mtu, IP6_MIN_MTU);
-
-                                log_icmp6_nd(nd, "Router Advertisement link MTU %d using %d",
-                                             mtu, nd->mtu);
-                        }
-
-                        break;
-
-                case ND_OPT_PREFIX_INFORMATION:
-                        opt_prefix = opt;
-
-                        icmp6_ra_prefix_update(nd, len, opt_prefix);
-
-                        break;
-                }
-
-                len -= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS;
-                opt = (void *)((char *)opt +
-                        opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS);
-                opt_hdr = opt;
-        }
-
-        if (len > 0)
-                log_icmp6_nd(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
-
-        return 0;
-}
-
-static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_icmp6_nd *nd = userdata;
-        int r, buflen = 0;
-        ssize_t len;
-        _cleanup_free_ struct nd_router_advert *ra = NULL;
-        int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE;
-
-        assert(s);
-        assert(nd);
-        assert(nd->event);
-
-        r = ioctl(fd, FIONREAD, &buflen);
-        if (r < 0 || buflen <= 0)
-                buflen = ICMP6_ND_RECV_SIZE;
-
-        ra = malloc(buflen);
-        if (!ra)
-                return -ENOMEM;
-
-        len = read(fd, ra, buflen);
-        if (len < 0) {
-                log_icmp6_nd(nd, "Could not receive message from UDP socket: %m");
-                return 0;
-        }
-
-        if (ra->nd_ra_type != ND_ROUTER_ADVERT)
-                return 0;
-
-        if (ra->nd_ra_code != 0)
-                return 0;
-
-        nd->timeout = sd_event_source_unref(nd->timeout);
-
-        nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
-
-        if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER )
-                event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER;
-
-        if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
-                event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED;
-
-        log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s",
-                     ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none",
-                     ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none");
-
-        if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) {
-                r = icmp6_ra_parse(nd, ra, len);
-                if (r < 0) {
-                        log_icmp6_nd(nd, "Could not parse Router Advertisement: %s",
-                                     strerror(-r));
-                        return 0;
-                }
-        }
-
-        icmp6_nd_notify(nd, event);
-
-        return 0;
-}
-
-static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
-        sd_icmp6_nd *nd = userdata;
-        uint64_t time_now, next_timeout;
-        struct ether_addr unset = { };
-        struct ether_addr *addr = NULL;
-        int r;
-
-        assert(s);
-        assert(nd);
-        assert(nd->event);
-
-        nd->timeout = sd_event_source_unref(nd->timeout);
-
-        if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) {
-                icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
-                nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
-        } else {
-                if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
-                        addr = &nd->mac_addr;
-
-                r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr);
-                if (r < 0)
-                        log_icmp6_nd(nd, "Error sending Router Solicitation");
-                else {
-                        nd->state = ICMP6_ROUTER_SOLICITATION_SENT;
-                        log_icmp6_nd(nd, "Sent Router Solicitation");
-                }
-
-                nd->nd_sent++;
-
-                r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
-                if (r < 0) {
-                        icmp6_nd_notify(nd, r);
-                        return 0;
-                }
-
-                next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL;
-
-                r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
-                                      next_timeout, 0,
-                                      icmp6_router_solicitation_timeout, nd);
-                if (r < 0) {
-                        icmp6_nd_notify(nd, r);
-                        return 0;
-                }
-
-                r = sd_event_source_set_priority(nd->timeout,
-                                                 nd->event_priority);
-                if (r < 0) {
-                        icmp6_nd_notify(nd, r);
-                        return 0;
-                }
-
-                r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
-                if (r < 0) {
-                        icmp6_nd_notify(nd, r);
-                        return 0;
-                }
-        }
-
-        return 0;
-}
-
-int sd_icmp6_nd_stop(sd_icmp6_nd *nd) {
-        assert_return(nd, -EINVAL);
-        assert_return(nd->event, -EINVAL);
-
-        log_icmp6_nd(client, "Stop ICMPv6");
-
-        icmp6_nd_init(nd);
-
-        nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE;
-
-        return 0;
-}
-
-int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
-        int r;
-
-        assert(nd);
-        assert(nd->event);
-
-        if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE)
-                return -EINVAL;
-
-        if (nd->index < 1)
-                return -EINVAL;
-
-        r = dhcp_network_icmp6_bind_router_solicitation(nd->index);
-        if (r < 0)
-                return r;
-
-        nd->fd = r;
-
-        r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
-                            icmp6_router_advertisment_recv, nd);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_priority(nd->recv, nd->event_priority);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_description(nd->recv, "icmp6-receive-message");
-        if (r < 0)
-                goto error;
-
-        r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
-                              0, 0, icmp6_router_solicitation_timeout, nd);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
-        if (r < 0)
-                goto error;
-
-        r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
-error:
-        if (r < 0)
-                icmp6_nd_init(nd);
-        else
-                log_icmp6_nd(client, "Start Router Solicitation");
-
-        return r;
-}
index 95b96bfd52836260af25b22d4558b74000c59900..5340fdc0c1f70317c60ea5ed577233dd345362c5 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include "sd-ipv4acd.h"
+
+#include "alloc-util.h"
+#include "arp-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "in-addr-util.h"
 #include "list.h"
-#include "refcnt.h"
 #include "random-util.h"
+#include "refcnt.h"
 #include "siphash24.h"
 #include "util.h"
 
-#include "arp-util.h"
-#include "sd-ipv4acd.h"
-
 /* Constants from the RFC */
 #define PROBE_WAIT 1
 #define PROBE_NUM 3
@@ -468,7 +470,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
         return 0;
 }
 
-bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
+int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
         assert_return(ll, false);
 
         return ll->state != IPV4ACD_STATE_INIT;
index dd427ddd78467317cf564b2328b25c1f20e2cbfe..0d915e20e7fd8d6483031420979c6014d9ec9323 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
+#include <arpa/inet.h>
 #include <errno.h>
-#include <string.h>
 #include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-ipv4acd.h"
+#include "sd-ipv4ll.h"
 
+#include "alloc-util.h"
 #include "event-util.h"
+#include "in-addr-util.h"
 #include "list.h"
 #include "random-util.h"
 #include "refcnt.h"
@@ -32,9 +37,6 @@
 #include "sparse-endian.h"
 #include "util.h"
 
-#include "sd-ipv4acd.h"
-#include "sd-ipv4ll.h"
-
 #define IPV4LL_NETWORK 0xA9FE0000L
 #define IPV4LL_NETMASK 0xFFFF0000L
 
@@ -226,12 +228,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
         return 0;
 }
 
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
+int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
         assert_return(ll, false);
 
         return sd_ipv4acd_is_running(ll->acd);
 }
 
+static bool ipv4ll_address_is_valid(const struct in_addr *address) {
+        uint32_t addr;
+
+        assert(address);
+
+        if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+                return false;
+
+        addr = be32toh(address->s_addr);
+
+        if ((addr & 0x0000FF00) == 0x0000 ||
+            (addr & 0x0000FF00) == 0xFF00)
+                return false;
+
+        return true;
+}
+
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
+        int r;
+
+        assert_return(ll, -EINVAL);
+        assert_return(address, -EINVAL);
+        assert_return(ipv4ll_address_is_valid(address), -EINVAL);
+
+        r = sd_ipv4acd_set_address(ll->acd, address);
+        if (r < 0)
+                return r;
+
+        ll->address = address->s_addr;
+
+        return 0;
+}
+
 static int ipv4ll_pick_address(sd_ipv4ll *ll) {
         struct in_addr in_addr;
         be32_t addr;
@@ -247,18 +282,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
                         return r;
                 addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
         } while (addr == ll->address ||
-                (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
                 (ntohl(addr) & 0x0000FF00) == 0x0000 ||
                 (ntohl(addr) & 0x0000FF00) == 0xFF00);
 
         in_addr.s_addr = addr;
 
-        r = sd_ipv4acd_set_address(ll->acd, &in_addr);
+        r = sd_ipv4ll_set_address(ll, &in_addr);
         if (r < 0)
                 return r;
 
-        ll->address = addr;
-
         return 0;
 }
 
index 06949a1e8303ead8a9fe4728de3c130551b9464f..4ebe8053fa2e61cd0254757e289a3cf2966df847 100644 (file)
 
 #include <arpa/inet.h>
 
-#include "siphash24.h"
-#include "hashmap.h"
-
-#include "lldp-tlv.h"
-#include "lldp-port.h"
 #include "sd-lldp.h"
-#include "prioq.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
 #include "lldp-internal.h"
+#include "lldp-port.h"
+#include "lldp-tlv.h"
 #include "lldp-util.h"
+#include "prioq.h"
+#include "siphash24.h"
+#include "string-util.h"
 
 typedef enum LLDPAgentRXState {
         LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
new file mode 100644 (file)
index 0000000..0881973
--- /dev/null
@@ -0,0 +1,672 @@
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  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 <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "sd-ndisc.h"
+
+#include "alloc-util.h"
+#include "async.h"
+#include "icmp6-util.h"
+#include "in-addr-util.h"
+#include "list.h"
+#include "socket-util.h"
+
+#define NDISC_ROUTER_SOLICITATION_INTERVAL      4 * USEC_PER_SEC
+#define NDISC_MAX_ROUTER_SOLICITATIONS          3
+
+enum NDiscState {
+        NDISC_STATE_IDLE,
+        NDISC_STATE_SOLICITATION_SENT,
+        NDISC_STATE_ADVERTISMENT_LISTEN,
+        _NDISC_STATE_MAX,
+        _NDISC_STATE_INVALID = -1,
+};
+
+#define IP6_MIN_MTU (unsigned)1280
+#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
+#define NDISC_OPT_LEN_UNITS 8
+
+#define ND_RA_FLAG_PREF                0x18
+#define ND_RA_FLAG_PREF_LOW            0x03
+#define ND_RA_FLAG_PREF_MEDIUM         0x0
+#define ND_RA_FLAG_PREF_HIGH           0x1
+#define ND_RA_FLAG_PREF_INVALID        0x2
+
+typedef struct NDiscPrefix NDiscPrefix;
+
+struct NDiscPrefix {
+        unsigned n_ref;
+
+        sd_ndisc *nd;
+
+        LIST_FIELDS(NDiscPrefix, prefixes);
+
+        uint8_t len;
+        usec_t valid_until;
+        struct in6_addr addr;
+};
+
+struct sd_ndisc {
+        unsigned n_ref;
+
+        enum NDiscState state;
+        sd_event *event;
+        int event_priority;
+        int index;
+        struct ether_addr mac_addr;
+        uint32_t mtu;
+        LIST_HEAD(NDiscPrefix, prefixes);
+        int fd;
+        sd_event_source *recv;
+        sd_event_source *timeout;
+        int nd_sent;
+        sd_ndisc_router_callback_t router_callback;
+        sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback;
+        sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback;
+        sd_ndisc_callback_t callback;
+        void *userdata;
+};
+
+#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
+
+static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) {
+
+        if (!prefix)
+                return NULL;
+
+        assert(prefix->n_ref > 0);
+        prefix->n_ref--;
+
+        if (prefix->n_ref > 0)
+                return NULL;
+
+        if (prefix->nd)
+                LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix);
+
+        free(prefix);
+
+        return NULL;
+}
+
+static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) {
+        _cleanup_free_ NDiscPrefix *prefix = NULL;
+
+        assert(ret);
+
+        prefix = new0(NDiscPrefix, 1);
+        if (!prefix)
+                return -ENOMEM;
+
+        prefix->n_ref = 1;
+        LIST_INIT(prefixes, prefix);
+        prefix->nd = nd;
+
+        *ret = prefix;
+        prefix = NULL;
+
+        return 0;
+}
+
+int sd_ndisc_set_callback(sd_ndisc *nd,
+                          sd_ndisc_router_callback_t router_callback,
+                          sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback,
+                          sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback,
+                          sd_ndisc_callback_t callback,
+                          void *userdata) {
+        assert(nd);
+
+        nd->router_callback = router_callback;
+        nd->prefix_onlink_callback = prefix_onlink_callback;
+        nd->prefix_autonomous_callback = prefix_autonomous_callback;
+        nd->callback = callback;
+        nd->userdata = userdata;
+
+        return 0;
+}
+
+int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) {
+        assert(nd);
+        assert(interface_index >= -1);
+
+        nd->index = interface_index;
+
+        return 0;
+}
+
+int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
+        assert(nd);
+
+        if (mac_addr)
+                memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr));
+        else
+                zero(nd->mac_addr);
+
+        return 0;
+
+}
+
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) {
+        int r;
+
+        assert_return(nd, -EINVAL);
+        assert_return(!nd->event, -EBUSY);
+
+        if (event)
+                nd->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&nd->event);
+                if (r < 0)
+                        return 0;
+        }
+
+        nd->event_priority = priority;
+
+        return 0;
+}
+
+int sd_ndisc_detach_event(sd_ndisc *nd) {
+        assert_return(nd, -EINVAL);
+
+        nd->event = sd_event_unref(nd->event);
+
+        return 0;
+}
+
+sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
+        assert(nd);
+
+        return nd->event;
+}
+
+sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
+
+        if (!nd)
+                return NULL;
+
+        assert(nd->n_ref > 0);
+        nd->n_ref++;
+
+        return nd;
+}
+
+static int ndisc_init(sd_ndisc *nd) {
+        assert(nd);
+
+        nd->recv = sd_event_source_unref(nd->recv);
+        nd->fd = asynchronous_close(nd->fd);
+        nd->timeout = sd_event_source_unref(nd->timeout);
+
+        return 0;
+}
+
+sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
+        NDiscPrefix *prefix, *p;
+
+        if (!nd)
+                return NULL;
+
+        assert(nd->n_ref > 0);
+        nd->n_ref--;
+
+        if (nd->n_ref > 0)
+                return NULL;
+
+        ndisc_init(nd);
+        sd_ndisc_detach_event(nd);
+
+        LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes)
+                prefix = ndisc_prefix_unref(prefix);
+
+        free(nd);
+
+        return NULL;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref);
+#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp)
+
+int sd_ndisc_new(sd_ndisc **ret) {
+        _cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL;
+
+        assert(ret);
+
+        nd = new0(sd_ndisc, 1);
+        if (!nd)
+                return -ENOMEM;
+
+        nd->n_ref = 1;
+
+        nd->index = -1;
+        nd->fd = -1;
+
+        LIST_HEAD_INIT(nd->prefixes);
+
+        *ret = nd;
+        nd = NULL;
+
+        return 0;
+}
+
+int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
+        assert_return(nd, -EINVAL);
+        assert_return(mtu, -EINVAL);
+
+        if (nd->mtu == 0)
+                return -ENOMSG;
+
+        *mtu = nd->mtu;
+
+        return 0;
+}
+
+static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
+                        const struct in6_addr *addr,
+                        uint8_t addr_prefixlen) {
+        uint8_t bytes, mask, len;
+
+        assert_return(prefix, -EINVAL);
+        assert_return(addr, -EINVAL);
+
+        len = MIN(prefixlen, addr_prefixlen);
+
+        bytes = len / 8;
+        mask = 0xff << (8 - len % 8);
+
+        if (memcmp(prefix, addr, bytes) != 0 ||
+            (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask))
+                return -EADDRNOTAVAIL;
+
+        return 0;
+}
+
+static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr,
+                              uint8_t addr_len, NDiscPrefix **result) {
+        NDiscPrefix *prefix, *p;
+        usec_t time_now;
+        int r;
+
+        assert(nd);
+
+        r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
+        if (r < 0)
+                return r;
+
+        LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
+                if (prefix->valid_until < time_now) {
+                        prefix = ndisc_prefix_unref(prefix);
+
+                        continue;
+                }
+
+                if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) {
+                        *result = prefix;
+                        return 0;
+                }
+        }
+
+        return -EADDRNOTAVAIL;
+}
+
+static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
+                               const struct nd_opt_prefix_info *prefix_opt) {
+        NDiscPrefix *prefix;
+        uint32_t lifetime_valid, lifetime_preferred;
+        usec_t time_now;
+        char time_string[FORMAT_TIMESPAN_MAX];
+        int r;
+
+        assert(nd);
+        assert(prefix_opt);
+
+        if (len < prefix_opt->nd_opt_pi_len)
+                return -ENOMSG;
+
+        if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO)))
+                return 0;
+
+        if (in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &prefix_opt->nd_opt_pi_prefix) > 0)
+                return 0;
+
+        lifetime_valid = be32toh(prefix_opt->nd_opt_pi_valid_time);
+        lifetime_preferred = be32toh(prefix_opt->nd_opt_pi_preferred_time);
+
+        if (lifetime_valid < lifetime_preferred)
+                return 0;
+
+        r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix,
+                               prefix_opt->nd_opt_pi_prefix_len, &prefix);
+
+        if (r < 0 && r != -EADDRNOTAVAIL)
+                return r;
+
+        /* if router advertisment prefix valid timeout is zero, the timeout
+           callback will be called immediately to clean up the prefix */
+
+        if (r == -EADDRNOTAVAIL) {
+                r = ndisc_prefix_new(nd, &prefix);
+                if (r < 0)
+                        return r;
+
+                prefix->len = prefix_opt->nd_opt_pi_prefix_len;
+
+                memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
+                        sizeof(prefix->addr));
+
+                log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+                             SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
+                             prefix->len, lifetime_valid,
+                             format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC));
+
+                LIST_PREPEND(prefixes, nd->prefixes, prefix);
+
+        } else {
+                if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) {
+                        uint8_t prefixlen;
+
+                        prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len);
+
+                        log_ndisc(nd, "Prefix length mismatch %d/%d using %d",
+                                     prefix->len,
+                                     prefix_opt->nd_opt_pi_prefix_len,
+                                     prefixlen);
+
+                        prefix->len = prefixlen;
+                }
+
+                log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+                             SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
+                             prefix->len, lifetime_valid,
+                             format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC));
+        }
+
+        r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
+        if (r < 0)
+                return r;
+
+        prefix->valid_until = time_now + lifetime_valid * USEC_PER_SEC;
+
+        if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && nd->prefix_onlink_callback)
+                nd->prefix_onlink_callback(nd, &prefix->addr, prefix->len, prefix->valid_until, nd->userdata);
+
+        if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && nd->prefix_autonomous_callback)
+                nd->prefix_autonomous_callback(nd, &prefix->addr, prefix->len, lifetime_preferred, lifetime_valid,
+                                               nd->userdata);
+
+        return 0;
+}
+
+static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
+                          ssize_t len) {
+        void *opt;
+        struct nd_opt_hdr *opt_hdr;
+
+        assert_return(nd, -EINVAL);
+        assert_return(ra, -EINVAL);
+
+        len -= sizeof(*ra);
+        if (len < NDISC_OPT_LEN_UNITS) {
+                log_ndisc(nd, "Router Advertisement below minimum length");
+
+                return -ENOMSG;
+        }
+
+        opt = ra + 1;
+        opt_hdr = opt;
+
+        while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) {
+                struct nd_opt_mtu *opt_mtu;
+                uint32_t mtu;
+                struct nd_opt_prefix_info *opt_prefix;
+
+                if (opt_hdr->nd_opt_len == 0)
+                        return -ENOMSG;
+
+                switch (opt_hdr->nd_opt_type) {
+                case ND_OPT_MTU:
+                        opt_mtu = opt;
+
+                        mtu = be32toh(opt_mtu->nd_opt_mtu_mtu);
+
+                        if (mtu != nd->mtu) {
+                                nd->mtu = MAX(mtu, IP6_MIN_MTU);
+
+                                log_ndisc(nd, "Router Advertisement link MTU %d using %d",
+                                             mtu, nd->mtu);
+                        }
+
+                        break;
+
+                case ND_OPT_PREFIX_INFORMATION:
+                        opt_prefix = opt;
+
+                        ndisc_prefix_update(nd, len, opt_prefix);
+
+                        break;
+                }
+
+                len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS;
+                opt = (void *)((char *)opt +
+                        opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
+                opt_hdr = opt;
+        }
+
+        if (len > 0)
+                log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
+
+        return 0;
+}
+
+static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_free_ struct nd_router_advert *ra = NULL;
+        sd_ndisc *nd = userdata;
+        int r, buflen = 0, pref, stateful;
+        union sockaddr_union router = {};
+        socklen_t router_len = sizeof(router);
+        unsigned lifetime;
+        ssize_t len;
+
+        assert(s);
+        assert(nd);
+        assert(nd->event);
+
+        r = ioctl(fd, FIONREAD, &buflen);
+        if (r < 0 || buflen <= 0)
+                buflen = ICMP6_RECV_SIZE;
+
+        ra = malloc(buflen);
+        if (!ra)
+                return -ENOMEM;
+
+        len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len);
+        if (len < 0) {
+                log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m");
+                return 0;
+        } else if (router_len != sizeof(router.in6) && router_len != 0) {
+                log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len);
+                return 0;
+        }
+
+        if (ra->nd_ra_type != ND_ROUTER_ADVERT)
+                return 0;
+
+        if (ra->nd_ra_code != 0)
+                return 0;
+
+        nd->timeout = sd_event_source_unref(nd->timeout);
+
+        nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
+
+        stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER);
+        pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3;
+
+        switch (pref) {
+        case ND_RA_FLAG_PREF_LOW:
+        case ND_RA_FLAG_PREF_HIGH:
+                break;
+        default:
+                pref = ND_RA_FLAG_PREF_MEDIUM;
+                break;
+        }
+
+        lifetime = be16toh(ra->nd_ra_router_lifetime);
+
+        log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %u sec",
+                  stateful & ND_RA_FLAG_MANAGED ? "MANAGED" : stateful & ND_RA_FLAG_OTHER ? "OTHER" : "none",
+                  pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium",
+                  lifetime);
+
+        r = ndisc_ra_parse(nd, ra, len);
+        if (r < 0) {
+                log_ndisc(nd, "Could not parse Router Advertisement: %s", strerror(-r));
+                return 0;
+        }
+
+        if (nd->router_callback)
+                nd->router_callback(nd, stateful, router_len != 0 ? &router.in6.sin6_addr : NULL, lifetime, pref, nd->userdata);
+
+        return 0;
+}
+
+static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+        sd_ndisc *nd = userdata;
+        uint64_t time_now, next_timeout;
+        struct ether_addr unset = { };
+        struct ether_addr *addr = NULL;
+        int r;
+
+        assert(s);
+        assert(nd);
+        assert(nd->event);
+
+        nd->timeout = sd_event_source_unref(nd->timeout);
+
+        if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) {
+                if (nd->callback)
+                        nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata);
+                nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
+        } else {
+                if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
+                        addr = &nd->mac_addr;
+
+                r = icmp6_send_router_solicitation(nd->fd, addr);
+                if (r < 0)
+                        log_ndisc(nd, "Error sending Router Solicitation");
+                else {
+                        nd->state = NDISC_STATE_SOLICITATION_SENT;
+                        log_ndisc(nd, "Sent Router Solicitation");
+                }
+
+                nd->nd_sent++;
+
+                assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+                next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
+
+                r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
+                                      next_timeout, 0,
+                                      ndisc_router_solicitation_timeout, nd);
+                if (r < 0) {
+                        /* we cannot continue if we are unable to rearm the timer */
+                        sd_ndisc_stop(nd);
+                        return 0;
+                }
+
+                r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
+                if (r < 0)
+                        return 0;
+
+                r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
+                if (r < 0)
+                        return 0;
+        }
+
+        return 0;
+}
+
+int sd_ndisc_stop(sd_ndisc *nd) {
+        assert_return(nd, -EINVAL);
+        assert_return(nd->event, -EINVAL);
+
+        log_ndisc(client, "Stop NDisc");
+
+        ndisc_init(nd);
+
+        nd->state = NDISC_STATE_IDLE;
+
+        if (nd->callback)
+                nd->callback(nd, SD_NDISC_EVENT_STOP, nd->userdata);
+
+        return 0;
+}
+
+int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
+        int r;
+
+        assert(nd);
+        assert(nd->event);
+
+        if (nd->state != NDISC_STATE_IDLE)
+                return -EINVAL;
+
+        if (nd->index < 1)
+                return -EINVAL;
+
+        r = icmp6_bind_router_solicitation(nd->index);
+        if (r < 0)
+                return r;
+
+        nd->fd = r;
+
+        r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
+                            ndisc_router_advertisment_recv, nd);
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_priority(nd->recv, nd->event_priority);
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_description(nd->recv, "ndisc-receive-message");
+        if (r < 0)
+                goto error;
+
+        r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
+                              0, 0, ndisc_router_solicitation_timeout, nd);
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
+        if (r < 0)
+                goto error;
+
+        r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
+error:
+        if (r < 0)
+                ndisc_init(nd);
+        else
+                log_ndisc(client, "Start Router Solicitation");
+
+        return r;
+}
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
deleted file mode 100644 (file)
index cd5a204..0000000
+++ /dev/null
@@ -1,810 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Tom Gundersen
-
-  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/>.
-***/
-
-/* See RFC 2516 */
-
-#include <sys/ioctl.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <linux/if_pppox.h>
-
-#include "sd-pppoe.h"
-
-#include "event-util.h"
-
-#include "util.h"
-#include "random-util.h"
-#include "socket-util.h"
-#include "async.h"
-#include "utf8.h"
-
-#define PPPOE_MAX_PACKET_SIZE 1484
-#define PPPOE_MAX_PADR_RESEND 16
-
-/* TODO: move this to socket-util.h without getting into
- * a mess with the includes */
-union sockaddr_union_pppox {
-        struct sockaddr sa;
-        struct sockaddr_pppox pppox;
-};
-
-typedef enum PPPoEState {
-        PPPOE_STATE_INITIALIZING,
-        PPPOE_STATE_REQUESTING,
-        PPPOE_STATE_RUNNING,
-        PPPOE_STATE_STOPPED,
-        _PPPOE_STATE_MAX,
-        _PPPOE_STATE_INVALID = -1,
-} PPPoEState;
-
-typedef struct PPPoETags {
-                char *service_name;
-                char *ac_name;
-                uint8_t *host_uniq;
-                size_t host_uniq_len;
-                uint8_t *cookie;
-                size_t cookie_len;
-} PPPoETags;
-
-struct sd_pppoe {
-        unsigned n_ref;
-
-        PPPoEState state;
-        uint64_t host_uniq;
-
-        int ifindex;
-        char *ifname;
-
-        sd_event *event;
-        int event_priority;
-        int fd;
-        sd_event_source *io;
-        sd_event_source *timeout;
-        int padr_resend_count;
-
-        char *service_name;
-        struct ether_addr peer_mac;
-        be16_t session_id;
-
-        int pppoe_fd;
-        int channel;
-
-        sd_pppoe_cb_t cb;
-        void *userdata;
-
-        PPPoETags tags;
-};
-
-#define PPPOE_PACKET_LENGTH(header) \
-        be16toh((header)->length)
-
-#define PPPOE_PACKET_TAIL(packet)                                                                               \
-        (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
-
-#define PPPOE_TAG_LENGTH(tag)  \
-        be16toh((tag)->tag_len)
-
-#define PPPOE_TAG_TYPE(tag) \
-        (tag)->tag_type
-
-#define PPPOE_TAG_NEXT(tag)                                                                      \
-        (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag))
-
-#define PPPOE_TAGS_FOREACH(tag, header)                                                                 \
-        for (tag = (header)->tag;                                                                       \
-             ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) &&     \
-                (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) &&                                   \
-                (tag >= (header)->tag) &&                                                               \
-                (PPPOE_TAG_TYPE(tag) != PTT_EOL);                                                           \
-             tag = PPPOE_TAG_NEXT(tag))
-
-static void pppoe_tags_clear(PPPoETags *tags) {
-        free(tags->service_name);
-        free(tags->ac_name);
-        free(tags->host_uniq);
-        free(tags->cookie);
-
-        zero(*tags);
-}
-
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) {
-        assert_return(ppp, -EINVAL);
-        assert_return(ifindex > 0, -EINVAL);
-
-        ppp->ifindex = ifindex;
-
-        return 0;
-}
-
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) {
-        char *name;
-
-        assert_return(ppp, -EINVAL);
-        assert_return(ifname, -EINVAL);
-
-        if (strlen(ifname) > IFNAMSIZ)
-                return -EINVAL;
-
-        name = strdup(ifname);
-        if (!name)
-                return -ENOMEM;
-
-        free(ppp->ifname);
-        ppp->ifname = name;
-
-        return 0;
-}
-
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) {
-        _cleanup_free_ char *name = NULL;
-
-        assert_return(ppp, -EINVAL);
-
-        if (service_name) {
-                name = strdup(service_name);
-                if (!name)
-                        return -ENOMEM;
-        }
-
-        free(ppp->service_name);
-        ppp->service_name = name;
-        name = NULL;
-
-        return 0;
-}
-
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) {
-        int r;
-
-        assert_return(ppp, -EINVAL);
-        assert_return(!ppp->event, -EBUSY);
-
-        if (event)
-                ppp->event = sd_event_ref(event);
-        else {
-                r = sd_event_default(&ppp->event);
-                if (r < 0)
-                        return r;
-        }
-
-        ppp->event_priority = priority;
-
-        return 0;
-}
-
-int sd_pppoe_detach_event(sd_pppoe *ppp) {
-        assert_return(ppp, -EINVAL);
-
-        ppp->event = sd_event_unref(ppp->event);
-
-        return 0;
-}
-
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) {
-
-        if (!ppp)
-                return NULL;
-
-        assert(ppp->n_ref > 0);
-        ppp->n_ref++;
-
-        return ppp;
-}
-
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) {
-
-        if (!ppp)
-                return NULL;
-
-        assert(ppp->n_ref > 0);
-        ppp->n_ref--;
-
-        if (ppp->n_ref > 0)
-                return NULL;
-
-        pppoe_tags_clear(&ppp->tags);
-        free(ppp->ifname);
-        free(ppp->service_name);
-        sd_pppoe_stop(ppp);
-        sd_pppoe_detach_event(ppp);
-
-        free(ppp);
-        return NULL;
-}
-
-int sd_pppoe_new (sd_pppoe **ret) {
-        sd_pppoe *ppp;
-
-        assert_return(ret, -EINVAL);
-
-        ppp = new0(sd_pppoe, 1);
-        if (!ppp)
-                return -ENOMEM;
-
-        ppp->n_ref = 1;
-        ppp->state = _PPPOE_STATE_INVALID;
-        ppp->ifindex = -1;
-        ppp->fd = -1;
-        ppp->pppoe_fd = -1;
-        ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
-
-        *ret = ppp;
-
-        return 0;
-}
-
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) {
-        assert_return(ppp, -EINVAL);
-        assert_return(channel, -EINVAL);
-        assert_return(ppp->pppoe_fd != -1, -EUNATCH);
-        assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH);
-
-        *channel = ppp->channel;
-
-        return 0;
-}
-
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) {
-        assert_return(ppp, -EINVAL);
-
-        ppp->cb = cb;
-        ppp->userdata = userdata;
-
-        return 0;
-}
-
-static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) {
-        struct pppoe_tag *tag;
-
-        assert(packet);
-        assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size);
-        assert(!(!tag_data ^ !tag_len));
-
-        tag = PPPOE_PACKET_TAIL(packet);
-
-        tag->tag_len = htobe16(tag_len);
-        tag->tag_type = tag_type;
-        if (tag_data)
-                memcpy(tag->tag_data, tag_data, tag_len);
-
-        packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len);
-}
-
-static int pppoe_send(sd_pppoe *ppp, uint8_t code) {
-        union sockaddr_union link = {
-                .ll = {
-                        .sll_family = AF_PACKET,
-                        .sll_protocol = htons(ETH_P_PPP_DISC),
-                        .sll_halen = ETH_ALEN,
-                },
-        };
-        _cleanup_free_ struct pppoe_hdr *packet = NULL;
-        int r;
-
-        assert(ppp);
-        assert(ppp->fd != -1);
-        assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE));
-
-        link.ll.sll_ifindex = ppp->ifindex;
-        if (code == PADI_CODE)
-                memset(&link.ll.sll_addr, 0xff, ETH_ALEN);
-        else
-                memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN);
-
-        packet = malloc0(PPPOE_MAX_PACKET_SIZE);
-        if (!packet)
-                return -ENOMEM;
-
-        packet->ver = 0x1;
-        packet->type = 0x1;
-        packet->code = code;
-        if (code == PADT_CODE)
-                packet->sid = ppp->session_id;
-
-        /* Service-Name */
-        pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME,
-                         ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0);
-
-        /* AC-Cookie */
-        if (code == PADR_CODE && ppp->tags.cookie)
-                pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE,
-                                 ppp->tags.cookie, ppp->tags.cookie_len);
-
-        /* Host-Uniq */
-        if (code != PADT_CODE) {
-                ppp->host_uniq = random_u64();
-
-                pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ,
-                                 &ppp->host_uniq, sizeof(ppp->host_uniq));
-        }
-
-        r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet),
-                   0, &link.sa, sizeof(link.ll));
-        if (r < 0)
-                return -errno;
-
-        return 0;
-}
-
-static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata);
-
-static int pppoe_arm_timeout(sd_pppoe *ppp) {
-        _cleanup_event_source_unref_ sd_event_source *timeout = NULL;
-        usec_t next_timeout = 0;
-        int r;
-
-        assert(ppp);
-
-        r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
-        if (r < 0)
-                return r;
-
-        next_timeout += 500 * USEC_PER_MSEC;
-
-        r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout,
-                              10 * USEC_PER_MSEC, pppoe_timeout, ppp);
-        if (r < 0)
-                return r;
-
-        r = sd_event_source_set_priority(timeout, ppp->event_priority);
-        if (r < 0)
-                return r;
-
-        sd_event_source_unref(ppp->timeout);
-        ppp->timeout = timeout;
-        timeout = NULL;
-
-        return 0;
-}
-
-static int pppoe_send_initiation(sd_pppoe *ppp) {
-        int r;
-
-        r = pppoe_send(ppp, PADI_CODE);
-        if (r < 0)
-                return r;
-
-        log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
-                  strna(ppp->service_name));
-
-        pppoe_arm_timeout(ppp);
-
-        return r;
-}
-
-static int pppoe_send_request(sd_pppoe *ppp) {
-        int r;
-
-        r = pppoe_send(ppp, PADR_CODE);
-        if (r < 0)
-                return r;
-
-        log_debug("PPPoE: sent REQUEST");
-
-        ppp->padr_resend_count --;
-
-        pppoe_arm_timeout(ppp);
-
-        return 0;
-}
-
-static int pppoe_send_terminate(sd_pppoe *ppp) {
-        int r;
-
-        r = pppoe_send(ppp, PADT_CODE);
-        if (r < 0)
-                return r;
-
-        log_debug("PPPoE: sent TERMINATE");
-
-        return 0;
-}
-
-static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
-        sd_pppoe *ppp = userdata;
-        int r;
-
-        assert(ppp);
-
-        switch (ppp->state) {
-        case PPPOE_STATE_INITIALIZING:
-                r = pppoe_send_initiation(ppp);
-                if (r < 0)
-                        log_warning_errno(r, "PPPoE: sending PADI failed: %m");
-
-                break;
-        case PPPOE_STATE_REQUESTING:
-                if (ppp->padr_resend_count <= 0) {
-                        log_debug("PPPoE: PADR timed out, restarting PADI");
-
-                        r = pppoe_send_initiation(ppp);
-                        if (r < 0)
-                                log_warning_errno(r, "PPPoE: sending PADI failed: %m");
-
-                        ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
-                        ppp->state = PPPOE_STATE_INITIALIZING;
-                } else {
-                        r = pppoe_send_request(ppp);
-                        if (r < 0)
-                                log_warning_errno(r, "PPPoE: sending PADR failed: %m");
-                }
-
-                break;
-        default:
-                assert_not_reached("timeout in invalid state");
-        }
-
-        return 0;
-}
-
-static int pppoe_tag_parse_binary(struct pppoe_tag *tag, uint8_t **ret, size_t *length) {
-        uint8_t *data;
-
-        assert(ret);
-        assert(length);
-
-        data = memdup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
-        if (!data)
-                return -ENOMEM;
-
-        free(*ret);
-        *ret = data;
-        *length = PPPOE_TAG_LENGTH(tag);
-
-        return 0;
-}
-
-static int pppoe_tag_parse_string(struct pppoe_tag *tag, char **ret) {
-        char *string;
-
-        assert(ret);
-
-        string = strndup(tag->tag_data, PPPOE_TAG_LENGTH(tag));
-        if (!string)
-                return -ENOMEM;
-
-        free(*ret);
-        *ret = string;
-
-        return 0;
-}
-
-static int pppoe_payload_parse(PPPoETags *tags, struct pppoe_hdr *header) {
-        struct pppoe_tag *tag;
-        int r;
-
-        assert(tags);
-
-        pppoe_tags_clear(tags);
-
-        PPPOE_TAGS_FOREACH(tag, header) {
-                switch (PPPOE_TAG_TYPE(tag)) {
-                case PTT_SRV_NAME:
-                        r = pppoe_tag_parse_string(tag, &tags->service_name);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                case PTT_AC_NAME:
-                        r = pppoe_tag_parse_string(tag, &tags->ac_name);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                case PTT_HOST_UNIQ:
-                        r = pppoe_tag_parse_binary(tag, &tags->host_uniq, &tags->host_uniq_len);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                case PTT_AC_COOKIE:
-                        r = pppoe_tag_parse_binary(tag, &tags->cookie, &tags->cookie_len);
-                        if (r < 0)
-                                return r;
-
-                        break;
-                case PTT_SRV_ERR:
-                case PTT_SYS_ERR:
-                case PTT_GEN_ERR:
-                {
-                        _cleanup_free_ char *error = NULL;
-
-                        /* TODO: do something more sensible with the error messages */
-                        r = pppoe_tag_parse_string(tag, &error);
-                        if (r < 0)
-                                return r;
-
-                        if (strlen(error) > 0 && utf8_is_valid(error))
-                                log_debug("PPPoE: error - '%s'", error);
-                        else
-                                log_debug("PPPoE: error");
-
-                        break;
-                }
-                default:
-                        log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag));
-                }
-        }
-
-        return 0;
-}
-
-static int pppoe_open_pppoe_socket(sd_pppoe *ppp) {
-        int s;
-
-        assert(ppp);
-        assert(ppp->pppoe_fd == -1);
-
-        s = socket(AF_PPPOX, SOCK_STREAM, 0);
-        if (s < 0)
-                return -errno;
-
-        ppp->pppoe_fd = s;
-
-        return 0;
-}
-
-static int pppoe_connect_pppoe_socket(sd_pppoe *ppp) {
-        union sockaddr_union_pppox link = {
-                .pppox = {
-                        .sa_family = AF_PPPOX,
-                        .sa_protocol = PX_PROTO_OE,
-                },
-        };
-        int r, channel;
-
-        assert(ppp);
-        assert(ppp->pppoe_fd != -1);
-        assert(ppp->session_id);
-        assert(ppp->ifname);
-
-        link.pppox.sa_addr.pppoe.sid = ppp->session_id;
-        memcpy(link.pppox.sa_addr.pppoe.dev, ppp->ifname, strlen(ppp->ifname));
-        memcpy(link.pppox.sa_addr.pppoe.remote, &ppp->peer_mac, ETH_ALEN);
-
-        r = connect(ppp->pppoe_fd, &link.sa, sizeof(link.pppox));
-        if (r < 0)
-                return r;
-
-        r = ioctl(ppp->pppoe_fd, PPPIOCGCHAN, &channel);
-        if (r < 0)
-                return -errno;
-
-        ppp->channel = channel;
-
-        return 0;
-}
-
-static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct ether_addr *mac) {
-        int r;
-
-        assert(packet);
-
-        if (packet->ver != 0x1 || packet->type != 0x1)
-                return 0;
-
-        r = pppoe_payload_parse(&ppp->tags, packet);
-        if (r < 0)
-                return 0;
-
-        switch (ppp->state) {
-        case PPPOE_STATE_INITIALIZING:
-                if (packet->code != PADO_CODE)
-                        return 0;
-
-                if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
-                    memcmp(ppp->tags.host_uniq, &ppp->host_uniq, sizeof(ppp->host_uniq)) != 0)
-                        return 0;
-
-                log_debug("PPPoE: got OFFER (Peer: "
-                  "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; "
-                  "Service-Name: '%s'; AC-Name: '%s')",
-                  mac->ether_addr_octet[0],
-                  mac->ether_addr_octet[1],
-                  mac->ether_addr_octet[2],
-                  mac->ether_addr_octet[3],
-                  mac->ether_addr_octet[4],
-                  mac->ether_addr_octet[5],
-                  strempty(ppp->tags.service_name),
-                  strempty(ppp->tags.ac_name));
-
-                memcpy(&ppp->peer_mac, mac, ETH_ALEN);
-
-                r = pppoe_open_pppoe_socket(ppp);
-                if (r < 0) {
-                        log_warning("PPPoE: could not open socket");
-                        return r;
-                }
-
-                r = pppoe_send_request(ppp);
-                if (r < 0)
-                        return 0;
-
-                ppp->state = PPPOE_STATE_REQUESTING;
-
-                break;
-        case PPPOE_STATE_REQUESTING:
-                if (packet->code != PADS_CODE)
-                        return 0;
-
-                if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) ||
-                    memcmp(ppp->tags.host_uniq, &ppp->host_uniq,
-                           sizeof(ppp->host_uniq)) != 0)
-                        return 0;
-
-                if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
-                        return 0;
-
-                ppp->session_id = packet->sid;
-
-                log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16")",
-                          be16toh(ppp->session_id));
-
-                r = pppoe_connect_pppoe_socket(ppp);
-                if (r < 0) {
-                        log_warning("PPPoE: could not connect socket");
-                        return r;
-                }
-
-                ppp->state = PPPOE_STATE_RUNNING;
-
-                ppp->timeout = sd_event_source_unref(ppp->timeout);
-                assert(ppp->cb);
-                ppp->cb(ppp, SD_PPPOE_EVENT_RUNNING, ppp->userdata);
-
-                break;
-        case PPPOE_STATE_RUNNING:
-                if (packet->code != PADT_CODE)
-                        return 0;
-
-                if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
-                        return 0;
-
-                if (ppp->session_id != packet->sid)
-                        return 0;
-
-                log_debug("PPPoE: got TERMINATE");
-
-                ppp->state = PPPOE_STATE_STOPPED;
-
-                assert(ppp->cb);
-                ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata);
-
-                break;
-        case PPPOE_STATE_STOPPED:
-                break;
-        default:
-                assert_not_reached("PPPoE: invalid state when receiving message");
-        }
-
-        return 0;
-}
-
-static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
-        sd_pppoe *ppp = userdata;
-        _cleanup_free_ struct pppoe_hdr *packet = NULL;
-        union sockaddr_union link = {};
-        socklen_t addrlen = sizeof(link);
-        int buflen = 0, len, r;
-
-        assert(ppp);
-        assert(fd != -1);
-
-        r = ioctl(fd, FIONREAD, &buflen);
-        if (r < 0)
-                return r;
-
-        if (buflen < 0)
-                /* this can't be right */
-                return -EIO;
-
-        packet = malloc0(buflen);
-        if (!packet)
-                return -ENOMEM;
-
-        len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen);
-        if (len < 0) {
-                log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m");
-                return 0;
-        } else if ((size_t)len < sizeof(struct pppoe_hdr))
-                return 0;
-        else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
-                return 0;
-
-        if (link.ll.sll_halen != ETH_ALEN)
-                /* not ethernet? */
-                return 0;
-
-        r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr);
-        if (r < 0)
-                return r;
-
-        return 1;
-}
-
-int sd_pppoe_start(sd_pppoe *ppp) {
-        union sockaddr_union link = {
-                .ll = {
-                        .sll_family = AF_PACKET,
-                        .sll_protocol = htons(ETH_P_PPP_DISC),
-                },
-        };
-        _cleanup_close_ int s = -1;
-        _cleanup_event_source_unref_ sd_event_source *io = NULL;
-        int r;
-
-        assert_return(ppp, -EINVAL);
-        assert_return(ppp->fd == -1, -EBUSY);
-        assert_return(!ppp->io, -EBUSY);
-        assert_return(ppp->ifindex > 0, -EUNATCH);
-        assert_return(ppp->ifname, -EUNATCH);
-        assert_return(ppp->event, -EUNATCH);
-        assert_return(ppp->cb, -EUNATCH);
-
-        s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
-        if (s < 0)
-                return -errno;
-
-        link.ll.sll_ifindex = ppp->ifindex;
-
-        r = bind(s, &link.sa, sizeof(link.ll));
-        if (r < 0)
-                return r;
-
-        r = sd_event_add_io(ppp->event, &io,
-                            s, EPOLLIN, pppoe_receive_message,
-                            ppp);
-        if (r < 0)
-                return r;
-
-        r = sd_event_source_set_priority(io, ppp->event_priority);
-        if (r < 0)
-                return r;
-
-        ppp->fd = s;
-        s = -1;
-        ppp->io = io;
-        io = NULL;
-
-        r = pppoe_send_initiation(ppp);
-        if (r < 0)
-                return r;
-
-        ppp->state = PPPOE_STATE_INITIALIZING;
-
-        return 0;
-}
-
-int sd_pppoe_stop(sd_pppoe *ppp) {
-        assert_return(ppp, -EINVAL);
-
-        if (ppp->state == PPPOE_STATE_RUNNING)
-                pppoe_send_terminate(ppp);
-
-        ppp->io = sd_event_source_unref(ppp->io);
-        ppp->timeout = sd_event_source_unref(ppp->timeout);
-        ppp->fd = asynchronous_close(ppp->fd);
-        ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd);
-
-        return 0;
-}
index c112ec813467697a55a6775dff5d0af83e7a52dd..5b52c1cbb9bb6b0b57c64a2d3eefa3444a3b6dd4 100644 (file)
 #include <sys/socket.h>
 #include <unistd.h>
 
-#include "util.h"
+#include "sd-dhcp-client.h"
 #include "sd-event.h"
-#include "event-util.h"
 
+#include "alloc-util.h"
 #include "dhcp-identifier.h"
-#include "dhcp-protocol.h"
 #include "dhcp-internal.h"
-#include "sd-dhcp-client.h"
+#include "dhcp-protocol.h"
+#include "event-util.h"
+#include "util.h"
+#include "fd-util.h"
 
 static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
 
index b1ef1748490732865efc4a457534ad0f37bab630..2d29e28f16885219399717fefbd3cf1d3dff4291 100644 (file)
@@ -5,11 +5,11 @@
 #include <errno.h>
 #include <string.h>
 
-#include "util.h"
-#include "macro.h"
-
-#include "dhcp-protocol.h"
+#include "alloc-util.h"
 #include "dhcp-internal.h"
+#include "dhcp-protocol.h"
+#include "macro.h"
+#include "util.h"
 
 struct option_desc {
         uint8_t sname[64];
index c3bcb9cb4b0aff39fadee1bbc0131a553d36fe9a..1a5c8c460539e8e4cfb924cde8f88e23eb3f92c7 100644 (file)
 
 #include <errno.h>
 
+#include "sd-dhcp-server.h"
 #include "sd-event.h"
-#include "event-util.h"
 
-#include "sd-dhcp-server.h"
 #include "dhcp-server-internal.h"
+#include "event-util.h"
 
 static void test_pool(struct in_addr *address, unsigned size, int ret) {
         _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
index 0c131a9897d80a7006e19a77b21680cc5251ffd6..17ed6d58f35a5d08379643675ca3141aa66863f2 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <net/ethernet.h>
 #include <stdbool.h>
 #include <stdio.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include <net/ethernet.h>
 
-#include "socket-util.h"
-#include "macro.h"
+#include "sd-dhcp6-client.h"
 #include "sd-event.h"
-#include "event-util.h"
-#include "virt.h"
 
-#include "sd-dhcp6-client.h"
-#include "dhcp6-protocol.h"
 #include "dhcp6-internal.h"
 #include "dhcp6-lease-internal.h"
+#include "dhcp6-protocol.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "socket-util.h"
+#include "virt.h"
 
 static struct ether_addr mac_addr = {
         .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
@@ -700,7 +701,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
 static int test_client_solicit(sd_event *e) {
         sd_dhcp6_client *client;
         usec_t time_now = now(clock_boottime_or_monotonic());
-        bool val = true;
+        int val = true;
 
         if (verbose)
                 printf("* %s\n", __FUNCTION__);
diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c
deleted file mode 100644 (file)
index 27b0ef4..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Intel Corporation. All rights reserved.
-
-  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 <netinet/icmp6.h>
-
-#include "socket-util.h"
-
-#include "dhcp6-internal.h"
-#include "sd-icmp6-nd.h"
-
-static struct ether_addr mac_addr = {
-        .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
-};
-
-static bool verbose = false;
-static sd_event_source *test_hangcheck;
-static int test_fd[2];
-
-typedef int (*send_ra_t)(uint8_t flags);
-static send_ra_t send_ra_function;
-
-static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
-                             void *userdata) {
-        assert_se(false);
-
-        return 0;
-}
-
-int dhcp_network_icmp6_bind_router_solicitation(int index) {
-        assert_se(index == 42);
-
-        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
-                return -errno;
-
-        return test_fd[0];
-}
-
-static int send_ra_short_prefix(uint8_t flags) {
-        uint8_t advertisement[] = {
-                0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
-                0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4,
-                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-        };
-
-        assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
-               sizeof(advertisement));
-
-        return 0;
-}
-
-static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) {
-        sd_event *e = userdata;
-        struct {
-                struct in6_addr addr;
-                uint8_t prefixlen;
-                bool success;
-        } addrs[] = {
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  52, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  64, false },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  60, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  64, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
-                  52, true },
-        };
-        uint8_t prefixlen;
-        unsigned int i;
-
-        for (i = 0; i < ELEMENTSOF(addrs); i++) {
-                printf("  %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
-                        __FUNCTION__,
-                        addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
-                        addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
-                        addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
-                        addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
-
-                if (addrs[i].success) {
-                        assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
-                                                                &prefixlen) >= 0);
-                        assert_se(addrs[i].prefixlen == prefixlen);
-                        printf("/%d onlink\n", prefixlen);
-                } else {
-                        assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
-                                                                &prefixlen) == -EADDRNOTAVAIL);
-                        printf("/128 offlink\n");
-                }
-        }
-
-        sd_event_exit(e, 0);
-}
-
-static int send_ra_prefixes(uint8_t flags) {
-        uint8_t advertisement[] = {
-                0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4,
-                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58,
-                0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84,
-                0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84,
-                0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-                0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-                0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
-                0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53
-        };
-
-        assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
-               sizeof(advertisement));
-
-        return 0;
-}
-
-static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) {
-        sd_event *e = userdata;
-        struct {
-                struct in6_addr addr;
-                uint8_t prefixlen;
-                bool success;
-        } addrs[] = {
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  63, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  64, false },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  60, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
-                  64, true },
-                { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
-                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
-                  63, false },
-        };
-        uint8_t prefixlen;
-        unsigned int i;
-
-        for (i = 0; i < ELEMENTSOF(addrs); i++) {
-                printf("  %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
-                        __FUNCTION__,
-                        addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
-                        addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
-                        addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
-                        addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
-
-                if (addrs[i].success) {
-                        assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
-                                                                &prefixlen) >= 0);
-                        assert_se(addrs[i].prefixlen == prefixlen);
-                        printf("/%d onlink\n", prefixlen);
-                } else {
-                        assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
-                                                                &prefixlen) == -EADDRNOTAVAIL);
-                        printf("/128 offlink\n");
-                }
-        }
-
-        send_ra_function = send_ra_short_prefix;
-        assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0);
-        assert_se(sd_icmp6_nd_stop(nd) >= 0);
-        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-}
-
-static void test_prefixes(void) {
-        sd_event *e;
-        sd_icmp6_nd *nd;
-
-        if (verbose)
-                printf("* %s\n", __FUNCTION__);
-
-        send_ra_function = send_ra_prefixes;
-
-        assert_se(sd_event_new(&e) >= 0);
-
-        assert_se(sd_icmp6_nd_new(&nd) >= 0);
-        assert_se(nd);
-
-        assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
-
-        assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
-        assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
-        assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0);
-
-        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-
-        sd_event_loop(e);
-
-        nd = sd_icmp6_nd_unref(nd);
-        assert_se(!nd);
-
-        close(test_fd[1]);
-
-        sd_event_unref(e);
-}
-
-static int send_ra(uint8_t flags) {
-        uint8_t advertisement[] = {
-                0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
-                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
-                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-                0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
-                0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
-                0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
-        };
-
-        advertisement[5] = flags;
-
-        assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
-               sizeof(advertisement));
-
-        if (verbose)
-                printf("  sent RA with flag 0x%02x\n", flags);
-
-        return 0;
-}
-
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
-        return send_ra_function(0);
-}
-
-static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
-        sd_event *e = userdata;
-        static int idx = 0;
-        struct {
-                uint8_t flag;
-                int event;
-        } flag_event[] = {
-                { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE },
-                { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER },
-                { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED }
-        };
-        uint32_t mtu;
-
-        assert_se(nd);
-
-        assert_se(event == flag_event[idx].event);
-        idx++;
-
-        if (verbose)
-                printf("  got event %d\n", event);
-
-        if (idx < 3) {
-                send_ra(flag_event[idx].flag);
-                return;
-        }
-
-        assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
-
-        sd_event_exit(e, 0);
-}
-
-static void test_rs(void) {
-        sd_event *e;
-        sd_icmp6_nd *nd;
-        usec_t time_now = now(clock_boottime_or_monotonic());
-
-        if (verbose)
-                printf("* %s\n", __FUNCTION__);
-
-        send_ra_function = send_ra;
-
-        assert_se(sd_event_new(&e) >= 0);
-
-        assert_se(sd_icmp6_nd_new(&nd) >= 0);
-        assert_se(nd);
-
-        assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
-
-        assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
-        assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
-        assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
-
-        assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
-                                 time_now + 2 *USEC_PER_SEC, 0,
-                                 test_rs_hangcheck, NULL) >= 0);
-
-        assert_se(sd_icmp6_nd_stop(nd) >= 0);
-        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-        assert_se(sd_icmp6_nd_stop(nd) >= 0);
-
-        assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-
-        sd_event_loop(e);
-
-        test_hangcheck = sd_event_source_unref(test_hangcheck);
-
-        nd = sd_icmp6_nd_unref(nd);
-        assert_se(!nd);
-
-        close(test_fd[1]);
-
-        sd_event_unref(e);
-}
-
-int main(int argc, char *argv[]) {
-
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
-
-        test_rs();
-        test_prefixes();
-
-        return 0;
-}
index dd2e44e7a3d4e0bff26dd939681eb89c5a470fbc..913a929069980f833c0beeda3b70aa590132dca3 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
+#include <net/if.h>
+#include <stdlib.h>
 #include <unistd.h>
-
 #include <linux/veth.h>
-#include <net/if.h>
 
 #include "sd-event.h"
-#include "sd-netlink.h"
 #include "sd-ipv4ll.h"
+#include "sd-netlink.h"
 
-#include "util.h"
+#include "alloc-util.h"
 #include "event-util.h"
-#include "netlink-util.h"
 #include "in-addr-util.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
 
 static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
         _cleanup_free_ char *address = NULL;
index e72204d9927af0082525affb137fc68660e515e2..6f416c51e4359d06fa228b8f7f80ca3caecda223 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
-#include <sys/types.h>
+#include <stdlib.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "socket-util.h"
-#include "event-util.h"
-
 #include "sd-ipv4ll.h"
+
 #include "arp-util.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "socket-util.h"
+#include "util.h"
 
 static bool verbose = false;
 static bool extended = false;
@@ -100,6 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad
 }
 
 static void test_public_api_setters(sd_event *e) {
+        struct in_addr address = {};
         unsigned seed = 0;
         sd_ipv4ll *ll;
         struct ether_addr mac_addr = {
@@ -118,6 +120,16 @@ static void test_public_api_setters(sd_event *e) {
         assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
         assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
 
+        assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+        address.s_addr |= htobe32(169U << 24 | 254U << 16);
+        assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+        address.s_addr |= htobe32(0x00FF);
+        assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+        address.s_addr |= htobe32(0xF000);
+        assert_se(sd_ipv4ll_set_address(ll, &address) == 0);
+        address.s_addr |= htobe32(0x0F00);
+        assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+
         assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL);
         assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);
 
index e57102a57601a336d93f6e65fea545259cbec7be..99545d0b8bfd70d7e060eff3bd5e572eb62171e2 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <arpa/inet.h>
+#include <net/ethernet.h>
 #include <stdio.h>
 #include <string.h>
-#include <net/ethernet.h>
-#include <arpa/inet.h>
 
-#include "sd-lldp.h"
 #include "sd-event.h"
+#include "sd-lldp.h"
+
+#include "alloc-util.h"
 #include "event-util.h"
-#include "macro.h"
-#include "lldp.h"
-#include "lldp-tlv.h"
+#include "fd-util.h"
 #include "lldp-network.h"
+#include "lldp-tlv.h"
+#include "lldp.h"
+#include "macro.h"
+#include "string-util.h"
 
 #define TEST_LLDP_PORT "em1"
 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
@@ -50,7 +54,7 @@ static int lldp_build_tlv_packet(tlv_packet **ret) {
                 .ether_type = htons(ETHERTYPE_LLDP),
         };
 
-        /* Append ethernet header */
+        /* Append Ethernet header */
         memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
         memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
 
diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c
new file mode 100644 (file)
index 0000000..a485be7
--- /dev/null
@@ -0,0 +1,170 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  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 <netinet/icmp6.h>
+
+#include "sd-ndisc.h"
+
+#include "icmp6-util.h"
+#include "socket-util.h"
+
+static struct ether_addr mac_addr = {
+        .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
+};
+
+static bool verbose = false;
+static sd_event_source *test_hangcheck;
+static int test_fd[2];
+
+typedef int (*send_ra_t)(uint8_t flags);
+static send_ra_t send_ra_function;
+
+static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
+                             void *userdata) {
+        assert_se(false);
+
+        return 0;
+}
+
+int icmp6_bind_router_solicitation(int index) {
+        assert_se(index == 42);
+
+        if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
+                return -errno;
+
+        return test_fd[0];
+}
+
+static int send_ra(uint8_t flags) {
+        uint8_t advertisement[] = {
+                0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+                0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+                0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+                0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+                0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
+                0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
+        };
+
+        advertisement[5] = flags;
+
+        assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+               sizeof(advertisement));
+
+        if (verbose)
+                printf("  sent RA with flag 0x%02x\n", flags);
+
+        return 0;
+}
+
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+        return send_ra_function(0);
+}
+
+static void test_rs_done(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
+        sd_event *e = userdata;
+        static unsigned idx = 0;
+        uint8_t flags_array[] = {
+                0,
+                0,
+                0,
+                ND_RA_FLAG_OTHER,
+                ND_RA_FLAG_MANAGED
+        };
+        uint32_t mtu;
+
+        assert_se(nd);
+
+        assert_se(flags == flags_array[idx]);
+        idx++;
+
+        if (verbose)
+                printf("  got event 0x%02x\n", flags);
+
+        if (idx < ELEMENTSOF(flags_array)) {
+                send_ra(flags_array[idx]);
+                return;
+        }
+
+        assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG);
+
+        sd_event_exit(e, 0);
+}
+
+static void test_rs(void) {
+        sd_event *e;
+        sd_ndisc *nd;
+        usec_t time_now = now(clock_boottime_or_monotonic());
+
+        if (verbose)
+                printf("* %s\n", __FUNCTION__);
+
+        send_ra_function = send_ra;
+
+        assert_se(sd_event_new(&e) >= 0);
+
+        assert_se(sd_ndisc_new(&nd) >= 0);
+        assert_se(nd);
+
+        assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
+
+        assert_se(sd_ndisc_set_index(nd, 42) >= 0);
+        assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
+        assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0);
+
+        assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
+                                 time_now + 2 *USEC_PER_SEC, 0,
+                                 test_rs_hangcheck, NULL) >= 0);
+
+        assert_se(sd_ndisc_stop(nd) >= 0);
+        assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+        assert_se(sd_ndisc_stop(nd) >= 0);
+
+        assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+
+        sd_event_loop(e);
+
+        test_hangcheck = sd_event_source_unref(test_hangcheck);
+
+        nd = sd_ndisc_unref(nd);
+        assert_se(!nd);
+
+        close(test_fd[1]);
+
+        sd_event_unref(e);
+}
+
+int main(int argc, char *argv[]) {
+
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+        log_open();
+
+        test_rs();
+
+        return 0;
+}
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
deleted file mode 100644 (file)
index 6ea460d..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
-
-  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 <errno.h>
-#include <linux/veth.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sched.h>
-
-#include "sd-event.h"
-#include "sd-netlink.h"
-#include "sd-pppoe.h"
-
-#include "event-util.h"
-#include "process-util.h"
-#include "util.h"
-
-static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
-        static int pppoe_state = -1;
-        sd_event *e = userdata;
-
-        assert_se(ppp);
-        assert_se(e);
-
-        switch (event) {
-        case SD_PPPOE_EVENT_RUNNING:
-                assert_se(pppoe_state == -1);
-                log_info("running");
-                break;
-        case SD_PPPOE_EVENT_STOPPED:
-                assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING);
-                log_info("stopped");
-                assert_se(sd_event_exit(e, 0) >= 0);
-                break;
-        default:
-                assert_not_reached("invalid pppoe event");
-        }
-
-        pppoe_state = event;
-}
-
-static int client_run(const char *client_name, sd_event *e) {
-        sd_pppoe *pppoe;
-        int client_ifindex;
-
-        client_ifindex = (int) if_nametoindex(client_name);
-        assert_se(client_ifindex > 0);
-
-        assert_se(sd_pppoe_new(&pppoe) >= 0);
-        assert_se(sd_pppoe_attach_event(pppoe, e, 0) >= 0);
-
-        assert_se(sd_pppoe_set_ifname(pppoe, "pppoe-client") >= 0);
-        assert_se(sd_pppoe_set_ifindex(pppoe, client_ifindex) >= 0);
-        assert_se(sd_pppoe_set_callback(pppoe, pppoe_handler, e) >= 0);
-
-        log_info("starting PPPoE client, it will exit when the server times out and sends PADT");
-
-        assert_se(sd_pppoe_start(pppoe) >= 0);
-
-        assert_se(sd_event_loop(e) >= 0);
-
-        assert_se(!sd_pppoe_unref(pppoe));
-
-        return EXIT_SUCCESS;
-}
-
-static int test_pppoe_server(sd_event *e) {
-        sd_netlink *rtnl;
-        sd_netlink_message *m;
-        pid_t pid;
-        int r, client_ifindex, server_ifindex;
-
-        r = unshare(CLONE_NEWNET);
-        if (r < 0 && errno == EPERM)
-                return EXIT_TEST_SKIP;
-
-        assert_se(r >= 0);
-
-        assert_se(sd_netlink_open(&rtnl) >= 0);
-        assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
-
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
-        assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
-        assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
-        assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
-        assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0);
-        assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
-        assert_se(sd_netlink_message_close_container(m) >= 0);
-        assert_se(sd_netlink_message_close_container(m) >= 0);
-        assert_se(sd_netlink_message_close_container(m) >= 0);
-        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
-        client_ifindex = (int) if_nametoindex("pppoe-client");
-        assert_se(client_ifindex > 0);
-        server_ifindex = (int) if_nametoindex("pppoe-server");
-        assert_se(server_ifindex > 0);
-
-        m = sd_netlink_message_unref(m);
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0);
-        assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
-        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
-        m = sd_netlink_message_unref(m);
-        assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0);
-        assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
-        assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
-        pid = fork();
-        assert_se(pid >= 0);
-        if (pid == 0) {
-                /* let the client send some discover messages before the server is started */
-                sleep(2);
-
-                /* TODO: manage pppoe-server-options */
-                execlp("pppoe-server", "pppoe-server", "-F",
-                       "-I", "pppoe-server",
-                       "-C", "Test-AC",
-                       "-S", "Service-Default",
-                       "-S", "Service-First-Auxiliary",
-                       "-S", "Service-Second-Auxiliary",
-                       NULL);
-                assert_not_reached("failed to execute pppoe-server. not installed?");
-        }
-
-        client_run("pppoe-client", e);
-
-        assert_se(kill(pid, SIGTERM) >= 0);
-        assert_se(wait_for_terminate(pid, NULL) >= 0);
-
-        assert_se(!sd_netlink_message_unref(m));
-        assert_se(!sd_netlink_unref(rtnl));
-
-        return EXIT_SUCCESS;
-}
-
-int main(int argc, char *argv[]) {
-        _cleanup_event_unref_ sd_event *e = NULL;
-
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
-
-        assert_se(sd_event_new(&e) >= 0);
-
-        if (argc == 1) {
-                log_info("running PPPoE client against local server");
-
-                return test_pppoe_server(e);
-        } else if (argc == 2) {
-                log_info("running PPPoE client over '%s'", argv[1]);
-
-                return client_run(argv[1], e);
-        } else {
-                log_error("This program takes one or no arguments.\n"
-                          "\t %s [<ifname>]", program_invocation_short_name);
-                return EXIT_FAILURE;
-        }
-}
index 435ec92d6fab3c7915fbc1eff63501bb5d899d4a..589a90bbfff246bbdf20512944662552dbc8bd72 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "util.h"
-#include "process-util.h"
+#include "bus-container.h"
 #include "bus-internal.h"
 #include "bus-socket.h"
-#include "bus-container.h"
+#include "fd-util.h"
+#include "process-util.h"
+#include "util.h"
 
 int bus_container_connect_socket(sd_bus *b) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
index aeb48bedd13cc3a5603e6a1e2c48661b397a76d1..ddd3a55b6c987b068e892bf170af9215d35a6d74 100644 (file)
 #include <stddef.h>
 #include <errno.h>
 
-#include "strv.h"
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-bloom.h"
+#include "bus-control.h"
 #include "bus-internal.h"
 #include "bus-message.h"
-#include "bus-control.h"
-#include "bus-bloom.h"
 #include "bus-util.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
 
 _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
         int r;
@@ -976,8 +981,12 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
 static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
         _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
         pid_t pid = 0;
+        bool do_label;
         int r;
-        bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
+
+        assert(bus);
+
+        do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
 
         /* Avoid allocating anything if we have no chance of returning useful data */
         if (!bus->ucred_valid && !do_label)
index af5f7da11c0ebada9fb46dd3af097af6a6fa5e0f..0afafc2942de9031a6d9feae62b605f0624b11bc 100644 (file)
@@ -22,8 +22,9 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-signature.h"
-#include "bus-util.h"
 #include "bus-type.h"
+#include "bus-util.h"
+#include "string-util.h"
 
 _public_ int sd_bus_emit_signal(
                 sd_bus *bus,
index 3e8cb0b7d0ded0cb1a5603f92860079a07ec01ac..2922da3763e63d3f7047e8affdbce0ea08b869ea 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <linux/capability.h>
+#include <stdlib.h>
 
-#include "util.h"
-#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "capability.h"
-#include "cgroup-util.h"
-#include "fileio.h"
-#include "audit.h"
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "bus-creds.h"
+#include "bus-label.h"
 #include "bus-message.h"
 #include "bus-util.h"
+#include "capability-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "bus-creds.h"
-#include "bus-label.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
 
 enum {
         CAP_OFFSET_INHERITABLE = 0,
index 8833b9c677aa0de68b80d676b82d613df54658a8..43a7e67a6d542e64bb9eb1c73191bbdac3c9b933 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "capability.h"
-#include "strv.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "bus-dump.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-type.h"
 #include "cap-list.h"
+#include "capability-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "string-util.h"
+#include "strv.h"
 #include "terminal-util.h"
-
-#include "bus-message.h"
-#include "bus-internal.h"
-#include "bus-type.h"
-#include "bus-dump.h"
+#include "util.h"
 
 static char *indent(unsigned level, unsigned flags) {
         char *p;
index 64a5a972aef719637fdf9e527eb094ae3797bdea..239d7245e6eca00df859b4533fdde5bc2352bfc1 100644 (file)
 ***/
 
 #include <errno.h>
-#include <stdlib.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include <string.h>
 #include <stdio.h>
-
-#include "util.h"
-#include "errno-list.h"
+#include <stdlib.h>
+#include <string.h>
 
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "errno-list.h"
+#include "string-util.h"
+#include "util.h"
 #include "bus-error.h"
 
 BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
@@ -565,7 +567,7 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for
 const char *bus_error_message(const sd_bus_error *e, int error) {
 
         if (e) {
-                /* Sometimes the D-Bus server is a little bit too verbose with
+                /* Sometimes, the D-Bus server is a little bit too verbose with
                  * its error messages, so let's override them here */
                 if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
                         return "Access denied";
index fea796cd30483d01c7984a010f9072030fe120d1..d9f9cd1c5e24e14a9a8bdfd400fcbcf14b630612 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "bus-message.h"
+#include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-message.h"
+#include "hexdecoct.h"
+#include "string-util.h"
 
 bool object_path_is_valid(const char *p) {
         const char *q;
index e399701beb10006cc7b1d25061526921474deb0a..5fc0926f06f406046568ac991a3ce5a42406cc1f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
 #include <pthread.h>
-
-#include "hashmap.h"
-#include "prioq.h"
-#include "list.h"
-#include "util.h"
-#include "refcnt.h"
-#include "socket-util.h"
+#include <sys/socket.h>
 
 #include "sd-bus.h"
+
 #include "bus-error.h"
-#include "bus-match.h"
 #include "bus-kernel.h"
+#include "bus-match.h"
+#include "hashmap.h"
 #include "kdbus.h"
+#include "list.h"
+#include "prioq.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
 
 struct reply_callback {
         sd_bus_message_handler_t callback;
index 3149a5639758f213c15057c38afd8c157cb3a4ba..a90536bac9d0086d01c8b640f03fc7bbb9bd0e0f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "bus-introspect.h"
-#include "bus-signature.h"
 #include "bus-internal.h"
+#include "bus-introspect.h"
 #include "bus-protocol.h"
+#include "bus-signature.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "string-util.h"
+#include "util.h"
 
 int introspect_begin(struct introspect *i, bool trusted) {
         assert(i);
index 577a8b44c362835359f66e277820bab5ccce4b1d..6716f6daca8967745fcdc599daf6062ef9ed20bc 100644 (file)
 #include <libgen.h>
 #undef basename
 
-#include "util.h"
-#include "strv.h"
-#include "memfd-util.h"
-#include "capability.h"
-#include "fileio.h"
-#include "formats-util.h"
-
+#include "alloc-util.h"
+#include "bus-bloom.h"
 #include "bus-internal.h"
-#include "bus-message.h"
 #include "bus-kernel.h"
-#include "bus-bloom.h"
-#include "bus-util.h"
 #include "bus-label.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "capability-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "memfd-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
 
@@ -1433,12 +1437,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
         if (!bus || !bus->is_kernel)
                 return -EOPNOTSUPP;
 
-        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
 
         if (bus->n_memfd_cache <= 0) {
                 int r;
 
-                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
 
                 r = memfd_new(bus->description);
                 if (r < 0)
@@ -1460,7 +1464,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
         *allocated = c->allocated;
         fd = c->fd;
 
-        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
 
         return fd;
 }
@@ -1484,10 +1488,10 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si
                 return;
         }
 
-        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+        assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
 
         if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
-                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+                assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
 
                 close_and_munmap(fd, address, mapped);
                 return;
@@ -1507,7 +1511,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si
                 c->allocated = allocated;
         }
 
-        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+        assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
 }
 
 void bus_kernel_flush_memfd(sd_bus *b) {
index 7234e7926ac9e098b4e3ee2e43654cda0a644e7a..55dc7caa53012c2870a0ea852bfa4c36f01ba1d3 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "bus-internal.h"
-#include "bus-message.h"
 #include "bus-match.h"
+#include "bus-message.h"
 #include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hexdecoct.h"
+#include "string-util.h"
 #include "strv.h"
 
 /* Example:
index 53ee0463ca2527801c43ff5c43a512bb689b573b..bc85af3ec09e628c14d054f7478ff10d3b4bdcd5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "hashmap.h"
-
 #include "sd-bus.h"
 
+#include "hashmap.h"
+
 enum bus_match_node_type {
         BUS_MATCH_ROOT,
         BUS_MATCH_VALUE,
index 72e2b9f785cacbd59119aba491556906d26b2863..5c80095bf09b222c5a2d72b0deb2cb0e9db1518b 100644 (file)
 #include <fcntl.h>
 #include <sys/mman.h>
 
-#include "util.h"
-#include "utf8.h"
-#include "strv.h"
-#include "time-util.h"
-#include "memfd-util.h"
-
 #include "sd-bus.h"
-#include "bus-message.h"
+
+#include "alloc-util.h"
+#include "bus-gvariant.h"
 #include "bus-internal.h"
-#include "bus-type.h"
+#include "bus-message.h"
 #include "bus-signature.h"
-#include "bus-gvariant.h"
+#include "bus-type.h"
 #include "bus-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "memfd-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "time-util.h"
+#include "utf8.h"
+#include "util.h"
 
 static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
 
index ff250034618d754fd65646e5ba6f67d4aa187306..4c91dbae09b0083de2f6f3d09385a4b83fe44188 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
 #include <byteswap.h>
+#include <stdbool.h>
 #include <sys/socket.h>
 
-#include "macro.h"
 #include "sd-bus.h"
-#include "time-util.h"
+
 #include "bus-creds.h"
 #include "bus-protocol.h"
+#include "macro.h"
+#include "time-util.h"
 
 struct bus_container {
         char enclosing;
index 728f20447a8405bfd45900cfbde56fe88e8fbfd5..8c472626a869eef9cad306e3df7f5d5241a3fcd9 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "strv.h"
-#include "set.h"
+#include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-introspect.h"
 #include "bus-message.h"
-#include "bus-type.h"
 #include "bus-signature.h"
-#include "bus-introspect.h"
-#include "bus-util.h"
 #include "bus-slot.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
 #include "bus-objects.h"
 
 static int node_vtable_get_userdata(
index b149ea16daa2efc3cf271f71cdc19890d7f3223a..550bad27ba689e36f42efce34056c43181498a2e 100644 (file)
 ***/
 
 #include "sd-bus.h"
+
+#include "alloc-util.h"
 #include "bus-control.h"
 #include "bus-objects.h"
+#include "string-util.h"
 #include "bus-slot.h"
 
 sd_bus_slot *bus_slot_allocate(
index d0b1e3d7dc69873c8e6a727ae9198c903df0e7b1..25873dea1ecd30ad5111000a1e7408e614759fa2 100644 (file)
 ***/
 
 #include <endian.h>
+#include <poll.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <poll.h>
 
+#include "sd-bus.h"
 #include "sd-daemon.h"
-#include "util.h"
-#include "macro.h"
-#include "missing.h"
-#include "utf8.h"
-#include "formats-util.h"
-#include "signal-util.h"
 
-#include "sd-bus.h"
-#include "bus-socket.h"
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-message.h"
+#include "bus-socket.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "missing.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "utf8.h"
+#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
@@ -602,9 +609,11 @@ static void bus_get_peercred(sd_bus *b) {
         b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
 
         /* Get the SELinux context of the peer */
-        r = getpeersec(b->input_fd, &b->label);
-        if (r < 0 && r != -EOPNOTSUPP)
-                log_debug_errno(r, "Failed to determine peer security context: %m");
+        if (mac_selinux_use()) {
+                r = getpeersec(b->input_fd, &b->label);
+                if (r < 0 && r != -EOPNOTSUPP)
+                        log_debug_errno(r, "Failed to determine peer security context: %m");
+        }
 }
 
 static int bus_socket_start_auth_client(sd_bus *b) {
index e43891be258477a686b397855e741d979e2e613e..fd7e58fcfacb0b15bb58a36ad5d1fbec28cbdbd5 100644 (file)
 ***/
 
 #include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-track.h"
+#include "bus-util.h"
 
 struct sd_bus_track {
         unsigned n_ref;
index 581574ab73183b98344814d9cbcbe5f05ddb7bd4..ad89e6c91171067b2bbc249d5348a532e4e2201d 100644 (file)
 
 #include <stdbool.h>
 
-#include "macro.h"
 #include "sd-bus.h"
 
+#include "macro.h"
+
 bool bus_type_is_valid(char c) _const_;
 bool bus_type_is_valid_in_signature(char c) _const_;
 bool bus_type_is_basic(char c) _const_;
index abe482fc46d52af716024cade4b27a6f91541a7f..71f962b00cd7ecfcce7947cef59f46b48eb0ff27 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "xml.h"
-#include "sd-bus-vtable.h"
+#include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "busctl-introspect.h"
+#include "string-util.h"
+#include "util.h"
+#include "xml.h"
 
 #define NODE_DEPTH_MAX 16
 
index 49c97af33909a869051e7f86ca7eda3a62b2b2f3..452ac7c407ece57bac3f3e6f622bd708e11c307f 100644 (file)
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-dump.h"
 #include "bus-internal.h"
 #include "bus-signature.h"
 #include "bus-type.h"
 #include "bus-util.h"
 #include "busctl-introspect.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "locale-util.h"
 #include "log.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "user-util.h"
 #include "util.h"
 
 static bool arg_no_pager = false;
index a23f7257fa744e50b56223ebbdab16416e827005..a8d79b01b0428eb58ba88ae3dd0d88f216692379 100644 (file)
 #include <sys/mman.h>
 #include <pthread.h>
 
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "missing.h"
-#include "def.h"
-#include "cgroup-util.h"
-#include "hostname-util.h"
-#include "bus-label.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-container.h"
+#include "bus-control.h"
 #include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-type.h"
-#include "bus-socket.h"
 #include "bus-kernel.h"
-#include "bus-control.h"
+#include "bus-label.h"
+#include "bus-message.h"
 #include "bus-objects.h"
-#include "bus-util.h"
-#include "bus-container.h"
 #include "bus-protocol.h"
-#include "bus-track.h"
 #include "bus-slot.h"
+#include "bus-socket.h"
+#include "bus-track.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 #define log_debug_bus_message(m)                                         \
         do {                                                             \
index d14110aa04e9951d3599bfeda1d145828b4245ea..96a0929a14ca7494a0bffbffc74de6f46ac649cc 100644 (file)
 
 #include <sys/wait.h>
 
-#include "def.h"
-#include "util.h"
-#include "time-util.h"
-
 #include "sd-bus.h"
-#include "bus-kernel.h"
+
+#include "alloc-util.h"
 #include "bus-internal.h"
+#include "bus-kernel.h"
 #include "bus-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "time-util.h"
+#include "util.h"
 
 #define MAX_SIZE (2*1024*1024)
 
index 20f1b532b71c3e342c8f58806f57dcb6933f5f78..767aef63ffe0755c81caa70f2fe459d8847e399a 100644 (file)
 #include <unistd.h>
 #include <fcntl.h>
 
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "formats-util.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "bus-match.h"
 #include "bus-internal.h"
+#include "bus-match.h"
 #include "bus-util.h"
+#include "formats-util.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "fd-util.h"
 
 static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
index f58688059304e821be5be2495317eeaf9814eb9f..51aa0a9ad0e8a21a5d2660f13f78e05112b89a4b 100644 (file)
 #include <stdio.h>
 
 #include "sd-bus.h"
-#include "bus-util.h"
+
 #include "bus-internal.h"
 #include "bus-message.h"
+#include "bus-util.h"
 #include "refcnt.h"
 
 static void test_bus_new(void) {
index b078bdc5f6809c26fa82ab2166b549608a524264..931c001788d3e0ecf4e641c062a15709205b1591 100644 (file)
 #include <glib.h>
 #endif
 
-#include "util.h"
-#include "macro.h"
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
 #include "bus-gvariant.h"
-#include "bus-util.h"
 #include "bus-internal.h"
 #include "bus-message.h"
-#include "bus-dump.h"
+#include "bus-util.h"
+#include "macro.h"
+#include "util.h"
 
 static void test_bus_gvariant_is_fixed_size(void) {
         assert_se(bus_gvariant_is_fixed_size("") > 0);
index f3d1099dd2d9a011815c090a1643af1e4132899f..dbdaa69fbe782e63923bbb8633d5a40056cad5ab 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "log.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
 #include "bus-kernel.h"
 #include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "util.h"
 
 static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         int *found = userdata;
index 6506eaab2e52e414e15735c8c21aad3de08dc465..0080f71d3bf34519e2526a6617047debc0d6a6f0 100644 (file)
 
 #include <fcntl.h>
 
-#include "util.h"
-#include "log.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
 #include "bus-kernel.h"
 #include "bus-util.h"
-#include "bus-dump.h"
+#include "fd-util.h"
+#include "log.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int bus_ref = -1;
index ff6bba5988dec355c3ae8cd3215a5fb32f543226..0747d6a37cb1a4fdedfd5a2bbe5650f93e00da78 100644 (file)
 #include <dbus/dbus.h>
 #endif
 
-#include "log.h"
-#include "util.h"
-
 #include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-dump.h"
 #include "bus-label.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "hexdecoct.h"
+#include "util.h"
 
 static void test_bus_path_encode_unique(void) {
         _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL;
index 0a35b750b39620bfc2eed5fa2d8f07a1dd8be70d..5bc72e2355d6269cf418d952801f0de2173b32ad 100644 (file)
 #include <stdlib.h>
 #include <pthread.h>
 
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "bus-dump.h"
+#include "log.h"
+#include "macro.h"
+#include "strv.h"
+#include "util.h"
 
 struct context {
         int fds[2];
index aef768dc185fe9c05daca89be13670ce0d2e625e..428e18576946ed85e04e12da323f33d030e80ce8 100644 (file)
 #include <fcntl.h>
 #include <stdlib.h>
 
-#include "util.h"
-#include "log.h"
-
 #include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
 #include "bus-kernel.h"
 #include "bus-util.h"
-#include "bus-dump.h"
+#include "log.h"
+#include "util.h"
 
 typedef struct {
         const char *sender;
index 080d8eddb76ddc2fa4c939c13050cf6a5a3eefa7..5bf2c1ecf85354700fa4a58a99d713670f9d2594 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <pthread.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
+#include <stdlib.h>
 
 #include "sd-bus.h"
+
 #include "bus-internal.h"
 #include "bus-util.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
 
 struct context {
         int fds[2];
index 17c6188ca01cee5e565ed22ac3f09fca379f3774..92a810a7d8d52d0f33fc2301b712a3c493629dfb 100644 (file)
@@ -19,7 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
+#include "string-util.h"
 #include "log.h"
 #include "bus-signature.h"
 #include "bus-internal.h"
index 2d062fc9b5009eb61ee96360ea8be68ecf059c1a..ff8df61a9e6cb2c98fd64ec5181414903a713a22 100644 (file)
 
 #include <sys/mman.h>
 
-#include "util.h"
-#include "log.h"
-#include "memfd-util.h"
-
 #include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-kernel.h"
+
+#include "alloc-util.h"
 #include "bus-dump.h"
+#include "bus-kernel.h"
+#include "bus-message.h"
+#include "log.h"
+#include "memfd-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "fd-util.h"
 
 #define FIRST_ARRAY 17
 #define SECOND_ARRAY 33
index 582fb535290a126813eb2dd38fc5c153de3d5685..f1e9b7ed1b21ad450f745a73038e4d9544cb467d 100644 (file)
 #include <sys/un.h>
 #include <unistd.h>
 
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "socket-util.h"
 #include "strv.h"
 #include "util.h"
 
-#include "sd-daemon.h"
+#define SNDBUF_SIZE (8*1024*1024)
 
 static void unsetenv_all(bool unset_environment) {
 
@@ -52,8 +58,7 @@ static void unsetenv_all(bool unset_environment) {
 
 _public_ int sd_listen_fds(int unset_environment) {
         const char *e;
-        unsigned n;
-        int r, fd;
+        int n, r, fd;
         pid_t pid;
 
         e = getenv("LISTEN_PID");
@@ -78,17 +83,23 @@ _public_ int sd_listen_fds(int unset_environment) {
                 goto finish;
         }
 
-        r = safe_atou(e, &n);
+        r = safe_atoi(e, &n);
         if (r < 0)
                 goto finish;
 
-        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
+        assert_cc(SD_LISTEN_FDS_START < INT_MAX);
+        if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
+                r = -EINVAL;
+                goto finish;
+        }
+
+        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
                 r = fd_cloexec(fd, true);
                 if (r < 0)
                         goto finish;
         }
 
-        r = (int) n;
+        r = n;
 
 finish:
         unsetenv_all(unset_environment);
@@ -430,12 +441,19 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
                 goto finish;
         }
 
+        if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
+                r = -EINVAL;
+                goto finish;
+        }
+
         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
         if (fd < 0) {
                 r = -errno;
                 goto finish;
         }
 
+        fd_inc_sndbuf(fd, SNDBUF_SIZE);
+
         iovec.iov_len = strlen(state);
 
         strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
@@ -454,7 +472,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
                         (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
                         (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
 
-                msghdr.msg_control = alloca(msghdr.msg_controllen);
+                msghdr.msg_control = alloca0(msghdr.msg_controllen);
 
                 cmsg = CMSG_FIRSTHDR(&msghdr);
                 if (n_fds > 0) {
@@ -573,7 +591,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
         r = safe_atou64(s, &u);
         if (r < 0)
                 goto finish;
-        if (u <= 0) {
+        if (u <= 0 || u >= USEC_INFINITY) {
                 r = -EINVAL;
                 goto finish;
         }
diff --git a/src/libsystemd/sd-device/Makefile b/src/libsystemd/sd-device/Makefile
new file mode 120000 (symlink)
index 0000000..d0b0e8e
--- /dev/null
@@ -0,0 +1 @@
+../Makefile
\ No newline at end of file
index 45a4d12eb72c4060a09392d06913417856c0fc61..ae3157ee5ee30856c774ac53dd50a9c59a81e9a4 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "prioq.h"
-#include "strv.h"
-#include "set.h"
-
 #include "sd-device.h"
 
-#include "device-util.h"
+#include "alloc-util.h"
 #include "device-enumerator-private.h"
+#include "device-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "prioq.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 #define DEVICE_ENUMERATE_MAX_DEPTH 256
 
index b5215cb9b5001c98d10e880db7bb766a633fb989..a13477e75330afed4150a0ed67ca9d8ae5e82633 100644 (file)
 ***/
 
 #include <ctype.h>
-#include <sys/types.h>
 #include <net/if.h>
-
-#include "util.h"
-#include "macro.h"
-#include "refcnt.h"
-#include "path-util.h"
-#include "strxcpyx.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "set.h"
-#include "strv.h"
-#include "mkdir.h"
+#include <sys/types.h>
 
 #include "sd-device.h"
 
-#include "device-util.h"
+#include "alloc-util.h"
 #include "device-internal.h"
 #include "device-private.h"
+#include "device-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "refcnt.h"
+#include "set.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+#include "user-util.h"
+#include "util.h"
 
 int device_add_property(sd_device *device, const char *key, const char *value) {
         int r;
index 49a7b66a2b1a02e96b3b6e5e69c34330322b2aab..d1f34efc2d6bce605465941610addc6380049e7a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "sd-device.h"
+
 int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
 int device_new_from_strv(sd_device **ret, char **strv);
 
index e46546ed91e17d6338452588f1b33e4b0086d31f..0e4926208784dc9b53bd5460073ecfdf36d4bf2a 100644 (file)
 ***/
 
 #include <ctype.h>
-#include <sys/types.h>
 #include <net/if.h>
+#include <sys/types.h>
 
-#include "util.h"
-#include "macro.h"
-#include "path-util.h"
-#include "strxcpyx.h"
+#include "sd-device.h"
+
+#include "alloc-util.h"
+#include "device-internal.h"
+#include "device-private.h"
+#include "device-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "hashmap.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
 #include "set.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "strv.h"
-
-#include "sd-device.h"
-
-#include "device-util.h"
-#include "device-private.h"
-#include "device-internal.h"
+#include "strxcpyx.h"
+#include "util.h"
 
 int device_new_aux(sd_device **ret) {
         _cleanup_device_unref_ sd_device *device = NULL;
@@ -351,13 +356,10 @@ int device_set_ifindex(sd_device *device, const char *_ifindex) {
         assert(device);
         assert(_ifindex);
 
-        r = safe_atoi(_ifindex, &ifindex);
+        r = parse_ifindex(_ifindex, &ifindex);
         if (r < 0)
                 return r;
 
-        if (ifindex <= 0)
-                return -EINVAL;
-
         r = device_add_property_internal(device, "IFINDEX", _ifindex);
         if (r < 0)
                 return r;
@@ -627,11 +629,9 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
                 struct ifreq ifr = {};
                 int ifindex;
 
-                r = safe_atoi(&id[1], &ifr.ifr_ifindex);
+                r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
                 if (r < 0)
                         return r;
-                else if (ifr.ifr_ifindex <= 0)
-                        return -EINVAL;
 
                 sk = socket(PF_INET, SOCK_DGRAM, 0);
                 if (sk < 0)
index e7cad9be46e35bd8d207b3f4eefd1162afc9a6da..ae020340a590a240606769ee3eca92a0285aa1b6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "sd-event.h"
 
+#include "util.h"
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);
 
index 1a82c4c9401ae5882008bee5cb03a2b121938fff..ee4886700e3cb304d2badb712e73ab7c76edc7cf 100644 (file)
 #include <sys/timerfd.h>
 #include <sys/wait.h>
 
-#include "sd-id128.h"
 #include "sd-daemon.h"
-#include "macro.h"
-#include "prioq.h"
+#include "sd-event.h"
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "hashmap.h"
-#include "util.h"
-#include "time-util.h"
+#include "list.h"
+#include "macro.h"
 #include "missing.h"
+#include "prioq.h"
 #include "set.h"
-#include "list.h"
 #include "signal-util.h"
-
-#include "sd-event.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "util.h"
 
 #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
 
@@ -1123,8 +1126,8 @@ _public_ int sd_event_add_signal(
                 callback = signal_exit_callback;
 
         r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
-        if (r < 0)
-                return -errno;
+        if (r != 0)
+                return -r;
 
         if (!sigismember(&ss, sig))
                 return -EBUSY;
index c092e56b7a7aa54e018e9576bf8deddb5e9b7a3f..c1a3b494836e7dc658a8f96fd35798797b5336b8 100644 (file)
 ***/
 
 #include "sd-event.h"
+
+#include "fd-util.h"
 #include "log.h"
-#include "util.h"
 #include "macro.h"
 #include "signal-util.h"
+#include "util.h"
 
 static int prepare_handler(sd_event_source *s, void *userdata) {
         log_info("preparing %c", PTR_TO_INT(userdata));
index ee020a29428ec9664d9091e9b3836230a660b95f..d366c6fa417944a0228ca4a489a229d057bc84e2 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-
 #include "sd-hwdb.h"
 
+#include "util.h"
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref);
 #define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp)
 
index f0316be659e83de953cb4362590633fb7bc356c9..0e034863d6c667bbf6997b5e4ae4f92df78c70db 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <errno.h>
-#include <string.h>
+#include <fnmatch.h>
 #include <inttypes.h>
+#include <stdio.h>
 #include <stdlib.h>
-#include <fnmatch.h>
+#include <string.h>
 #include <sys/mman.h>
 
 #include "sd-hwdb.h"
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "hashmap.h"
-#include "refcnt.h"
-
-#include "hwdb-util.h"
 #include "hwdb-internal.h"
+#include "hwdb-util.h"
+#include "refcnt.h"
+#include "string-util.h"
 
 struct sd_hwdb {
         RefCount n_ref;
index eb539ad318fdee7c8fa37123d7809c91d62225b0..1e17ea6a063e46e8f57f64477b907080d8964e3c 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "macro.h"
 #include "sd-id128.h"
+
+#include "fd-util.h"
+#include "io-util.h"
+#include "macro.h"
+#include "hexdecoct.h"
 #include "random-util.h"
+#include "util.h"
 
 _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
         unsigned n;
index 265c7c7db2aa378c5b911e6b8cc4aaec98f66438..3f2e459825797b4f2f124e924de63a69b265119e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
-#include <string.h>
 #include <errno.h>
-#include <sys/inotify.h>
 #include <poll.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <unistd.h>
 
-#include "util.h"
+#include "sd-login.h"
+
+#include "alloc-util.h"
 #include "cgroup-util.h"
-#include "macro.h"
-#include "strv.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "login-util.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "hostname-util.h"
-#include "sd-login.h"
+#include "io-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 /* Error codes:
  *
@@ -920,9 +932,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
 
                 *(char*) (mempcpy(buf, word, l)) = 0;
 
-                if (safe_atoi(buf, &ifi) < 0)
-                        continue;
-                if (ifi <= 0)
+                if (parse_ifindex(buf, &ifi) < 0)
                         continue;
 
                 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
index f734ce9eee5d9524e72daf6effd4e75a37fd5c01..b0f94c9522ec379de9fdc287fae6d520683f12dd 100644 (file)
 #include <poll.h>
 #include <string.h>
 
-#include "systemd/sd-login.h"
+#include "sd-login.h"
 
-#include "util.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 static void test_login(void) {
         _cleanup_close_pair_ int pair[2] = { -1, -1 };
index e2f637f7f9c93c58a53a2fc258b6ad62a8213055..a00865b56bd4cdadbf654ac5b985ee92caffddea 100644 (file)
@@ -21,6 +21,8 @@
 ***/
 
 #include "sd-netlink.h"
+
+#include "alloc-util.h"
 #include "netlink-util.h"
 #include "macro.h"
 #include "local-addresses.h"
index 4026e2c341b1333fe3e648e0e30ee6186a8372e0..8519a4d523a848932c728439b4f67b479df6a260 100644 (file)
 
 #include <linux/netlink.h>
 
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
 #include "sd-netlink.h"
 
+#include "list.h"
 #include "netlink-types.h"
+#include "prioq.h"
+#include "refcnt.h"
 
 #define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
 
@@ -64,6 +63,9 @@ struct sd_netlink {
                 struct sockaddr_nl nl;
         } sockaddr;
 
+        Hashmap *broadcast_group_refs;
+        bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
+
         sd_netlink_message **rqueue;
         unsigned rqueue_size;
         size_t rqueue_allocated;
@@ -124,7 +126,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
 
 int socket_open(int family);
 int socket_bind(sd_netlink *nl);
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
 int socket_read_message(sd_netlink *nl);
 
index cf693de5fbf3cb68779df2652fcb5fbe9148d6b5..03971b35963cfe04ae667c4b2aeac33fda7709ec 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
 #include "formats-util.h"
-#include "refcnt.h"
 #include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
 #include "netlink-internal.h"
 #include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
 
 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
index 84ff7c38c925e7b5dca7fb0571cd53d32512dcba..13945202e40a93565209405e68341d7b1a5b04d1 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
 #include "formats-util.h"
-#include "refcnt.h"
 #include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
 #include "netlink-internal.h"
 #include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
 
 int socket_open(int family) {
         int fd;
@@ -44,6 +45,65 @@ int socket_open(int family) {
         return fd;
 }
 
+static int broadcast_groups_get(sd_netlink *nl) {
+        _cleanup_free_ uint32_t *groups = NULL;
+        socklen_t len = 0, old_len;
+        unsigned i, j;
+        int r;
+
+        assert(nl);
+        assert(nl->fd > 0);
+
+        r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
+        if (r < 0) {
+                if (errno == ENOPROTOOPT) {
+                        nl->broadcast_group_dont_leave = true;
+                        return 0;
+                } else
+                        return -errno;
+        }
+
+        if (len == 0)
+                return 0;
+
+        groups = new0(uint32_t, len);
+        if (!groups)
+                return -ENOMEM;
+
+        old_len = len;
+
+        r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
+        if (r < 0)
+                return -errno;
+
+        if (old_len != len)
+                return -EIO;
+
+        r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < len; i++) {
+                for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
+                        uint32_t offset;
+                        unsigned group;
+
+                        offset = 1U << j;
+
+                        if (!(groups[i] & offset))
+                                continue;
+
+                        group = i * sizeof(uint32_t) * 8 + j + 1;
+
+                        r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
 int socket_bind(sd_netlink *nl) {
         socklen_t addrlen;
         int r, one = 1;
@@ -63,11 +123,32 @@ int socket_bind(sd_netlink *nl) {
         if (r < 0)
                 return -errno;
 
+        r = broadcast_groups_get(nl);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
+static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
+        assert(nl);
+
+        return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
+}
 
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
+static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
+        int r;
+
+        assert(nl);
+
+        r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int broadcast_group_join(sd_netlink *nl, unsigned group) {
         int r;
 
         assert(nl);
@@ -81,6 +162,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
         return 0;
 }
 
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
+        unsigned n_ref;
+        int r;
+
+        assert(nl);
+
+        n_ref = broadcast_group_get_ref(nl, group);
+
+        n_ref ++;
+
+        r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+        if (r < 0)
+                return r;
+
+        r = broadcast_group_set_ref(nl, group, n_ref);
+        if (r < 0)
+                return r;
+
+        if (n_ref > 1)
+                /* not yet in the group */
+                return 0;
+
+        r = broadcast_group_join(nl, group);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
+        int r;
+
+        assert(nl);
+        assert(nl->fd >= 0);
+        assert(group > 0);
+
+        if (nl->broadcast_group_dont_leave)
+                return 0;
+
+        r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
+        unsigned n_ref;
+        int r;
+
+        assert(nl);
+
+        n_ref = broadcast_group_get_ref(nl, group);
+
+        assert(n_ref > 0);
+
+        n_ref --;
+
+        r = broadcast_group_set_ref(nl, group, n_ref);
+        if (r < 0)
+                return r;
+
+        if (n_ref > 0)
+                /* still refs left */
+                return 0;
+
+        r = broadcast_group_leave(nl, group);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 /* returns the number of bytes sent, or a negative error code */
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         union {
index 4a5340e659248dac68e85f595aa7c4cccb98f701..135354e5f3478ecac03469fbcd44cab2572be9da 100644 (file)
 #include <linux/if_bridge.h>
 #include <linux/if_addr.h>
 #include <linux/if.h>
-
 #include <linux/ip.h>
 #include <linux/if_link.h>
 #include <linux/if_tunnel.h>
 
 #include "macro.h"
-#include "util.h"
-
-#include "netlink-types.h"
 #include "missing.h"
+#include "netlink-types.h"
+#include "string-table.h"
+#include "util.h"
 
 /* Maximum ARP IP target defined in kernel */
 #define BOND_MAX_ARP_TARGETS    16
@@ -84,20 +83,20 @@ static const NLTypeSystem empty_type_system = {
         .types = empty_types,
 };
 
-static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = {
+static const NLType rtnl_link_info_data_veth_types[] = {
         [VETH_INFO_PEER]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
 };
 
-static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_ipvlan_types[] = {
         [IFLA_IPVLAN_MODE]  = { .type = NETLINK_TYPE_U16 },
 };
 
-static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_macvlan_types[] = {
         [IFLA_MACVLAN_MODE]  = { .type = NETLINK_TYPE_U32 },
         [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
 };
 
-static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = {
+static const NLType rtnl_link_bridge_management_types[] = {
         [IFLA_BRIDGE_FLAGS]     = { .type = NETLINK_TYPE_U16 },
         [IFLA_BRIDGE_MODE]      = { .type = NETLINK_TYPE_U16 },
 /*
@@ -106,7 +105,7 @@ static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = {
 */
 };
 
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = {
+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 },
@@ -115,7 +114,7 @@ static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = {
         [IFLA_BR_PRIORITY]       = { .type = NETLINK_TYPE_U16 },
 };
 
-static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
+static const NLType rtnl_link_info_data_vlan_types[] = {
         [IFLA_VLAN_ID]          = { .type = NETLINK_TYPE_U16 },
 /*
         [IFLA_VLAN_FLAGS]       = { .len = sizeof(struct ifla_vlan_flags) },
@@ -125,7 +124,7 @@ static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
         [IFLA_VLAN_PROTOCOL]    = { .type = NETLINK_TYPE_U16 },
 };
 
-static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
+static const NLType rtnl_link_info_data_vxlan_types[] = {
         [IFLA_VXLAN_ID]                = { .type = NETLINK_TYPE_U32 },
         [IFLA_VXLAN_GROUP]             = { .type = NETLINK_TYPE_IN_ADDR },
         [IFLA_VXLAN_LINK]              = { .type = NETLINK_TYPE_U32 },
@@ -152,7 +151,7 @@ static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = {
         [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG },
 };
 
-static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = {
+static const NLType rtnl_bond_arp_target_types[] = {
         [BOND_ARP_TARGETS_0]        = { .type = NETLINK_TYPE_U32 },
         [BOND_ARP_TARGETS_1]        = { .type = NETLINK_TYPE_U32 },
         [BOND_ARP_TARGETS_2]        = { .type = NETLINK_TYPE_U32 },
@@ -176,7 +175,7 @@ static const NLTypeSystem rtnl_bond_arp_type_system = {
         .types = rtnl_bond_arp_target_types,
 };
 
-static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
+static const NLType rtnl_link_info_data_bond_types[] = {
         [IFLA_BOND_MODE]                = { .type = NETLINK_TYPE_U8 },
         [IFLA_BOND_ACTIVE_SLAVE]        = { .type = NETLINK_TYPE_U32 },
         [IFLA_BOND_MIIMON]              = { .type = NETLINK_TYPE_U32 },
@@ -202,7 +201,7 @@ static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = {
         [IFLA_BOND_AD_INFO]             = { .type = NETLINK_TYPE_NESTED },
 };
 
-static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
+static const NLType rtnl_link_info_data_iptun_types[] = {
         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
@@ -221,7 +220,7 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = {
         [IFLA_IPTUN_ENCAP_DPORT]         = { .type = NETLINK_TYPE_U16 },
 };
 
-static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
+static  const NLType rtnl_link_info_data_ipgre_types[] = {
         [IFLA_GRE_LINK]         = { .type = NETLINK_TYPE_U32 },
         [IFLA_GRE_IFLAGS]       = { .type = NETLINK_TYPE_U16 },
         [IFLA_GRE_OFLAGS]       = { .type = NETLINK_TYPE_U16 },
@@ -240,7 +239,7 @@ static  const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = {
         [IFLA_GRE_ENCAP_DPORT]  = { .type = NETLINK_TYPE_U16 },
 };
 
-static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
+static const NLType rtnl_link_info_data_ipvti_types[] = {
         [IFLA_VTI_LINK]         = { .type = NETLINK_TYPE_U32 },
         [IFLA_VTI_IKEY]         = { .type = NETLINK_TYPE_U32 },
         [IFLA_VTI_OKEY]         = { .type = NETLINK_TYPE_U32 },
@@ -248,7 +247,7 @@ static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = {
         [IFLA_VTI_REMOTE]       = { .type = NETLINK_TYPE_IN_ADDR },
 };
 
-static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
+static const NLType rtnl_link_info_data_ip6tnl_types[] = {
         [IFLA_IPTUN_LINK]                = { .type = NETLINK_TYPE_U32 },
         [IFLA_IPTUN_LOCAL]               = { .type = NETLINK_TYPE_IN_ADDR },
         [IFLA_IPTUN_REMOTE]              = { .type = NETLINK_TYPE_IN_ADDR },
@@ -260,7 +259,7 @@ static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = {
 };
 
 /* these strings must match the .kind entries in the kernel */
-static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = {
+static const char* const nl_union_link_info_data_table[] = {
         [NL_UNION_LINK_INFO_DATA_BOND] = "bond",
         [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge",
         [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan",
@@ -283,7 +282,7 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_
 
 DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData);
 
-static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = {
+static const NLTypeSystem rtnl_link_info_data_type_systems[] = {
         [NL_UNION_LINK_INFO_DATA_BOND] =        { .count = ELEMENTSOF(rtnl_link_info_data_bond_types),
                                                   .types = rtnl_link_info_data_bond_types },
         [NL_UNION_LINK_INFO_DATA_BRIDGE] =      { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types),
@@ -329,7 +328,7 @@ static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = {
         .match = IFLA_INFO_KIND,
 };
 
-static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = {
+static const NLType rtnl_link_info_types[] = {
         [IFLA_INFO_KIND]        = { .type = NETLINK_TYPE_STRING },
         [IFLA_INFO_DATA]        = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union},
 /*
@@ -344,7 +343,7 @@ static const NLTypeSystem rtnl_link_info_type_system = {
         .types = rtnl_link_info_types,
 };
 
-static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
+static const struct NLType rtnl_prot_info_bridge_port_types[] = {
         [IFLA_BRPORT_STATE]             = { .type = NETLINK_TYPE_U8 },
         [IFLA_BRPORT_COST]              = { .type = NETLINK_TYPE_U32 },
         [IFLA_BRPORT_PRIORITY]          = { .type = NETLINK_TYPE_U16 },
@@ -358,7 +357,7 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1]
         [IFLA_BRPORT_LEARNING_SYNC]     = { .type = NETLINK_TYPE_U8 },
 };
 
-static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = {
+static const NLTypeSystem rtnl_prot_info_type_systems[] = {
         [AF_BRIDGE] =   { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types),
                           .types = rtnl_prot_info_bridge_port_types },
 };
@@ -369,7 +368,7 @@ static const NLTypeSystemUnion rtnl_prot_info_type_system_union = {
         .match_type = NL_MATCH_PROTOCOL,
 };
 
-static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = {
+static const struct NLType rtnl_af_spec_inet6_types[] = {
         [IFLA_INET6_FLAGS]              = { .type = NETLINK_TYPE_U32 },
 /*
         IFLA_INET6_CONF,
@@ -387,7 +386,7 @@ static const NLTypeSystem rtnl_af_spec_inet6_type_system = {
         .types = rtnl_af_spec_inet6_types,
 };
 
-static const NLType rtnl_af_spec_types[AF_MAX + 1] = {
+static const NLType rtnl_af_spec_types[] = {
         [AF_INET6] =    { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system },
 };
 
@@ -396,7 +395,7 @@ static const NLTypeSystem rtnl_af_spec_type_system = {
         .types = rtnl_af_spec_types,
 };
 
-static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
+static const NLType rtnl_link_types[] = {
         [IFLA_ADDRESS]          = { .type = NETLINK_TYPE_ETHER_ADDR },
         [IFLA_BROADCAST]        = { .type = NETLINK_TYPE_ETHER_ADDR },
         [IFLA_IFNAME]           = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
@@ -455,7 +454,7 @@ static const NLTypeSystem rtnl_link_type_system = {
 
 /* IFA_FLAGS was defined in kernel 3.14, but we still support older
  * kernels where IFA_MAX is lower. */
-static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = {
+static const NLType rtnl_address_types[] = {
         [IFA_ADDRESS]           = { .type = NETLINK_TYPE_IN_ADDR },
         [IFA_LOCAL]             = { .type = NETLINK_TYPE_IN_ADDR },
         [IFA_LABEL]             = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
@@ -473,7 +472,7 @@ static const NLTypeSystem rtnl_address_type_system = {
         .types = rtnl_address_types,
 };
 
-static const NLType rtnl_route_types[RTA_MAX + 1] = {
+static const NLType rtnl_route_types[] = {
         [RTA_DST]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
         [RTA_SRC]               = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */
         [RTA_IIF]               = { .type = NETLINK_TYPE_U32 },
@@ -491,7 +490,11 @@ static const NLType rtnl_route_types[RTA_MAX + 1] = {
         RTA_TABLE,
         RTA_MARK,
         RTA_MFC_STATS,
+        RTA_VIA,
+        RTA_NEWDST,
 */
+        [RTA_PREF]              = { .type = NETLINK_TYPE_U8 },
+
 };
 
 static const NLTypeSystem rtnl_route_type_system = {
@@ -499,7 +502,7 @@ static const NLTypeSystem rtnl_route_type_system = {
         .types = rtnl_route_types,
 };
 
-static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
+static const NLType rtnl_neigh_types[] = {
         [NDA_DST]               = { .type = NETLINK_TYPE_IN_ADDR },
         [NDA_LLADDR]            = { .type = NETLINK_TYPE_ETHER_ADDR },
         [NDA_CACHEINFO]         = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) },
@@ -515,7 +518,7 @@ static const NLTypeSystem rtnl_neigh_type_system = {
         .types = rtnl_neigh_types,
 };
 
-static const NLType rtnl_types[RTM_MAX + 1] = {
+static const NLType rtnl_types[] = {
         [NLMSG_DONE]   = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
         [NLMSG_ERROR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
         [RTM_NEWLINK]  = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
index 482ff6b1c2e4303d5eeced85b2fef8bc5913b4b3..6f9fd2993b1bd6a257a2d26200f45fac86665913 100644 (file)
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
 #include "sd-netlink.h"
 
 #include "netlink-util.h"
index 9df0aa28bfbe2d70e354c46e90254c96dc71dd4c..acc6c15ff312e41a679fc6f264ae99de60259e42 100644 (file)
@@ -21,9 +21,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "sd-netlink.h"
 
 #include "util.h"
-#include "sd-netlink.h"
 
 int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
 uint32_t rtnl_message_get_serial(sd_netlink_message *m);
index 2f31f4ee699b2e69f774a2e3bc564b85d37bbd36..3e605db6618dd0a9db57b87c67b475a1683c3f41 100644 (file)
 #include <stdbool.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
 #include "formats-util.h"
-#include "refcnt.h"
 #include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
 #include "netlink-internal.h"
 #include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
 
 int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
         struct rtmsg *rtm;
@@ -84,6 +84,35 @@ int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope)
         return 0;
 }
 
+int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        rtm->rtm_flags = flags;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(flags, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *flags = rtm->rtm_flags;
+
+        return 0;
+}
+
 int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
         struct rtmsg *rtm;
 
@@ -99,6 +128,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
         return 0;
 }
 
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(protocol, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *protocol = rtm->rtm_protocol;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(scope, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *scope = rtm->rtm_scope;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(tos, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *tos = rtm->rtm_tos;
+
+        return 0;
+}
+
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
+        struct rtmsg *rtm;
+
+        assert_return(m, -EINVAL);
+        assert_return(m->hdr, -EINVAL);
+        assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+        assert_return(table, -EINVAL);
+
+        rtm = NLMSG_DATA(m->hdr);
+
+        *table = rtm->rtm_table;
+
+        return 0;
+}
+
 int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
         struct rtmsg *rtm;
 
index d248869c8dab917e01718e836112ee94dc33fe6b..7c24e053cfb5bf1a6718f0d0b9f6cc8ad7f1830a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
 #include <poll.h>
-
-#include "missing.h"
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
+#include <sys/socket.h>
 
 #include "sd-netlink.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "missing.h"
 #include "netlink-internal.h"
 #include "netlink-util.h"
+#include "socket-util.h"
+#include "util.h"
 
 static int sd_netlink_new(sd_netlink **ret) {
         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
@@ -183,10 +186,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
                 sd_event_unref(rtnl->event);
 
                 while ((f = rtnl->match_callbacks)) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
-                        free(f);
+                        sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
                 }
 
+                hashmap_free(rtnl->broadcast_group_refs);
+
                 safe_close(rtnl->fd);
                 free(rtnl);
         }
@@ -856,26 +860,33 @@ int sd_netlink_add_match(sd_netlink *rtnl,
 
         switch (type) {
                 case RTM_NEWLINK:
-                case RTM_SETLINK:
-                case RTM_GETLINK:
                 case RTM_DELLINK:
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
                         if (r < 0)
                                 return r;
 
                         break;
                 case RTM_NEWADDR:
-                case RTM_GETADDR:
                 case RTM_DELADDR:
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
                         if (r < 0)
                                 return r;
 
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
                         if (r < 0)
                                 return r;
 
                         break;
+                case RTM_NEWROUTE:
+                case RTM_DELROUTE:
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
+                        if (r < 0)
+                                return r;
+
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
+                        if (r < 0)
+                                return r;
+                        break;
                 default:
                         return -EOPNOTSUPP;
         }
@@ -892,23 +903,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl,
                          sd_netlink_message_handler_t callback,
                          void *userdata) {
         struct match_callback *c;
+        int r;
 
         assert_return(rtnl, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
 
-        /* we should unsubscribe from the broadcast groups at this point, but it is not so
-           trivial for a few reasons: the refcounting is a bit of a mess and not obvious
-           how it will look like after we add genetlink support, and it is also not possible
-           to query what broadcast groups were subscribed to when we inherit the socket to get
-           the initial refcount. The latter could indeed be done for the first 32 broadcast
-           groups (which incidentally is all we currently support in .socket units anyway),
-           but we better not rely on only ever using 32 groups. */
         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
                         free(c);
 
+                        switch (type) {
+                                case RTM_NEWLINK:
+                                case RTM_DELLINK:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
+                                        if (r < 0)
+                                                return r;
+
+                                        break;
+                                case RTM_NEWADDR:
+                                case RTM_DELADDR:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
+                                        if (r < 0)
+                                                return r;
+
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
+                                        if (r < 0)
+                                                return r;
+
+                                        break;
+                                case RTM_NEWROUTE:
+                                case RTM_DELROUTE:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
+                                        if (r < 0)
+                                                return r;
+
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
+                                        if (r < 0)
+                                                return r;
+                                        break;
+                                default:
+                                        return -EOPNOTSUPP;
+                        }
+
                         return 1;
                 }
 
index 9867eec0653bbc4792eff77335df3b1a97921731..71801759700a91ed49a3d7f84bc89dd97a8f8c6d 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "in-addr-util.h"
 #include "local-addresses.h"
 #include "af-list.h"
index c9cb415ca04265f379a87ebde2bf884070ebcc24..58b774e0e1acf6431d1fd2f535066a5d4cbc7b3d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <netinet/ether.h>
 #include <net/if.h>
+#include <netinet/ether.h>
 
-#include "util.h"
-#include "macro.h"
 #include "sd-netlink.h"
-#include "socket-util.h"
-#include "netlink-util.h"
+
+#include "ether-addr-util.h"
 #include "event-util.h"
+#include "macro.h"
 #include "missing.h"
+#include "netlink-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
 
 static void test_message_link_bridge(sd_netlink *rtnl) {
         _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
index 48958e8a9fccd128121c96583b573457cb023cbc..a2d6c5931470d0446108bfb1fbb9239be2e69a1a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "network-util.h"
+#include "strv.h"
 
 bool network_is_online(void) {
         _cleanup_free_ char *state = NULL;
index 87d87359b857180cc40403952d40eb3e82e1af23..efbceba83d114c18aa3ba7dae0d7f2b988858576 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
-#include <sys/inotify.h>
 #include <poll.h>
+#include <string.h>
+#include <sys/inotify.h>
 
-#include "util.h"
+#include "sd-network.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "macro.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "fileio.h"
-#include "sd-network.h"
+#include "util.h"
 
 _public_ int sd_network_get_operational_state(char **state) {
         _cleanup_free_ char *s = NULL;
index 7363be27949c26c840df2c5dc144bf18c69eb7fe..480f1ad065e3e2d8493f10a1531c641db60abd36 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "sd-path.h"
+
+#include "alloc-util.h"
 #include "architecture.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "missing.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "sd-path.h"
-#include "missing.h"
+#include "user-util.h"
+#include "util.h"
 
 static int from_environment(const char *envname, const char *fallback, const char **ret) {
         assert(ret);
index 019cdaffe149573e699eeb5305c48565836d60f7..51a8a8af83ab837c92b63300296d2efead734adb 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "sd-resolve.h"
 
+#include "util.h"
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref);
 DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve_query*, sd_resolve_query_unref);
 
index 888b372c994841807d351577e4639f2e26387034..34a0b03f92ff0b00b94ed38a14ca33547f164edc 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <signal.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
 #include <errno.h>
+#include <poll.h>
+#include <pthread.h>
 #include <resolv.h>
+#include <signal.h>
 #include <stdint.h>
-#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/prctl.h>
-#include <poll.h>
+#include <unistd.h>
 
-#include "util.h"
+#include "sd-resolve.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "list.h"
-#include "socket-util.h"
 #include "missing.h"
 #include "resolve-util.h"
-#include "sd-resolve.h"
+#include "socket-util.h"
+#include "util.h"
 
 #define WORKERS_MIN 1U
 #define WORKERS_MAX 16U
@@ -580,12 +584,8 @@ static void resolve_free(sd_resolve *resolve) {
         }
 
         /* Now terminate them and wait until they are gone. */
-        for (i = 0; i < resolve->n_valid_workers; i++) {
-                for (;;) {
-                        if (pthread_join(resolve->workers[i], NULL) != EINTR)
-                                break;
-                }
-        }
+        for (i = 0; i < resolve->n_valid_workers; i++)
+                pthread_join(resolve->workers[i], NULL);
 
         /* Close all communication channels */
         for (i = 0; i < _FD_MAX; i++)
index e8056529f54665513565a30c9a5e56723f443570..05544a584c75d22d0d4f5a22fb68569b711e8d17 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
-#include <sys/socket.h>
 #include <arpa/inet.h>
-#include <stdio.h>
+#include <errno.h>
 #include <netinet/in.h>
 #include <resolv.h>
-#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
 
-#include "socket-util.h"
 #include "sd-resolve.h"
-#include "resolve-util.h"
+
+#include "alloc-util.h"
 #include "macro.h"
+#include "resolve-util.h"
+#include "socket-util.h"
+#include "string-util.h"
 
 static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
         const struct addrinfo *i;
index 6f2aa6064c9a19afb5fb4bbabd227bad56d4acf6..381397cc5208905904935a5c316a1e92874ace71 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "sd-utf8.h"
+
 #include "util.h"
 #include "utf8.h"
-#include "sd-utf8.h"
 
 _public_ const char *sd_utf8_is_valid(const char *s) {
         assert_return(s, NULL);
index aa36b8cb1229915a52acd353a13771c850cd4d8a..40d59201cf327b5e29d4df06689d4e2ce85be0ca 100644 (file)
 #pragma once
 
 #include "libudev.h"
-#include "libudev-private.h"
 #include "sd-device.h"
 
+#include "libudev-private.h"
+
 /**
  * udev_device:
  *
index 4b9c053b54e842991331f3e9f24253fc4dfd77e5..2d3e62410c5724a3e2684bf890912c577dbfcbf7 100644 (file)
 ***/
 
 #include "libudev.h"
-#include "libudev-private.h"
-#include "libudev-device-internal.h"
 
 #include "device-private.h"
+#include "libudev-device-internal.h"
+#include "libudev-private.h"
 
 int udev_device_tag_index(struct udev_device *udev_device, struct udev_device *udev_device_old, bool add) {
         sd_device *device_old = NULL;
index 9a8d6821073ca8b04b7d2c1e32e694e7aa010297..814e016800cff82f7a373fe2c5f826b55be6b2b5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
+#include <ctype.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
-#include <ctype.h>
+#include <linux/sockios.h>
 #include <net/if.h>
-#include <sys/stat.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
-#include <linux/sockios.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
+#include "libudev.h"
 #include "sd-device.h"
-#include "device-util.h"
-#include "device-private.h"
 
-#include "libudev.h"
-#include "libudev-private.h"
+#include "alloc-util.h"
+#include "device-private.h"
+#include "device-util.h"
 #include "libudev-device-internal.h"
+#include "libudev-private.h"
+#include "parse-util.h"
 
 /**
  * SECTION:libudev-device
index df088946df119b61cb630398fa3c11a20e1e8eb9..442f9615f2d4310a4eabc5b612d9926e256ebad3 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <errno.h>
-#include <string.h>
 #include <dirent.h>
+#include <errno.h>
 #include <fnmatch.h>
 #include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
 
 #include "libudev.h"
-#include "libudev-device-internal.h"
 #include "sd-device.h"
-#include "device-util.h"
-#include "device-enumerator-private.h"
 
+#include "alloc-util.h"
+#include "device-enumerator-private.h"
+#include "device-util.h"
+#include "libudev-device-internal.h"
 
 /**
  * SECTION:libudev-enumerate
index 98951fb85b907aaeac22c131a9e10e1169241ced..eba698d163e57689f956f5526e0d62de97dab7fb 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "libudev-private.h"
 #include "sd-hwdb.h"
+
+#include "alloc-util.h"
 #include "hwdb-util.h"
+#include "libudev-private.h"
 
 /**
  * SECTION:libudev-hwdb
index 19e9130be0b630ac6445e584a66289c5b50cea3b..da496ed4563aa10c63d021cf9f0f2571e1aba5d6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <stddef.h>
 #include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 
+#include "alloc-util.h"
 #include "libudev-private.h"
 
 /**
index 282aa2b0d9b040baef7642e005d4e0ccfbb58302..f870eba9eb2715a24d0e47986d7d095cc8f3d873 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <errno.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <poll.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
 #include <string.h>
-#include <poll.h>
 #include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/filter.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
 #include "libudev-private.h"
-#include "socket-util.h"
 #include "missing.h"
-#include "formats-util.h"
+#include "mount-util.h"
+#include "socket-util.h"
+#include "string-util.h"
 
 /**
  * SECTION:libudev-monitor
@@ -408,10 +414,8 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
 
         if (err >= 0)
                 monitor_set_nl_address(udev_monitor);
-        else {
-                log_debug_errno(errno, "bind failed: %m");
-                return -errno;
-        }
+        else
+                return log_debug_errno(errno, "bind failed: %m");
 
         /* enable receiving of sender credentials */
         err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
index 1240ea79ccfa247942eb7493866aa70b0eaef7b5..5f504962919582cf926fbb2c6a1c8af899a11314 100644 (file)
 #include <stdbool.h>
 
 #include "libudev.h"
+
 #include "macro.h"
-#include "util.h"
 #include "mkdir.h"
 #include "strxcpyx.h"
+#include "util.h"
 
 #define READ_END  0
 #define WRITE_END 1
@@ -135,8 +136,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor
 #define UTIL_NAME_SIZE                       512
 #define UTIL_LINE_SIZE                     16384
 #define UDEV_ALLOWED_CHARS_INPUT        "/ $%?,"
-ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size);
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
 int util_log_priority(const char *priority);
 size_t util_path_encode(const char *src, char *dest, size_t size);
 void util_remove_trailing_chars(char *path, char c);
index 11e15d13e62806014c494e97dfb57b5055c3bd3d..58410b1b8fea79f5873cf26ae96bcf47890b4cc1 100644 (file)
@@ -24,6 +24,9 @@
 #include <errno.h>
 #include <sys/inotify.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "libudev-private.h"
 
 /**
index f4656277c61029bead2797fb1e942131d347f50b..574cfeac85684dd9bdafb12f6fd8b861b81434b6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
+#include <ctype.h>
 #include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
+#include <unistd.h>
 
-#include "device-nodes.h"
 #include "libudev.h"
+
+#include "MurmurHash2.h"
+#include "device-nodes.h"
 #include "libudev-private.h"
+#include "syslog-util.h"
 #include "utf8.h"
-#include "MurmurHash2.h"
 
 /**
  * SECTION:libudev-util
@@ -100,52 +102,6 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
         return 0;
 }
 
-ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
-{
-        char path[UTIL_PATH_SIZE];
-        char target[UTIL_PATH_SIZE];
-        ssize_t len;
-        const char *pos;
-
-        strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
-        len = readlink(path, target, sizeof(target));
-        if (len <= 0 || len == (ssize_t)sizeof(target))
-                return -1;
-        target[len] = '\0';
-        pos = strrchr(target, '/');
-        if (pos == NULL)
-                return -1;
-        pos = &pos[1];
-        return strscpy(value, size, pos);
-}
-
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
-{
-        char link_target[UTIL_PATH_SIZE];
-
-        ssize_t len;
-        int i;
-        int back;
-        char *base = NULL;
-
-        len = readlink(syspath, link_target, sizeof(link_target));
-        if (len <= 0 || len == (ssize_t)sizeof(link_target))
-                return -1;
-        link_target[len] = '\0';
-
-        for (back = 0; startswith(&link_target[back * 3], "../"); back++)
-                ;
-        for (i = 0; i <= back; i++) {
-                base = strrchr(syspath, '/');
-                if (base == NULL)
-                        return -EINVAL;
-                base[0] = '\0';
-        }
-
-        strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
-        return 0;
-}
-
 int util_log_priority(const char *priority)
 {
         char *endptr;
index ec15d2576b71e27a67ffb508f85a485e22dc631d..63fb05547dee4e1c59ce30749ea7574968fb2fd8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
 #include <string.h>
-#include <ctype.h>
 
 #include "libudev.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "libudev-private.h"
 #include "missing.h"
+#include "string-util.h"
 
 /**
  * SECTION:libudev
index 880a1794aa42e5b1d05a7a908174845d758abcfb..4a339dcfd44bd95088f714fef8f4452a54431421 100644 (file)
@@ -32,6 +32,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "locale-util.h"
 #include "pager.h"
index e3eef4a610492b4bf8104ff8fd92ae27f0892fa2..720cbbaaba0121b6be453cdf8edd644bad6e4baf 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_XKBCOMMON
+#include <xkbcommon/xkbcommon.h>
+#endif
+
 #include "sd-bus.h"
 
-#include "util.h"
-#include "mkdir.h"
-#include "strv.h"
-#include "def.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "fileio-label.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-message.h"
+#include "bus-util.h"
+#include "def.h"
+#include "env-util.h"
 #include "event-util.h"
+#include "fd-util.h"
+#include "fileio-label.h"
+#include "fileio.h"
 #include "locale-util.h"
+#include "mkdir.h"
+#include "path-util.h"
 #include "selinux-util.h"
-
-#ifdef HAVE_XKBCOMMON
-#include <xkbcommon/xkbcommon.h>
-#endif
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 enum {
         /* We don't list LC_ALL here on purpose. People should be
index e671341b42055622603674da7bdb8c2163e6ed13..70fef332f7e4de99ab0d355b652661037b55a592 100644 (file)
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
 #include "process-util.h"
 #include "signal-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
 
 static const char* arg_what = "idle:sleep:shutdown";
index bfc8716009a0f55eba5df4369a38203ee9984d51..aff68a49fe976655a84344b47b61ac365f0fa3e0 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
@@ -35,6 +36,7 @@
 #include "logs-show.h"
 #include "macro.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "process-util.h"
 #include "signal-util.h"
 #include "spawn-polkit-agent.h"
@@ -42,6 +44,7 @@
 #include "sysfs-show.h"
 #include "terminal-util.h"
 #include "unit-name.h"
+#include "user-util.h"
 #include "util.h"
 #include "verbs.h"
 
index 466225d69c7e84ee2a10300cabaef99f2b04dffe..d0dd569a03cf96490a8639f968b983d2cb923f65 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "util.h"
-#include "formats-util.h"
 #include "acl-util.h"
-#include "set.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "formats-util.h"
 #include "logind-acl.h"
+#include "set.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "util.h"
 
 static int flush_acl(acl_t acl) {
         acl_entry_t i;
index ec09843a787fc20818a7284e61f01093ec022e49..93e9ed02eb6db461c5168059bbe3af6eab39482c 100644 (file)
@@ -23,7 +23,8 @@
 
 #include <sys/types.h>
 #include <stdbool.h>
-#include <libudev.h>
+
+#include "libudev.h"
 
 #ifdef HAVE_ACL
 
index a44e369149f51875be6862c34a81454e4b487823..185108f8f1d34972cf3d6da0f5cf87f96d3e2b64 100644 (file)
 
 #include <unistd.h>
 
-#include "conf-parser.h"
-#include "special.h"
-#include "sleep-config.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "logind-action.h"
+#include "bus-util.h"
+#include "conf-parser.h"
 #include "formats-util.h"
+#include "logind-action.h"
 #include "process-util.h"
+#include "sleep-config.h"
+#include "special.h"
+#include "string-table.h"
 #include "terminal-util.h"
+#include "user-util.h"
 
 int manager_handle_action(
                 Manager *m,
index ff98065371c5c996caf199eb19d67ade4cb72561..e9b424b5f64b949bb93bea032af863b8c76e02c7 100644 (file)
@@ -36,6 +36,7 @@ typedef enum HandleAction {
 } HandleAction;
 
 #include "logind.h"
+#include "logind-inhibit.h"
 
 int manager_handle_action(
                 Manager *m,
index f40e35a8cbbf60ffec2eb369fd7f3b24ddca6e7b..b08b69dbfc39c0350b4db9e3a94eb0c05ed18ded 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 #include <linux/input.h>
 
 #include "sd-messages.h"
-#include "util.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "logind-button.h"
+#include "string-util.h"
+#include "util.h"
 
 Button* button_new(Manager *m, const char *name) {
         Button *b;
index 6c05c11dbd0fee4dedc48a1d57d276a7dfa6a3e1..b3f30c8dc9369b61a820e06bfed7606a5d789989 100644 (file)
 #include <pwd.h>
 #include <linux/vt.h>
 
-#include "strv.h"
-#include "cgroup-util.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "udev-util.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
 #include "logind.h"
+#include "strv.h"
 #include "terminal-util.h"
+#include "udev-util.h"
+#include "user-util.h"
 
 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
         Device *d;
index 40d587ddb8123baf4ad2e77cc387a5c1e62e7124..7890d68aa0f6227c6c0cdfd6e04c68a6e16772d7 100644 (file)
 ***/
 
 #include <errno.h>
+#include <pwd.h>
 #include <string.h>
 #include <unistd.h>
-#include <pwd.h>
 
 #include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "special.h"
-#include "sleep-config.h"
-#include "fileio-label.h"
-#include "unit-name.h"
-#include "audit.h"
-#include "bus-util.h"
-#include "bus-error.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
 #include "bus-common-errors.h"
-#include "udev-util.h"
-#include "selinux-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "dirent-util.h"
 #include "efivars.h"
-#include "logind.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio-label.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "logind.h"
+#include "mkdir.h"
+#include "path-util.h"
 #include "process-util.h"
+#include "selinux-util.h"
+#include "sleep-config.h"
+#include "special.h"
+#include "strv.h"
 #include "terminal-util.h"
+#include "udev-util.h"
+#include "unit-name.h"
+#include "user-util.h"
 #include "utmp-wtmp.h"
 
 int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
@@ -2024,7 +2031,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
                 }
 
                 utmp_wall("The system shutdown has been cancelled",
-                          lookup_uid(uid), tty, logind_wall_tty_filter, m);
+                          uid_to_name(uid), tty, logind_wall_tty_filter, m);
         }
 
         return sd_bus_reply_method_return(message, "b", cancelled);
@@ -2588,7 +2595,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
         }
 
         if (m->action_job && streq(m->action_job, path)) {
-                log_info("Operation finished.");
+                log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
 
                 /* Tell people that they now may take a lock again */
                 send_prepare_for(m, m->action_what, false);
index ee4c45fb8dd9125d76d0bc0d366981a67c31f5c4..ffb9162e56c435f7a7add489d410b9e96c94a555 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <string.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "logind-device.h"
+#include "util.h"
 
 Device* device_new(Manager *m, const char *sysfs, bool master) {
         Device *d;
index 0c9c1e5e9795065e1ce4bd552cae76e281579b91..33fbdde557c92ae5d4f6a10b0eae0846c7454c3b 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "mkdir.h"
-#include "logind-inhibit.h"
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "logind-inhibit.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
 
 Inhibitor* inhibitor_new(Manager *m, const char* id) {
         Inhibitor *i;
index 346e1d2cece27f970ee2d537c13a106a66a7f6b1..43b578f364d447b11ecf0a445fa9ac3bb7091e12 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "util.h"
-#include "bus-util.h"
-#include "strv.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-label.h"
-#include "logind.h"
+#include "bus-util.h"
 #include "logind-seat.h"
+#include "logind.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 static int property_get_active_session(
                 sd_bus *bus,
index 8d13a63688180d7b029cab930e272259a4e9e64d..1f4936cebe4f8a77bf11aa53c4c41e83e5905338 100644 (file)
 ***/
 
 #include <errno.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "sd-messages.h"
-#include "logind-seat.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
 #include "logind-acl.h"
-#include "util.h"
+#include "logind-seat.h"
 #include "mkdir.h"
-#include "formats-util.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "util.h"
 
 Seat *seat_new(Manager *m, const char *id) {
         Seat *s;
index e6b4ccd7c6e46150a3fe0e2a432d748c25292822..7810199a542e566b12dcd63339953e1ea23c1019 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-label.h"
-
-#include "logind.h"
-#include "logind-session.h"
+#include "bus-util.h"
+#include "fd-util.h"
 #include "logind-session-device.h"
+#include "logind-session.h"
+#include "logind.h"
+#include "strv.h"
+#include "util.h"
 
 static int property_get_user(
                 sd_bus *bus,
index 656f268dba4eae34440005ec6a870359e7fb2608..9bf3ca0995530eca91c25aedcf911416f31fe8a1 100644 (file)
 ***/
 
 #include <fcntl.h>
-#include <libudev.h>
 #include <linux/input.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/types.h>
 
-#include "util.h"
-#include "missing.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
 #include "bus-util.h"
+#include "fd-util.h"
 #include "logind-session-device.h"
+#include "missing.h"
+#include "util.h"
 
 enum SessionDeviceNotifications {
         SESSION_DEVICE_RESUME,
index f5fe030b07f2333e8f6b7a1c5676ae523d0f81cf..1d561a6f8a73c06b1f0d60816a6564c0538d0485 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <linux/vt.h>
 #include <linux/kd.h>
+#include <linux/vt.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
 
 #include "sd-messages.h"
-#include "util.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "fileio.h"
-#include "audit.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
 #include "bus-error.h"
-#include "logind-session.h"
+#include "bus-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "io-util.h"
+#include "logind-session.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-table.h"
 #include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
 
 #define RELEASE_USEC (20*USEC_PER_SEC)
 
@@ -987,7 +996,7 @@ static int session_open_vt(Session *s) {
         sprintf(path, "/dev/tty%u", s->vtnr);
         s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
         if (s->vtfd < 0)
-                return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
+                return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
 
         return s->vtfd;
 }
@@ -1049,9 +1058,13 @@ error:
 }
 
 void session_restore_vt(Session *s) {
+
+        static const struct vt_mode mode = {
+                .mode = VT_AUTO,
+        };
+
         _cleanup_free_ char *utf8 = NULL;
-        int vt, kb = K_XLATE;
-        struct vt_mode mode = { 0 };
+        int vt, kb, old_fd;
 
         /* We need to get a fresh handle to the virtual terminal,
          * since the old file-descriptor is potentially in a hung-up
@@ -1059,7 +1072,7 @@ void session_restore_vt(Session *s) {
          * little dance to avoid having the terminal be available
          * for reuse before we've cleaned it up.
          */
-        int old_fd = s->vtfd;
+        old_fd = s->vtfd;
         s->vtfd = -1;
 
         vt = session_open_vt(s);
@@ -1072,13 +1085,13 @@ void session_restore_vt(Session *s) {
 
         if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
                 kb = K_UNICODE;
+        else
+                kb = K_XLATE;
 
         (void) ioctl(vt, KDSKBMODE, kb);
 
-        mode.mode = VT_AUTO;
         (void) ioctl(vt, VT_SETMODE, &mode);
-
-        fchown(vt, 0, -1);
+        (void) fchown(vt, 0, (gid_t) -1);
 
         s->vtfd = safe_close(s->vtfd);
 }
index 20ea2fbdc415882b28461ab7a70db53378b25921..df901f6558101111fb8ed65c02cee4242160f5a1 100644 (file)
 #include <errno.h>
 #include <string.h>
 
-#include "strv.h"
+#include "alloc-util.h"
 #include "bus-util.h"
-#include "logind.h"
-#include "logind-user.h"
 #include "formats-util.h"
+#include "logind-user.h"
+#include "logind.h"
+#include "strv.h"
+#include "user-util.h"
 
 static int property_get_display(
                 sd_bus *bus,
index 451954e860570b6f0eaad83f68ce093046e8bb11..56bc5a010c6710bbdeef7da18a705a7df6902965 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/mount.h>
+#include <errno.h>
 #include <string.h>
+#include <sys/mount.h>
 #include <unistd.h>
-#include <errno.h>
 
-#include "util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "hashmap.h"
-#include "fileio.h"
-#include "path-util.h"
-#include "special.h"
-#include "unit-name.h"
-#include "bus-util.h"
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "conf-parser.h"
+#include "bus-util.h"
 #include "clean-ipc.h"
-#include "smack-util.h"
+#include "conf-parser.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "hashmap.h"
 #include "label.h"
 #include "logind-user.h"
+#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "smack-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
 
 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
         User *u;
index 1e13ff01de75c460aa0e915c0f8b46848d118a0e..3e7a935a34a42d04343bdeab8bb439563e8d98eb 100644 (file)
 #include <pwd.h>
 
 #include "sd-messages.h"
-#include "strv.h"
-#include "special.h"
-#include "unit-name.h"
-#include "audit.h"
-#include "bus-util.h"
-#include "bus-error.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
 #include "bus-common-errors.h"
-#include "logind.h"
+#include "bus-error.h"
+#include "bus-util.h"
 #include "formats-util.h"
+#include "logind.h"
+#include "special.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "user-util.h"
 #include "utmp-wtmp.h"
 
 _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
@@ -94,7 +97,7 @@ static int warn_wall(Manager *m, usec_t n) {
                 return 0;
         }
 
-        utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid),
+        utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
                   m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
 
         return 1;
index 8ac2aceb9b37b540d49a21db09aee093fb465428..be6bbe5b5cdba987d0218f37ba1add4e90e8d5cb 100644 (file)
 ***/
 
 #include <errno.h>
-#include <libudev.h>
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "libudev.h"
 #include "sd-daemon.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "udev-util.h"
+#include "bus-util.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
-#include "signal-util.h"
 #include "logind.h"
+#include "signal-util.h"
+#include "strv.h"
+#include "udev-util.h"
 
 static void manager_free(Manager *m);
 
@@ -292,8 +297,7 @@ static int manager_enumerate_seats(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -329,8 +333,7 @@ static int manager_enumerate_linger_users(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -365,8 +368,7 @@ static int manager_enumerate_users(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /run/systemd/users: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /run/systemd/users: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -406,8 +408,7 @@ static int manager_enumerate_sessions(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -453,8 +454,7 @@ static int manager_enumerate_inhibitors(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
@@ -744,8 +744,7 @@ static int manager_connect_console(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
         }
 
         r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m);
@@ -1103,8 +1102,8 @@ static int manager_run(Manager *m) {
 static int manager_parse_config_file(Manager *m) {
         assert(m);
 
-        return config_parse_many("/etc/systemd/logind.conf",
-                                 CONF_DIRS_NULSTR("systemd/logind.conf"),
+        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);
index 7990da5a93db95255d7856f97e84a6b381630c8f..44e05d8b01a6412bf2f9c20e5f0b5b5608360a5e 100644 (file)
 ***/
 
 #include <stdbool.h>
-#include <libudev.h>
 
-#include "sd-event.h"
+#include "libudev.h"
 #include "sd-bus.h"
-#include "list.h"
+#include "sd-event.h"
+
 #include "hashmap.h"
+#include "list.h"
 #include "set.h"
 
 typedef struct Manager Manager;
 
+#include "logind-action.h"
+#include "logind-button.h"
 #include "logind-device.h"
 #include "logind-inhibit.h"
-#include "logind-button.h"
-#include "logind-action.h"
 
 struct Manager {
         sd_event *event;
index f66f1ce8428bfcfc6ee135dd940e330e4cd62ae1..0d61f528db360cabe368901ce8d46a08b21a23d7 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <endian.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/file.h>
 #include <pwd.h>
-#include <endian.h>
-
-#include <security/pam_modules.h>
 #include <security/_pam_macros.h>
-#include <security/pam_modutil.h>
 #include <security/pam_ext.h>
 #include <security/pam_misc.h>
+#include <security/pam_modules.h>
+#include <security/pam_modutil.h>
+#include <sys/file.h>
 
+#include "alloc-util.h"
+#include "audit-util.h"
 #include "bus-common-errors.h"
-#include "util.h"
-#include "audit.h"
-#include "macro.h"
-#include "strv.h"
+#include "bus-error.h"
 #include "bus-util.h"
 #include "def.h"
-#include "socket-util.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "bus-error.h"
 #include "formats-util.h"
-#include "terminal-util.h"
 #include "hostname-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
 
 static int parse_argv(
                 pam_handle_t *handle,
index f38f06baf9dec578b42dbd298f52e7dd91c23f0d..e9ca4bb03d0d15cdb0c02a14eeeffedd6d1087af 100644 (file)
 
 #include <errno.h>
 #include <string.h>
-#include <libudev.h>
 
-#include "util.h"
-#include "sysfs-show.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
+#include "locale-util.h"
 #include "path-util.h"
-#include "udev-util.h"
+#include "string-util.h"
+#include "sysfs-show.h"
 #include "terminal-util.h"
+#include "udev-util.h"
+#include "util.h"
 
 static int show_sysfs_one(
                 struct udev *udev,
index 03516de916b02bd57afc9673bef0d7e463aa9bdc..d0727ff7c7e760b98eb381b947f30989c203f34f 100644 (file)
 
 #include <unistd.h>
 
-#include "macro.h"
-#include "util.h"
 #include "sd-bus.h"
+
 #include "bus-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "util.h"
 
 static int inhibit(sd_bus *bus, const char *what) {
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
index a9c4e3fadfc226554d259b560bf72b979a6d9f71..f1165ea09ca4739edde7b8a4856c5b3e8e21cdd7 100644 (file)
@@ -27,8 +27,9 @@
 #include "log.h"
 #include "machine-id-setup.h"
 #include "util.h"
+#include "path-util.h"
 
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
 static bool arg_commit = false;
 
 static void help(void) {
@@ -57,7 +58,7 @@ static int parse_argv(int argc, char *argv[]) {
                 {}
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
@@ -74,7 +75,9 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case ARG_COMMIT:
@@ -104,13 +107,14 @@ int main(int argc, char *argv[]) {
 
         r = parse_argv(argc, argv);
         if (r <= 0)
-                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+                goto finish;
 
         if (arg_commit)
                 r = machine_id_commit(arg_root);
         else
                 r = machine_id_setup(arg_root);
 
-
+finish:
+        free(arg_root);
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 2453a9ff04580d442daf9b99c6e07a883412d113..4ec1766033906ba4b6be102ad1bd5cdc7c5ac88c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "bus-label.h"
-#include "strv.h"
 #include "bus-util.h"
-#include "machine-image.h"
 #include "image-dbus.h"
+#include "machine-image.h"
+#include "strv.h"
+#include "user-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
 
index 6e41e929621c74111f369d216e57484c558d1476..452130a29cf362015874d241ccbf4d7ee81d02cf 100644 (file)
 #include <libgen.h>
 #undef basename
 
-#include "bus-util.h"
-#include "bus-label.h"
-#include "strv.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
+#include "bus-internal.h"
+#include "bus-label.h"
+#include "bus-util.h"
 #include "copy.h"
+#include "env-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "formats-util.h"
+#include "fs-util.h"
 #include "in-addr-util.h"
 #include "local-addresses.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "bus-internal.h"
-#include "machine.h"
 #include "machine-dbus.h"
-#include "formats-util.h"
+#include "machine.h"
+#include "mkdir.h"
+#include "path-util.h"
 #include "process-util.h"
-#include "env-util.h"
+#include "strv.h"
 #include "terminal-util.h"
+#include "user-util.h"
 
 static int property_get_id(
                 sd_bus *bus,
index 7ab84607fbc39d236e5c8c81d5a8a9bc5eec5023..196bc4b8f4ff417dc3c4dd89ccb0e9d0df91f7b8 100644 (file)
 
 #include "sd-messages.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
 #include "hashmap.h"
+#include "machine-dbus.h"
+#include "machine.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "special.h"
+#include "string-table.h"
 #include "terminal-util.h"
 #include "unit-name.h"
 #include "util.h"
-#include "machine-dbus.h"
-#include "machine.h"
+#include "extract-word.h"
 
 Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
         Machine *m;
@@ -307,19 +313,26 @@ int machine_load(Machine *m) {
         }
 
         if (netif) {
-                size_t l, allocated = 0, nr = 0;
-                const char *word, *state;
+                size_t allocated = 0, nr = 0;
+                const char *p;
                 int *ni = NULL;
 
-                FOREACH_WORD(word, l, netif, state) {
-                        char buf[l+1];
+                p = netif;
+                for(;;) {
+                        _cleanup_free_ char *word = NULL;
                         int ifi;
 
-                        *(char*) (mempcpy(buf, word, l)) = 0;
+                        r = extract_first_word(&p, &word, NULL, 0);
+                        if (r == 0)
+                                break;
+                        if (r == -ENOMEM)
+                                return log_oom();
+                        if (r < 0) {
+                                log_warning_errno(r, "Failed to parse NETIF: %s", netif);
+                                break;
+                        }
 
-                        if (safe_atoi(buf, &ifi) < 0)
-                                continue;
-                        if (ifi <= 0)
+                        if (parse_ifindex(word, &ifi) < 0)
                                 continue;
 
                         if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
@@ -539,7 +552,7 @@ int machine_kill(Machine *m, KillWho who, int signo) {
                 return 0;
         }
 
-        /* Otherwise make PID 1 do it for us, for the entire cgroup */
+        /* Otherwise, make PID 1 do it for us, for the entire cgroup */
         return manager_kill_unit(m->manager, m->unit, signo, NULL);
 }
 
index 0a21ab4415b7a92ef307af2fba0a8dcf24cf69ce..7e17c7a41c15a7d6fcb6373486784d7e91e4376a 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
@@ -40,6 +41,7 @@
 #include "copy.h"
 #include "env-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "hostname-util.h"
 #include "import-util.h"
 #include "log.h"
@@ -47,6 +49,7 @@
 #include "macro.h"
 #include "mkdir.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "ptyfwd.h"
@@ -57,6 +60,7 @@
 #include "unit-name.h"
 #include "util.h"
 #include "verbs.h"
+#include "web-util.h"
 
 static char **arg_property = NULL;
 static bool arg_all = false;
@@ -1092,9 +1096,10 @@ static int copy_files(int argc, char *argv[], void *userdata) {
         container_path = copy_from ? argv[2] : dest;
 
         if (!path_is_absolute(host_path)) {
-                abs_host_path = path_make_absolute_cwd(host_path);
-                if (!abs_host_path)
-                        return log_oom();
+                r = path_make_absolute_cwd(host_path, &abs_host_path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to make path absolute: %m");
+
                 host_path = abs_host_path;
         }
 
@@ -1110,10 +1115,8 @@ static int copy_files(int argc, char *argv[], void *userdata) {
                         argv[1],
                         copy_from ? container_path : host_path,
                         copy_from ? host_path : container_path);
-        if (r < 0) {
-                log_error("Failed to copy: %s", bus_error_message(&error, -r));
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
 
         return 0;
 }
@@ -2382,7 +2385,7 @@ static int set_limit(int argc, char *argv[], void *userdata) {
         uint64_t limit;
         int r;
 
-        if (streq(argv[argc-1], "-"))
+        if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
                 limit = (uint64_t) -1;
         else {
                 r = parse_size(argv[argc-1], 1024, &limit);
index 41bb106d285163aafa9343e3bc42bde9624fdce1..7827f063c1911b9095b0927cd45d3181a2e75c5d 100644 (file)
 #include <unistd.h>
 
 #include "sd-id128.h"
-#include "strv.h"
-#include "path-util.h"
-#include "unit-name.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "btrfs-util.h"
 #include "bus-common-errors.h"
+#include "bus-util.h"
 #include "cgroup-util.h"
-#include "btrfs-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
-#include "process-util.h"
 #include "hostname-util.h"
+#include "image-dbus.h"
+#include "machine-dbus.h"
 #include "machine-image.h"
 #include "machine-pool.h"
-#include "image-dbus.h"
 #include "machined.h"
-#include "machine-dbus.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "user-util.h"
 
 static int property_get_pool_path(
                 sd_bus *bus,
@@ -79,7 +84,7 @@ static int property_get_pool_usage(
         if (fd >= 0) {
                 BtrfsQuotaInfo q;
 
-                if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+                if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
                         usage = q.referenced;
         }
 
@@ -115,7 +120,7 @@ static int property_get_pool_limit(
         if (fd >= 0) {
                 BtrfsQuotaInfo q;
 
-                if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+                if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
                         size = q.referenced_max;
         }
 
@@ -831,7 +836,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
         if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
                 return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
 
-        r = btrfs_quota_limit("/var/lib/machines", limit);
+        (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
+
+        r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
         if (r == -ENOTTY)
                 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
         if (r < 0)
index df3cc9972a04b910ef537300ec2960b51dbdd106..a099de9f36fd34ea55b84abd2097c9b19e989f08 100644 (file)
 #include <unistd.h>
 
 #include "sd-daemon.h"
-#include "cgroup-util.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-error.h"
-#include "label.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
-#include "signal-util.h"
 #include "hostname-util.h"
+#include "label.h"
 #include "machine-image.h"
 #include "machined.h"
+#include "signal-util.h"
 
 Manager *manager_new(void) {
         Manager *m;
@@ -146,8 +150,7 @@ int manager_enumerate_machines(Manager *m) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
         }
 
         FOREACH_DIRENT(de, d, return -errno) {
index b3e59bf9987c5c3c91b6e7946101ac168d15e93b..dac7a29ed193da0c39d2c7c925d1247341a73339 100644 (file)
 
 #include <stdbool.h>
 
-#include "list.h"
-#include "hashmap.h"
-#include "sd-event.h"
 #include "sd-bus.h"
+#include "sd-event.h"
+
+#include "hashmap.h"
+#include "list.h"
 
 typedef struct Manager Manager;
 
index b0a3add3e7d648d665e04b4d6d08940cc804b19a..a7fdcb09cf4a0c2435d7d0e269f9a78575ba4e19 100644 (file)
 
 #include <errno.h>
 #include <getopt.h>
+#include <libkmod.h>
 #include <limits.h>
 #include <string.h>
 #include <sys/stat.h>
-#include <libkmod.h>
 
 #include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "log.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
 static char **arg_proc_cmdline_modules = NULL;
 
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d");
 
 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
                              const char *fn, const char *format, va_list args) {
@@ -146,8 +151,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
                         if (feof(f))
                                 break;
 
-                        log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
-                        return -errno;
+                        return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
                 }
 
                 l = strstrip(line);
index c78b9444b6a7dba701aedeb04df629f50e76e26f..446b048ef1b0ba7369f10ff488d03b8f7e8194c2 100644 (file)
 #include "sd-netlink.h"
 #include "sd-network.h"
 
+#include "alloc-util.h"
 #include "arphrd-list.h"
 #include "device-util.h"
 #include "ether-addr-util.h"
 #include "hwdb-util.h"
 #include "lldp.h"
 #include "local-addresses.h"
+#include "locale-util.h"
+#include "locale-util.h"
 #include "netlink-util.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "util.h"
@@ -515,7 +521,7 @@ static int link_status_one(
         assert(rtnl);
         assert(name);
 
-        if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
+        if (parse_ifindex(name, &ifindex) >= 0)
                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
         else {
                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
@@ -904,12 +910,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
         _cleanup_free_ LinkInfo *links = NULL;
-        const char *state, *word;
-
         double ttl = -1;
         uint32_t capability;
         int i, r, c, j;
-        size_t ll;
+        const char *p;
         char **s;
 
         pager_open_if_enabled();
@@ -950,14 +954,19 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
                         return -ENOMEM;
 
                 STRV_FOREACH(s, l) {
-                        FOREACH_WORD_QUOTED(word, ll, *s, state) {
-                                _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
 
-                                t = strndup(word, ll);
-                                if (!t)
-                                        return -ENOMEM;
+                        p = *s;
+                        for (;;) {
+                                _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL;
+
+                                r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s);
+
+                                if (r == 0)
+                                        break;
 
-                                r = split_pair(t, "=", &a, &b);
+                                r = split_pair(word, "=", &a, &b);
                                 if (r < 0)
                                         continue;
 
index d609daafde99aa58703d72d27573f5bfc93924cd..889fe1e30d3a724c104624557758be0d4eac645b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "networkd.h"
+#include "alloc-util.h"
 #include "networkd-address-pool.h"
+#include "networkd.h"
+#include "set.h"
+#include "string-util.h"
 
 int address_pool_new(
                 Manager *m,
@@ -96,9 +99,10 @@ static bool address_pool_prefix_is_taken(
 
         HASHMAP_FOREACH(l, p->manager->links, i) {
                 Address *a;
+                Iterator j;
 
                 /* Don't clash with assigned addresses */
-                LIST_FOREACH(addresses, a, l->addresses) {
+                SET_FOREACH(a, l->addresses, j) {
                         if (a->family != p->family)
                                 continue;
 
index 388beb5d4cf405bed4f5178b3d30433f43c071a1..c0562e578865b07496d04fee94766c76d8d43d69 100644 (file)
 
 #include <net/if.h>
 
-#include "utf8.h"
-#include "util.h"
+#include "alloc-util.h"
 #include "conf-parser.h"
 #include "firewall-util.h"
 #include "netlink-util.h"
-
-#include "networkd.h"
 #include "networkd-address.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
 
-static void address_init(Address *address) {
-        assert(address);
+int address_new(Address **ret) {
+        _cleanup_address_free_ Address *address = NULL;
+
+        address = new0(Address, 1);
+        if (!address)
+                return -ENOMEM;
 
         address->family = AF_UNSPEC;
         address->scope = RT_SCOPE_UNIVERSE;
         address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
         address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
+
+        *ret = address;
+        address = NULL;
+
+        return 0;
 }
 
 int address_new_static(Network *network, unsigned section, Address **ret) {
         _cleanup_address_free_ Address *address = NULL;
+        int r;
 
         if (section) {
                 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
@@ -52,11 +65,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
                 }
         }
 
-        address = new0(Address, 1);
-        if (!address)
-                return -ENOMEM;
-
-        address_init(address);
+        r = address_new(&address);
+        if (r < 0)
+                return r;
 
         address->network = network;
 
@@ -74,21 +85,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
         return 0;
 }
 
-int address_new_dynamic(Address **ret) {
-        _cleanup_address_free_ Address *address = NULL;
-
-        address = new0(Address, 1);
-        if (!address)
-                return -ENOMEM;
-
-        address_init(address);
-
-        *ret = address;
-        address = NULL;
-
-        return 0;
-}
-
 void address_free(Address *address) {
         if (!address)
                 return;
@@ -101,10 +97,112 @@ void address_free(Address *address) {
                                        UINT_TO_PTR(address->section));
         }
 
+        if (address->link) {
+                set_remove(address->link->addresses, address);
+                set_remove(address->link->addresses_foreign, address);
+        }
+
         free(address);
 }
 
-int address_establish(Address *address, Link *link) {
+static void address_hash_func(const void *b, struct siphash *state) {
+        const Address *a = b;
+
+        assert(a);
+
+        siphash24_compress(&a->family, sizeof(a->family), state);
+
+        switch (a->family) {
+        case AF_INET:
+                siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
+
+                /* peer prefix */
+                if (a->prefixlen != 0) {
+                        uint32_t prefix;
+
+                        if (a->in_addr_peer.in.s_addr != 0)
+                                prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
+                        else
+                                prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
+
+                        siphash24_compress(&prefix, sizeof(prefix), state);
+                }
+
+                /* fallthrough */
+        case AF_INET6:
+                /* local address */
+                siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+
+                break;
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                break;
+        }
+}
+
+static int address_compare_func(const void *c1, const void *c2) {
+        const Address *a1 = c1, *a2 = c2;
+
+        if (a1->family < a2->family)
+                return -1;
+        if (a1->family > a2->family)
+                return 1;
+
+        switch (a1->family) {
+        /* use the same notion of equality as the kernel does */
+        case AF_INET:
+                if (a1->prefixlen < a2->prefixlen)
+                        return -1;
+                if (a1->prefixlen > a2->prefixlen)
+                        return 1;
+
+                /* compare the peer prefixes */
+                if (a1->prefixlen != 0) {
+                        /* make sure we don't try to shift by 32.
+                         * See ISO/IEC 9899:TC3 § 6.5.7.3. */
+                        uint32_t b1, b2;
+
+                        if (a1->in_addr_peer.in.s_addr != 0)
+                                b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+                        else
+                                b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+                        if (a2->in_addr_peer.in.s_addr != 0)
+                                b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+                        else
+                                b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+                        if (b1 < b2)
+                                return -1;
+                        if (b1 > b2)
+                                return 1;
+                }
+
+                /* fall-through */
+        case AF_INET6:
+                return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                return 0;
+        }
+}
+
+static const struct hash_ops address_hash_ops = {
+        .hash = address_hash_func,
+        .compare = address_compare_func
+};
+
+bool address_equal(Address *a1, Address *a2) {
+        if (a1 == a2)
+                return true;
+
+        if (!a1 || !a2)
+                return false;
+
+        return address_compare_func(a1, a2) == 0;
+}
+
+static int address_establish(Address *address, Link *link) {
         bool masq;
         int r;
 
@@ -112,9 +210,9 @@ int address_establish(Address *address, Link *link) {
         assert(link);
 
         masq = link->network &&
-                link->network->ip_masquerade &&
-                address->family == AF_INET &&
-                address->scope < RT_SCOPE_LINK;
+               link->network->ip_masquerade &&
+               address->family == AF_INET &&
+               address->scope < RT_SCOPE_LINK;
 
         /* Add firewall entry if this is requested */
         if (address->ip_masquerade_done != masq) {
@@ -131,11 +229,88 @@ int address_establish(Address *address, Link *link) {
         return 0;
 }
 
-int address_release(Address *address, Link *link) {
+static int address_add_internal(Link *link, Set **addresses,
+                                int family,
+                                const union in_addr_union *in_addr,
+                                unsigned char prefixlen,
+                                Address **ret) {
+        _cleanup_address_free_ Address *address = NULL;
         int r;
 
-        assert(address);
         assert(link);
+        assert(addresses);
+        assert(in_addr);
+
+        r = address_new(&address);
+        if (r < 0)
+                return r;
+
+        address->family = family;
+        address->in_addr = *in_addr;
+        address->prefixlen = prefixlen;
+        /* Consider address tentative until we get the real flags from the kernel */
+        address->flags = IFA_F_TENTATIVE;
+
+        r = set_ensure_allocated(addresses, &address_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = set_put(*addresses, address);
+        if (r < 0)
+                return r;
+
+        address->link = link;
+
+        if (ret)
+                *ret = address;
+
+        address = NULL;
+
+        return 0;
+}
+
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+        return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
+}
+
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+        Address *address;
+        int r;
+
+        r = address_get(link, family, in_addr, prefixlen, &address);
+        if (r == -ENOENT) {
+                /* Address does not exist, create a new one */
+                r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
+                if (r < 0)
+                        return r;
+        } else if (r == 0) {
+                /* Take over a foreign address */
+                r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = set_put(link->addresses, address);
+                if (r < 0)
+                        return r;
+
+                set_remove(link->addresses_foreign, address);
+        } else if (r == 1) {
+                /* Already exists, do nothing */
+                ;
+        } else
+                return r;
+
+        if (ret)
+                *ret = address;
+
+        return 0;
+}
+
+static int address_release(Address *address) {
+        int r;
+
+        assert(address);
+        assert(address->link);
 
         /* Remove masquerading firewall entry if it was added */
         if (address->ip_masquerade_done) {
@@ -144,7 +319,7 @@ int address_release(Address *address, Link *link) {
 
                 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
                 if (r < 0)
-                        log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");
+                        log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
 
                 address->ip_masquerade_done = false;
         }
@@ -152,81 +327,106 @@ int address_release(Address *address, Link *link) {
         return 0;
 }
 
-int address_drop(Address *address, Link *link,
-                 sd_netlink_message_handler_t callback) {
-        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
+        bool ready;
         int r;
 
         assert(address);
-        assert(address->family == AF_INET || address->family == AF_INET6);
-        assert(link);
-        assert(link->ifindex > 0);
-        assert(link->manager);
-        assert(link->manager->rtnl);
+        assert(cinfo);
 
-        address_release(address, link);
+        ready = address_is_ready(address);
 
-        r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
-                                     link->ifindex, address->family);
-        if (r < 0)
-                return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
+        address->flags = flags;
+        address->scope = scope;
+        address->cinfo = *cinfo;
 
-        r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
-        if (r < 0)
-                return log_error_errno(r, "Could not set prefixlen: %m");
+        if (address->link) {
+                link_update_operstate(address->link);
 
-        if (address->family == AF_INET)
-                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
-        else if (address->family == AF_INET6)
-                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
-        if (r < 0)
-                return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
+                if (!ready && address_is_ready(address)) {
+                        link_check_ready(address->link);
 
-        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
-        if (r < 0)
-                return log_error_errno(r, "Could not send rtnetlink message: %m");
+                        if (address->family == AF_INET6 &&
+                            in_addr_is_link_local(AF_INET6, &address->in_addr) &&
+                            !address->link->ipv6ll_address) {
+                                r = link_ipv6ll_gained(address->link);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        }
 
-        link_ref(link);
+        return 0;
+}
+
+int address_drop(Address *address) {
+        Link *link;
+        bool ready;
+
+        assert(address);
+
+        ready = address_is_ready(address);
+        link = address->link;
+
+        address_release(address);
+        address_free(address);
+
+        link_update_operstate(link);
+
+        if (link && !ready)
+                link_check_ready(link);
 
         return 0;
 }
 
-int address_update(Address *address, Link *link,
-                   sd_netlink_message_handler_t callback) {
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+        Address address = {}, *existing;
+
+        assert(link);
+        assert(in_addr);
+        assert(ret);
+
+        address.family = family;
+        address.in_addr = *in_addr;
+        address.prefixlen = prefixlen;
+
+        existing = set_get(link->addresses, &address);
+        if (existing) {
+                *ret = existing;
+
+                return 1;
+        } else {
+                existing = set_get(link->addresses_foreign, &address);
+                if (!existing)
+                        return -ENOENT;
+        }
+
+        *ret = existing;
+
+        return 0;
+}
+
+int address_remove(Address *address, Link *link,
+                 sd_netlink_message_handler_t callback) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
         assert(address);
         assert(address->family == AF_INET || address->family == AF_INET6);
+        assert(link);
         assert(link->ifindex > 0);
         assert(link->manager);
         assert(link->manager->rtnl);
 
-        r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
+        r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
                                      link->ifindex, address->family);
         if (r < 0)
-                return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
+                return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
 
         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
         if (r < 0)
                 return log_error_errno(r, "Could not set prefixlen: %m");
 
-        address->flags |= IFA_F_PERMANENT;
-
-        r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff);
-        if (r < 0)
-                return log_error_errno(r, "Could not set flags: %m");
-
-        if (address->flags & ~0xff && link->rtnl_extended_attrs) {
-                r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
-                if (r < 0)
-                        return log_error_errno(r, "Could not set extended flags: %m");
-        }
-
-        r = sd_rtnl_message_addr_set_scope(req, address->scope);
-        if (r < 0)
-                return log_error_errno(r, "Could not set scope: %m");
-
         if (address->family == AF_INET)
                 r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
         else if (address->family == AF_INET6)
@@ -234,22 +434,6 @@ int address_update(Address *address, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
 
-        if (address->family == AF_INET) {
-                r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
-                if (r < 0)
-                        return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
-        }
-
-        if (address->label) {
-                r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
-                if (r < 0)
-                        return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
-        }
-
-        r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
-        if (r < 0)
-                return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
-
         r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
         if (r < 0)
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
@@ -292,7 +476,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
         } else if (original->family == AF_INET6)
                 in_addr.in6.s6_addr[15] |= 1;
 
-        r = address_new_dynamic(&na);
+        r = address_new(&na);
         if (r < 0)
                 return r;
 
@@ -318,8 +502,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
         return 0;
 }
 
-int address_configure(Address *address, Link *link,
-                      sd_netlink_message_handler_t callback) {
+int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
 
@@ -334,8 +517,12 @@ int address_configure(Address *address, Link *link,
         if (r < 0)
                 return r;
 
-        r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
-                                     link->ifindex, address->family);
+        if (update)
+                r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
+                                                    link->ifindex, address->family);
+        else
+                r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
+                                             link->ifindex, address->family);
         if (r < 0)
                 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
 
@@ -392,13 +579,23 @@ int address_configure(Address *address, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
 
-        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        r = address_establish(address, link);
         if (r < 0)
+                return r;
+
+        r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+        if (r < 0) {
+                address_release(address);
                 return log_error_errno(r, "Could not send rtnetlink message: %m");
+        }
 
         link_ref(link);
 
-        address_establish(address, link);
+        r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+        if (r < 0) {
+                address_release(address);
+                return log_error_errno(r, "Could not add address: %m");
+        }
 
         return 0;
 }
@@ -580,49 +777,8 @@ int config_parse_label(const char *unit,
         return 0;
 }
 
-bool address_equal(Address *a1, Address *a2) {
-        /* same object */
-        if (a1 == a2)
-                return true;
-
-        /* one, but not both, is NULL */
-        if (!a1 || !a2)
-                return false;
-
-        if (a1->family != a2->family)
-                return false;
-
-        switch (a1->family) {
-        /* use the same notion of equality as the kernel does */
-        case AF_UNSPEC:
-                return true;
+bool address_is_ready(const Address *a) {
+        assert(a);
 
-        case AF_INET:
-                if (a1->prefixlen != a2->prefixlen)
-                        return false;
-                else if (a1->prefixlen == 0)
-                        /* make sure we don't try to shift by 32.
-                         * See ISO/IEC 9899:TC3 § 6.5.7.3. */
-                        return true;
-                else {
-                        uint32_t b1, b2;
-
-                        b1 = be32toh(a1->in_addr.in.s_addr);
-                        b2 = be32toh(a2->in_addr.in.s_addr);
-
-                        return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
-                }
-
-        case AF_INET6: {
-                uint64_t *b1, *b2;
-
-                b1 = (uint64_t*)&a1->in_addr.in6;
-                b2 = (uint64_t*)&a2->in_addr.in6;
-
-                return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
-        }
-
-        default:
-                assert_not_reached("Invalid address family");
-        }
+        return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
 }
index 39789a2382d55b5eeb5366e783022e8cb08cae1a..4049a23bdc4a1c923b11b38583b8fc3badb5be86 100644 (file)
@@ -38,6 +38,8 @@ struct Address {
         Network *network;
         unsigned section;
 
+        Link *link;
+
         int family;
         unsigned char prefixlen;
         unsigned char scope;
@@ -50,20 +52,23 @@ struct Address {
         union in_addr_union in_addr;
         union in_addr_union in_addr_peer;
 
-        bool ip_masquerade_done;
+        bool ip_masquerade_done:1;
 
         LIST_FIELDS(Address, addresses);
 };
 
 int address_new_static(Network *network, unsigned section, Address **ret);
-int address_new_dynamic(Address **ret);
+int address_new(Address **ret);
 void address_free(Address *address);
-int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_establish(Address *address, Link *link);
-int address_release(Address *address, Link *link);
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
+int address_drop(Address *address);
+int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update);
+int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
 bool address_equal(Address *a1, Address *a2);
+bool address_is_ready(const Address *a);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
 #define _cleanup_address_free_ _cleanup_(address_freep)
index 04f04df117698836b11d0b7fe807e17c6ae5ea79..b9c60a3c77871a765eb6087c83c28ec9cf9c0e79 100644 (file)
 #include <netinet/ether.h>
 #include <linux/if.h>
 
+#include "alloc-util.h"
+#include "dhcp-lease-internal.h"
 #include "hostname-util.h"
-#include "networkd-link.h"
 #include "network-internal.h"
-#include "dhcp-lease-internal.h"
+#include "networkd-link.h"
 
 static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
                                void *userdata) {
@@ -33,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
         int r;
 
         assert(link);
-        assert(link->dhcp4_messages);
+        assert(link->dhcp4_messages > 0);
 
         link->dhcp4_messages --;
 
@@ -43,9 +44,9 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
                 link_enter_failed(link);
         }
 
-        if (!link->dhcp4_messages) {
+        if (link->dhcp4_messages == 0) {
                 link->dhcp4_configured = true;
-                link_client_handler(link);
+                link_check_ready(link);
         }
 
         return 1;
@@ -72,11 +73,13 @@ static int link_set_dhcp_routes(Link *link) {
                 if (r < 0)
                         return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
 
-                r = route_new_dynamic(&route, RTPROT_DHCP);
+                r = route_new(&route);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not allocate route: %m");
 
-                r = route_new_dynamic(&route_gw, RTPROT_DHCP);
+                route->protocol = RTPROT_DHCP;
+
+                r = route_new(&route_gw);
                 if (r < 0)
                         return log_link_error_errno(link, r,  "Could not allocate route: %m");
 
@@ -84,11 +87,12 @@ static int link_set_dhcp_routes(Link *link) {
                  * route for the gw host so that we can route no matter the
                  * netmask or existing kernel route tables. */
                 route_gw->family = AF_INET;
-                route_gw->dst_addr.in = gateway;
+                route_gw->dst.in = gateway;
                 route_gw->dst_prefixlen = 32;
-                route_gw->prefsrc_addr.in = address;
+                route_gw->prefsrc.in = address;
                 route_gw->scope = RT_SCOPE_LINK;
-                route_gw->metrics = link->network->dhcp_route_metric;
+                route_gw->protocol = RTPROT_DHCP;
+                route_gw->priority = link->network->dhcp_route_metric;
 
                 r = route_configure(route_gw, link, &dhcp4_route_handler);
                 if (r < 0)
@@ -97,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) {
                 link->dhcp4_messages ++;
 
                 route->family = AF_INET;
-                route->in_addr.in = gateway;
-                route->prefsrc_addr.in = address;
-                route->metrics = link->network->dhcp_route_metric;
+                route->gw.in = gateway;
+                route->prefsrc.in = address;
+                route->priority = link->network->dhcp_route_metric;
 
                 r = route_configure(route, link, &dhcp4_route_handler);
                 if (r < 0) {
@@ -120,15 +124,16 @@ static int link_set_dhcp_routes(Link *link) {
         for (i = 0; i < n; i++) {
                 _cleanup_route_free_ Route *route = NULL;
 
-                r = route_new_dynamic(&route, RTPROT_DHCP);
+                r = route_new(&route);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not allocate route: %m");
 
                 route->family = AF_INET;
-                route->in_addr.in = static_routes[i].gw_addr;
-                route->dst_addr.in = static_routes[i].dst_addr;
+                route->protocol = RTPROT_DHCP;
+                route->gw.in = static_routes[i].gw_addr;
+                route->dst.in = static_routes[i].dst_addr;
                 route->dst_prefixlen = static_routes[i].dst_prefixlen;
-                route->metrics = link->network->dhcp_route_metric;
+                route->priority = link->network->dhcp_route_metric;
 
                 r = route_configure(route, link, &dhcp4_route_handler);
                 if (r < 0)
@@ -162,45 +167,45 @@ static int dhcp_lease_lost(Link *link) {
                         for (i = 0; i < n; i++) {
                                 _cleanup_route_free_ Route *route = NULL;
 
-                                r = route_new_dynamic(&route, RTPROT_UNSPEC);
+                                r = route_new(&route);
                                 if (r >= 0) {
                                         route->family = AF_INET;
-                                        route->in_addr.in = routes[i].gw_addr;
-                                        route->dst_addr.in = routes[i].dst_addr;
+                                        route->gw.in = routes[i].gw_addr;
+                                        route->dst.in = routes[i].dst_addr;
                                         route->dst_prefixlen = routes[i].dst_prefixlen;
 
-                                        route_drop(route, link,
-                                                   &link_route_drop_handler);
+                                        route_remove(route, link,
+                                                   &link_route_remove_handler);
                                 }
                         }
                 }
         }
 
-        r = address_new_dynamic(&address);
+        r = address_new(&address);
         if (r >= 0) {
                 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
                 if (r >= 0) {
                         _cleanup_route_free_ Route *route_gw = NULL;
                         _cleanup_route_free_ Route *route = NULL;
 
-                        r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
+                        r = route_new(&route_gw);
                         if (r >= 0) {
                                 route_gw->family = AF_INET;
-                                route_gw->dst_addr.in = gateway;
+                                route_gw->dst.in = gateway;
                                 route_gw->dst_prefixlen = 32;
                                 route_gw->scope = RT_SCOPE_LINK;
 
-                                route_drop(route_gw, link,
-                                           &link_route_drop_handler);
+                                route_remove(route_gw, link,
+                                           &link_route_remove_handler);
                         }
 
-                        r = route_new_dynamic(&route, RTPROT_UNSPEC);
+                        r = route_new(&route);
                         if (r >= 0) {
                                 route->family = AF_INET;
-                                route->in_addr.in = gateway;
+                                route->gw.in = gateway;
 
-                                route_drop(route, link,
-                                           &link_route_drop_handler);
+                                route_remove(route, link,
+                                           &link_route_remove_handler);
                         }
                 }
 
@@ -214,7 +219,7 @@ static int dhcp_lease_lost(Link *link) {
                         address->in_addr.in = addr;
                         address->prefixlen = prefixlen;
 
-                        address_drop(address, link, &link_address_drop_handler);
+                        address_remove(address, link, &link_address_remove_handler);
                 }
         }
 
@@ -267,7 +272,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
                 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
                 link_enter_failed(link);
         } else if (r >= 0)
-                link_rtnl_process_address(rtnl, m, link->manager);
+                manager_rtnl_process_address(rtnl, m, link->manager);
 
         link_set_dhcp_routes(link);
 
@@ -288,7 +293,7 @@ static int dhcp4_update_address(Link *link,
 
         prefixlen = in_addr_netmask_to_prefixlen(netmask);
 
-        r = address_new_dynamic(&addr);
+        r = address_new(&addr);
         if (r < 0)
                 return r;
 
@@ -299,9 +304,9 @@ static int dhcp4_update_address(Link *link,
         addr->prefixlen = prefixlen;
         addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
 
-        /* use update rather than configure so that we will update the
-         * lifetime of an existing address if it has already been configured */
-        r = address_update(addr, link, &dhcp4_address_handler);
+        /* allow reusing an existing address and simply update its lifetime
+         * in case it already exists */
+        r = address_configure(addr, link, &dhcp4_address_handler, true);
         if (r < 0)
                 return r;
 
@@ -528,9 +533,11 @@ int dhcp4_configure(Link *link) {
         assert(link->network);
         assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
 
-        r = sd_dhcp_client_new(&link->dhcp_client);
-        if (r < 0)
-                return r;
+        if (!link->dhcp_client) {
+                r = sd_dhcp_client_new(&link->dhcp_client);
+                if (r < 0)
+                        return r;
+        }
 
         r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
         if (r < 0)
index 3cb7b8d9caccf4448dd51b280b2aa34dd163d4fb..d407b31b78e9d8a145a879e972ffcec8481751a4 100644 (file)
 #include <netinet/ether.h>
 #include <linux/if.h>
 
-#include "networkd-link.h"
-#include "network-internal.h"
-
-#include "sd-icmp6-nd.h"
 #include "sd-dhcp6-client.h"
 
+#include "network-internal.h"
+#include "networkd-link.h"
+
 static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
 
 static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
@@ -58,18 +57,17 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
                 link_enter_failed(link);
 
         } else if (r >= 0)
-                link_rtnl_process_address(rtnl, m, link->manager);
+                manager_rtnl_process_address(rtnl, m, link->manager);
 
         return 1;
 }
 
-static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
-                                uint8_t prefixlen, uint32_t lifetime_preferred,
-                                uint32_t lifetime_valid) {
+static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
+                                uint32_t lifetime_preferred, uint32_t lifetime_valid) {
         int r;
         _cleanup_address_free_ Address *addr = NULL;
 
-        r = address_new_dynamic(&addr);
+        r = address_new(&addr);
         if (r < 0)
                 return r;
 
@@ -77,17 +75,17 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
         memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
 
         addr->flags = IFA_F_NOPREFIXROUTE;
-        addr->prefixlen = prefixlen;
+        addr->prefixlen = 128;
 
         addr->cinfo.ifa_prefered = lifetime_preferred;
         addr->cinfo.ifa_valid = lifetime_valid;
 
         log_link_info(link,
-                      "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
-                      SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
+                      "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
+                      SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
                       addr->prefixlen, lifetime_preferred, lifetime_valid);
 
-        r = address_update(addr, link, dhcp6_address_handler);
+        r = address_configure(addr, link, dhcp6_address_handler, true);
         if (r < 0)
                 log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
 
@@ -99,7 +97,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
         sd_dhcp6_lease *lease;
         struct in6_addr ip6_addr;
         uint32_t lifetime_preferred, lifetime_valid;
-        uint8_t prefixlen;
 
         r = sd_dhcp6_client_get_lease(client, &lease);
         if (r < 0)
@@ -111,18 +108,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
                                                 &lifetime_preferred,
                                                 &lifetime_valid) >= 0) {
 
-                r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
-                                        &ip6_addr, &prefixlen);
-                if (r < 0 && r != -EADDRNOTAVAIL) {
-                        log_link_warning_errno(link, r, "Could not get prefix information: %m");
-                        return r;
-                }
-
-                if (r == -EADDRNOTAVAIL)
-                        prefixlen = 128;
-
-                r = dhcp6_address_update(link, &ip6_addr, prefixlen,
-                                        lifetime_preferred, lifetime_valid);
+                r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
                 if (r < 0)
                         return r;
         }
@@ -145,7 +131,8 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
         case SD_DHCP6_CLIENT_EVENT_STOP:
         case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
         case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
-                log_link_warning(link, "DHCPv6 lease lost");
+                if (sd_dhcp6_client_get_lease(client, NULL) >= 0)
+                        log_link_warning(link, "DHCPv6 lease lost");
 
                 link->dhcp6_configured = false;
                 break;
@@ -176,197 +163,85 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
                 return;
         }
 
-        link_client_handler(link);
+        link_check_ready(link);
 }
 
-static int dhcp6_configure(Link *link, int event) {
-        int r;
-        bool information_request;
-
-        assert_return(link, -EINVAL);
-        assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
-                             SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER,
-                             SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);
-
-        link->dhcp6_configured = false;
-
-        if (link->dhcp6_client) {
-                r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
-                                                        &information_request);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
-                        goto error;
-                }
-
-                if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
-                        r = sd_dhcp6_client_stop(link->dhcp6_client);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
-                                goto error;
-                        }
-
-                        r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
-                                                                    false);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
-                                goto error;
-                        }
-
-                }
-
-                r = sd_dhcp6_client_start(link->dhcp6_client);
-                if (r < 0 && r != -EALREADY) {
-                        log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
-                        goto error;
-                }
-
-                if (r == -EALREADY)
-                        link->dhcp6_configured = true;
-
-                return r;
-        }
-
-        r = sd_dhcp6_client_new(&link->dhcp6_client);
-        if (r < 0)
-                goto error;
+int dhcp6_request_address(Link *link) {
+        int r, inf_req;
+        bool running;
 
-        r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
-        if (r < 0)
-                goto error;
+        assert(link);
+        assert(link->dhcp6_client);
 
-        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
-                                    (const uint8_t *) &link->mac,
-                                    sizeof (link->mac), ARPHRD_ETHER);
+        r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req);
         if (r < 0)
-                goto error;
+                return r;
 
-        r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
-        if (r < 0)
-                goto error;
+        if (!inf_req)
+                return 0;
 
-        r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
-                                         link);
+        r = sd_dhcp6_client_is_running(link->dhcp6_client);
         if (r < 0)
-                goto error;
+                return r;
+        else
+                running = !!r;
 
-        if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
-                r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
-                                                        true);
+        if (running) {
+                r = sd_dhcp6_client_stop(link->dhcp6_client);
                 if (r < 0)
-                        goto error;
+                        return r;
         }
 
-        r = sd_dhcp6_client_start(link->dhcp6_client);
-        if (r < 0)
-                goto error;
-
-        return r;
-
- error:
-        link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
-        return r;
-}
-
-static int dhcp6_prefix_expired(Link *link) {
-        int r;
-        sd_dhcp6_lease *lease;
-        struct in6_addr *expired_prefix, ip6_addr;
-        uint8_t expired_prefixlen;
-        uint32_t lifetime_preferred, lifetime_valid;
-
-        r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
-                                        &expired_prefix, &expired_prefixlen);
+        r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false);
         if (r < 0)
                 return r;
 
-        r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
-        if (r < 0)
-                return r;
-
-        log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired",
-                      SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix),
-                      expired_prefixlen);
-
-        sd_dhcp6_lease_reset_address_iter(lease);
-
-        while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
-                                                &lifetime_preferred,
-                                                &lifetime_valid) >= 0) {
-
-                r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
-                                        &ip6_addr);
+        if (running) {
+                r = sd_dhcp6_client_start(link->dhcp6_client);
                 if (r < 0)
-                        continue;
-
-                log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128);
-
-                dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
+                        return r;
         }
 
         return 0;
 }
 
-static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
-        Link *link = userdata;
+int dhcp6_configure(Link *link) {
+        sd_dhcp6_client *client = NULL;
+        int r;
 
         assert(link);
-        assert(link->network);
-        assert(link->manager);
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return;
-
-        switch(event) {
-        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
-                return;
-
-        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
-        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
-        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
-                dhcp6_configure(link, event);
-
-                break;
 
-        case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
-                if (!link->rtnl_extended_attrs)
-                        dhcp6_prefix_expired(link);
-
-                break;
-
-        default:
-                if (event < 0)
-                        log_link_warning_errno(link, event, "ICMPv6 error: %m");
-                else
-                        log_link_warning(link, "ICMPv6 unknown event: %d", event);
-
-                break;
-        }
-
-}
-
-int icmp6_configure(Link *link) {
-        int r;
+        r = sd_dhcp6_client_new(&client);
+        if (r < 0)
+                return r;
 
-        assert_return(link, -EINVAL);
+        r = sd_dhcp6_client_attach_event(client, NULL, 0);
+        if (r < 0)
+                goto error;
 
-        r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
+        r = sd_dhcp6_client_set_information_request(client, true);
         if (r < 0)
                 return r;
 
-        r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0);
+        r = sd_dhcp6_client_set_mac(client,
+                                    (const uint8_t *) &link->mac,
+                                    sizeof (link->mac), ARPHRD_ETHER);
         if (r < 0)
-                return r;
+                goto error;
 
-        r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac);
+        r = sd_dhcp6_client_set_index(client, link->ifindex);
         if (r < 0)
-                return r;
+                goto error;
 
-        r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex);
+        r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link);
         if (r < 0)
-                return r;
+                goto error;
+
+        link->dhcp6_client = client;
 
-        r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
-                                icmp6_router_handler, link);
+        return 0;
 
+error:
+        sd_dhcp6_client_unref(client);
         return r;
 }
index 9cb63cb79f4cf3eb1aaad33f2e26195c80bf1088..c9222b8cb8ec5f936fe87acab1bc0f8503e77ca3 100644 (file)
 #include <net/if.h>
 #include <net/ethernet.h>
 
+#include "alloc-util.h"
 #include "conf-parser.h"
-#include "util.h"
 #include "netlink-util.h"
-
-#include "networkd.h"
 #include "networkd-fdb.h"
+#include "networkd.h"
+#include "util.h"
 
 /* create a new FDB entry or get an existing one. */
 int fdb_entry_new_static(Network *const network,
index 1902b3d23ab09321142e222806136a8d5e35b182..ed0d861e7af5446f752c90855baf336262e92a83 100644 (file)
@@ -42,7 +42,7 @@ static int ipv4ll_address_lost(Link *link) {
 
         log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
 
-        r = address_new_dynamic(&address);
+        r = address_new(&address);
         if (r < 0) {
                 log_link_error_errno(link, r, "Could not allocate address: %m");
                 return r;
@@ -53,9 +53,9 @@ static int ipv4ll_address_lost(Link *link) {
         address->prefixlen = 16;
         address->scope = RT_SCOPE_LINK;
 
-        address_drop(address, link, &link_address_drop_handler);
+        address_remove(address, link, &link_address_remove_handler);
 
-        r = route_new_dynamic(&route, RTPROT_UNSPEC);
+        r = route_new(&route);
         if (r < 0) {
                 log_link_error_errno(link, r, "Could not allocate route: %m");
                 return r;
@@ -63,11 +63,11 @@ static int ipv4ll_address_lost(Link *link) {
 
         route->family = AF_INET;
         route->scope = RT_SCOPE_LINK;
-        route->metrics = IPV4LL_ROUTE_METRIC;
+        route->priority = IPV4LL_ROUTE_METRIC;
 
-        route_drop(route, link, &link_route_drop_handler);
+        route_remove(route, link, &link_route_remove_handler);
 
-        link_client_handler(link);
+        link_check_ready(link);
 
         return 0;
 }
@@ -88,7 +88,7 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
         link->ipv4ll_route = true;
 
         if (link->ipv4ll_address == true)
-                link_client_handler(link);
+                link_check_ready(link);
 
         return 1;
 }
@@ -105,12 +105,12 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void
                 log_link_error_errno(link, r, "could not set ipv4ll address: %m");
                 link_enter_failed(link);
         } else if (r >= 0)
-                link_rtnl_process_address(rtnl, m, link->manager);
+                manager_rtnl_process_address(rtnl, m, link->manager);
 
         link->ipv4ll_address = true;
 
         if (link->ipv4ll_route == true)
-                link_client_handler(link);
+                link_check_ready(link);
 
         return 1;
 }
@@ -133,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
                        ADDRESS_FMT_VAL(address));
 
-        r = address_new_dynamic(&ll_addr);
+        r = address_new(&ll_addr);
         if (r < 0)
                 return r;
 
@@ -143,19 +143,20 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
         ll_addr->scope = RT_SCOPE_LINK;
 
-        r = address_configure(ll_addr, link, ipv4ll_address_handler);
+        r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
         if (r < 0)
                 return r;
 
         link->ipv4ll_address = false;
 
-        r = route_new_dynamic(&route, RTPROT_STATIC);
+        r = route_new(&route);
         if (r < 0)
                 return r;
 
         route->family = AF_INET;
         route->scope = RT_SCOPE_LINK;
-        route->metrics = IPV4LL_ROUTE_METRIC;
+        route->protocol = RTPROT_STATIC;
+        route->priority = IPV4LL_ROUTE_METRIC;
 
         r = route_configure(route, link, ipv4ll_route_handler);
         if (r < 0)
@@ -207,9 +208,11 @@ int ipv4ll_configure(Link *link) {
         assert(link->network);
         assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
 
-        r = sd_ipv4ll_new(&link->ipv4ll);
-        if (r < 0)
-                return r;
+        if (!link->ipv4ll) {
+                r = sd_ipv4ll_new(&link->ipv4ll);
+                if (r < 0)
+                        return r;
+        }
 
         if (link->udev_device) {
                 r = net_get_unique_predictable_data(link->udev_device, seed);
index 1a1524dfb4e317013077e086a7520d27fc3da94e..11b35d6cf804c9f7859f387b670aed9cd8f623fa 100644 (file)
 #include "bus-util.h"
 #include "strv.h"
 
-#include "networkd.h"
+#include "alloc-util.h"
 #include "networkd-link.h"
+#include "networkd.h"
+#include "parse-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
@@ -101,7 +103,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
         if (r < 0)
                 return 0;
 
-        r = safe_atoi(identifier, &ifindex);
+        r = parse_ifindex(identifier, &ifindex);
         if (r < 0)
                 return 0;
 
index ffc9578e86841642693588af1468b86bfb038642..a415035887ac6edea417cf71fa00f9271fd4eefb 100644 (file)
 #include <linux/if.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "socket-util.h"
+#include "alloc-util.h"
 #include "bus-util.h"
-#include "udev-util.h"
-#include "netlink-util.h"
 #include "dhcp-lease-internal.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "netlink-util.h"
 #include "network-internal.h"
-
 #include "networkd-link.h"
 #include "networkd-netdev.h"
+#include "set.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "udev-util.h"
+#include "util.h"
+#include "virt.h"
 
 bool link_dhcp6_enabled(Link *link) {
         if (link->flags & IFF_LOOPBACK)
@@ -106,20 +111,56 @@ static bool link_ipv4_forward_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+                return false;
+
         return link->network->ip_forward & ADDRESS_FAMILY_IPV4;
 }
 
 static bool link_ipv6_forward_enabled(Link *link) {
+
+        if (!socket_ipv6_is_supported())
+                return false;
+
         if (link->flags & IFF_LOOPBACK)
                 return false;
 
         if (!link->network)
                 return false;
 
+        if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+                return false;
+
         return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
 }
 
+bool link_ipv6_accept_ra_enabled(Link *link) {
+        if (link->flags & IFF_LOOPBACK)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        /* If unset use system default (enabled if local forwarding is disabled.
+         * disabled if local forwarding is enabled).
+         * If set, ignore or enforce RA independent of local forwarding state.
+         */
+        if (link->network->ipv6_accept_ra < 0)
+                /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
+                return !link_ipv6_forward_enabled(link);
+        else if (link->network->ipv6_accept_ra > 0)
+                /* accept RA even if ip_forward is enabled */
+                return true;
+        else
+                /* ignore RA */
+                return false;
+}
+
 static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
+
+        if (!socket_ipv6_is_supported())
+                return _IPV6_PRIVACY_EXTENSIONS_INVALID;
+
         if (link->flags & IFF_LOOPBACK)
                 return _IPV6_PRIVACY_EXTENSIONS_INVALID;
 
@@ -129,6 +170,57 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
         return link->network->ipv6_privacy_extensions;
 }
 
+void link_update_operstate(Link *link) {
+        LinkOperationalState operstate;
+        assert(link);
+
+        if (link->kernel_operstate == IF_OPER_DORMANT)
+                operstate = LINK_OPERSTATE_DORMANT;
+        else if (link_has_carrier(link)) {
+                Address *address;
+                uint8_t scope = RT_SCOPE_NOWHERE;
+                Iterator i;
+
+                /* if we have carrier, check what addresses we have */
+                SET_FOREACH(address, link->addresses, i) {
+                        if (!address_is_ready(address))
+                                continue;
+
+                        if (address->scope < scope)
+                                scope = address->scope;
+                }
+
+                /* for operstate we also take foreign addresses into account */
+                SET_FOREACH(address, link->addresses_foreign, i) {
+                        if (!address_is_ready(address))
+                                continue;
+
+                        if (address->scope < scope)
+                                scope = address->scope;
+                }
+
+                if (scope < RT_SCOPE_SITE)
+                        /* universally accessible addresses found */
+                        operstate = LINK_OPERSTATE_ROUTABLE;
+                else if (scope < RT_SCOPE_HOST)
+                        /* only link or site local addresses found */
+                        operstate = LINK_OPERSTATE_DEGRADED;
+                else
+                        /* no useful addresses found */
+                        operstate = LINK_OPERSTATE_CARRIER;
+        } else if (link->flags & IFF_UP)
+                operstate = LINK_OPERSTATE_NO_CARRIER;
+        else
+                operstate = LINK_OPERSTATE_OFF;
+
+        if (link->operstate != operstate) {
+                link->operstate = operstate;
+                link_send_changed(link, "OperationalState", NULL);
+                link_dirty(link);
+                manager_dirty(link->manager);
+        }
+}
+
 #define FLAG_STRING(string, flag, old, new) \
         (((old ^ new) & flag) \
                 ? ((old & flag) ? (" -" string) : (" +" string)) \
@@ -201,7 +293,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
         link->flags = flags;
         link->kernel_operstate = operstate;
 
-        link_save(link);
+        link_update_operstate(link);
 
         return 0;
 }
@@ -291,10 +383,15 @@ static void link_free(Link *link) {
         if (!link)
                 return;
 
-        while ((address = link->addresses)) {
-                LIST_REMOVE(addresses, link->addresses, address);
-                address_free(address);
-        }
+        while (!set_isempty(link->addresses))
+                address_free(set_first(link->addresses));
+
+        while (!set_isempty(link->addresses_foreign))
+                address_free(set_first(link->addresses_foreign));
+
+        link->addresses = set_free(link->addresses);
+
+        link->addresses_foreign = set_free(link->addresses_foreign);
 
         while ((address = link->pool_addresses)) {
                 LIST_REMOVE(addresses, link->pool_addresses, address);
@@ -313,13 +410,14 @@ static void link_free(Link *link) {
 
         sd_ipv4ll_unref(link->ipv4ll);
         sd_dhcp6_client_unref(link->dhcp6_client);
-        sd_icmp6_nd_unref(link->icmp6_router_discovery);
+        sd_ndisc_unref(link->ndisc_router_discovery);
 
         if (link->manager)
                 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
 
         free(link->ifname);
 
+        (void)unlink(link->state_file);
         free(link->state_file);
 
         udev_device_unref(link->udev_device);
@@ -336,15 +434,28 @@ static void link_free(Link *link) {
 }
 
 Link *link_unref(Link *link) {
-        if (link && (-- link->n_ref <= 0))
-                link_free(link);
+        if (!link)
+                return NULL;
+
+        assert(link->n_ref > 0);
+
+        link->n_ref --;
+
+        if (link->n_ref > 0)
+                return NULL;
+
+        link_free(link);
 
         return NULL;
 }
 
 Link *link_ref(Link *link) {
-        if (link)
-                assert_se(++ link->n_ref >= 2);
+        if (!link)
+                return NULL;
+
+        assert(link->n_ref > 0);
+
+        link->n_ref ++;
 
         return link;
 }
@@ -385,7 +496,7 @@ static void link_enter_unmanaged(Link *link) {
 
         link_set_state(link, LINK_STATE_UNMANAGED);
 
-        link_save(link);
+        link_dirty(link);
 }
 
 static int link_stop_clients(Link *link) {
@@ -395,9 +506,6 @@ static int link_stop_clients(Link *link) {
         assert(link->manager);
         assert(link->manager->event);
 
-        if (!link->network)
-                return 0;
-
         if (link->dhcp_client) {
                 k = sd_dhcp_client_stop(link->dhcp_client);
                 if (k < 0)
@@ -410,16 +518,16 @@ static int link_stop_clients(Link *link) {
                         r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
         }
 
-        if(link->icmp6_router_discovery) {
-                if (link->dhcp6_client) {
-                        k = sd_dhcp6_client_stop(link->dhcp6_client);
-                        if (k < 0)
-                                r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
-                }
+        if (link->dhcp6_client) {
+                k = sd_dhcp6_client_stop(link->dhcp6_client);
+                if (k < 0)
+                        r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
+        }
 
-                k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
+        if (link->ndisc_router_discovery) {
+                k = sd_ndisc_stop(link->ndisc_router_discovery);
                 if (k < 0)
-                        r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m");
+                        r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
         }
 
         if (link->lldp) {
@@ -443,7 +551,7 @@ void link_enter_failed(Link *link) {
 
         link_stop_clients(link);
 
-        link_save(link);
+        link_dirty(link);
 }
 
 static Address* link_find_dhcp_server_address(Link *link) {
@@ -484,14 +592,19 @@ static int link_enter_configured(Link *link) {
 
         link_set_state(link, LINK_STATE_CONFIGURED);
 
-        link_save(link);
+        link_dirty(link);
 
         return 0;
 }
 
-void link_client_handler(Link *link) {
+void link_check_ready(Link *link) {
+        Address *a;
+        Iterator i;
+
         assert(link);
-        assert(link->network);
+
+        if (!link->network)
+                return;
 
         if (!link->static_configured)
                 return;
@@ -501,6 +614,10 @@ void link_client_handler(Link *link) {
                     !link->ipv4ll_route)
                         return;
 
+        if (link_ipv6ll_enabled(link))
+                if (!link->ipv6ll_address)
+                        return;
+
         if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
              !link->dhcp4_configured) ||
             (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
@@ -509,6 +626,13 @@ void link_client_handler(Link *link) {
              !link->dhcp4_configured && !link->dhcp6_configured))
                 return;
 
+        if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+                return;
+
+        SET_FOREACH(a, link->addresses, i)
+                if (!address_is_ready(a))
+                        return;
+
         if (link->state != LINK_STATE_CONFIGURED)
                 link_enter_configured(link);
 
@@ -531,12 +655,12 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
-                log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not set route: %m");
 
         if (link->link_messages == 0) {
                 log_link_debug(link, "Routes set");
                 link->static_configured = true;
-                link_client_handler(link);
+                link_check_ready(link);
         }
 
         return 1;
@@ -565,14 +689,14 @@ static int link_enter_set_routes(Link *link) {
 
         if (link->link_messages == 0) {
                 link->static_configured = true;
-                link_client_handler(link);
+                link_check_ready(link);
         } else
                 log_link_debug(link, "Setting routes");
 
         return 0;
 }
 
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -585,7 +709,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -ESRCH)
-                log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not drop route: %m");
 
         return 1;
 }
@@ -609,9 +733,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST)
-                log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "could not set address: %m");
         else if (r >= 0)
-                link_rtnl_process_address(rtnl, m, link->manager);
+                manager_rtnl_process_address(rtnl, m, link->manager);
 
         if (link->link_messages == 0) {
                 log_link_debug(link, "Addresses set");
@@ -722,7 +846,7 @@ static int link_enter_set_addresses(Link *link) {
         link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
 
         LIST_FOREACH(addresses, ad, link->network->static_addresses) {
-                r = address_configure(ad, link, &address_handler);
+                r = address_configure(ad, link, &address_handler, false);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "Could not set addresses: %m");
                         link_enter_failed(link);
@@ -854,7 +978,7 @@ static int link_enter_set_addresses(Link *link) {
         return 0;
 }
 
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
         _cleanup_link_unref_ Link *link = userdata;
         int r;
 
@@ -867,7 +991,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EADDRNOTAVAIL)
-                log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not drop address: %m");
 
         return 1;
 }
@@ -1019,7 +1143,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0)
-                log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not set MTU: %m");
 
         return 1;
 }
@@ -1129,6 +1253,34 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
         }
 }
 
+static int link_acquire_ipv6_conf(Link *link) {
+        int r;
+
+        assert(link);
+
+        if (link_dhcp6_enabled(link)) {
+                assert(link->dhcp6_client);
+
+                log_link_debug(link, "Acquiring DHCPv6 lease");
+
+                r = sd_dhcp6_client_start(link->dhcp6_client);
+                if (r < 0)
+                        return log_link_warning_errno(link, r,  "Could not acquire DHCPv6 lease: %m");
+        }
+
+        if (link_ipv6_accept_ra_enabled(link)) {
+                assert(link->ndisc_router_discovery);
+
+                log_link_debug(link, "Discovering IPv6 routers");
+
+                r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
+        }
+
+        return 0;
+}
+
 static int link_acquire_conf(Link *link) {
         int r;
 
@@ -1157,16 +1309,6 @@ static int link_acquire_conf(Link *link) {
                         return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
         }
 
-        if (link_dhcp6_enabled(link)) {
-                assert(link->icmp6_router_discovery);
-
-                log_link_debug(link, "Discovering IPv6 routers");
-
-                r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
-                if (r < 0)
-                        return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m");
-        }
-
         if (link_lldp_enabled(link)) {
                 assert(link->lldp);
 
@@ -1207,7 +1349,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
         if (r < 0)
                 /* we warn but don't fail the link, as it may be
                    brought up later */
-                log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not bring up interface: %m");
 
         return 1;
 }
@@ -1294,7 +1436,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0)
-                log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
+                log_link_warning_errno(link, r, "Could not bring down interface: %m");
 
         return 1;
 }
@@ -1432,14 +1574,14 @@ static int link_new_bound_by_list(Link *link) {
         }
 
         if (list_updated)
-                link_save(link);
+                link_dirty(link);
 
         HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
                 r = link_put_carrier(carrier, link, &carrier->bound_to_links);
                 if (r < 0)
                         return r;
 
-                link_save(carrier);
+                link_dirty(carrier);
         }
 
         return 0;
@@ -1474,14 +1616,14 @@ static int link_new_bound_to_list(Link *link) {
         }
 
         if (list_updated)
-                link_save(link);
+                link_dirty(link);
 
         HASHMAP_FOREACH (carrier, link->bound_to_links, i) {
                 r = link_put_carrier(carrier, link, &carrier->bound_by_links);
                 if (r < 0)
                         return r;
 
-                link_save(carrier);
+                link_dirty(carrier);
         }
 
         return 0;
@@ -1517,7 +1659,7 @@ static void link_free_bound_to_list(Link *link) {
                 hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
 
                 if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
-                        link_save(bound_to);
+                        link_dirty(bound_to);
         }
 
         return;
@@ -1531,7 +1673,7 @@ static void link_free_bound_by_list(Link *link) {
                 hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
 
                 if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
-                        link_save(bound_by);
+                        link_dirty(bound_by);
                         link_handle_bound_to_list(bound_by);
                 }
         }
@@ -1555,7 +1697,7 @@ static void link_free_carrier_maps(Link *link) {
         }
 
         if (list_updated)
-                link_save(link);
+                link_dirty(link);
 
         return;
 }
@@ -1570,6 +1712,7 @@ void link_drop(Link *link) {
 
         log_link_debug(link, "Link removed");
 
+        (void)unlink(link->state_file);
         link_unref(link);
 
         return;
@@ -1616,7 +1759,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us
 
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EEXIST) {
-                log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
+                log_link_error_errno(link, r, "Could not join netdev: %m");
                 link_enter_failed(link);
                 return 1;
         } else
@@ -1639,7 +1782,7 @@ static int link_enter_join_netdev(Link *link) {
 
         link_set_state(link, LINK_STATE_ENSLAVING);
 
-        link_save(link);
+        link_dirty(link);
 
         if (!link->network->bridge &&
             !link->network->bond &&
@@ -1715,32 +1858,69 @@ static int link_enter_join_netdev(Link *link) {
 }
 
 static int link_set_ipv4_forward(Link *link) {
-        const char *p = NULL, *v;
         int r;
 
-        if (link->flags & IFF_LOOPBACK)
+        if (!link_ipv4_forward_enabled(link))
                 return 0;
 
-        if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+        /* We propagate the forwarding flag from one interface to the
+         * global setting one way. This means: as long as at least one
+         * interface was configured at any time that had IP forwarding
+         * enabled the setting will stay on for good. We do this
+         * primarily to keep IPv4 and IPv6 packet forwarding behaviour
+         * somewhat in sync (see below). */
+
+        r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
+
+        return 0;
+}
+
+static int link_set_ipv6_forward(Link *link) {
+        int r;
+
+        if (!link_ipv6_forward_enabled(link))
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding");
-        v = one_zero(link_ipv4_forward_enabled(link));
+        /* On Linux, the IPv6 stack does not not know a per-interface
+         * packet forwarding setting: either packet forwarding is on
+         * for all, or off for all. We hence don't bother with a
+         * per-interface setting, but simply propagate the interface
+         * flag, if it is set, to the global flag, one-way. Note that
+         * while IPv4 would allow a per-interface flag, we expose the
+         * same behaviour there and also propagate the setting from
+         * one to all, to keep things simple (see above). */
 
-        r = write_string_file(p, v, 0);
-        if (r < 0) {
-                /* If the right value is set anyway, don't complain */
-                if (verify_one_line_file(p, v) > 0)
-                        return 0;
+        r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
 
-                log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname);
-        }
+        return 0;
+}
+
+static int link_set_ipv6_privacy_extensions(Link *link) {
+        char buf[DECIMAL_STR_MAX(unsigned) + 1];
+        IPv6PrivacyExtensions s;
+        const char *p = NULL;
+        int r;
+
+        s = link_ipv6_privacy_extensions(link);
+        if (s < 0)
+                return 0;
+
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
+        xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions);
+
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
 
         return 0;
 }
 
-static int link_set_ipv6_forward(Link *link) {
-        const char *p = NULL, *v = NULL;
+static int link_set_ipv6_accept_ra(Link *link) {
+        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -1750,27 +1930,21 @@ static int link_set_ipv6_forward(Link *link) {
         if (link->flags & IFF_LOOPBACK)
                 return 0;
 
-        if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
+        if (!link->network)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding");
-        v = one_zero(link_ipv6_forward_enabled(link));
-
-        r = write_string_file(p, v, 0);
-        if (r < 0) {
-                /* If the right value is set anyway, don't complain */
-                if (verify_one_line_file(p, v) > 0)
-                        return 0;
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
 
-                log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m");
-        }
+        /* We handle router advertisments ourselves, tell the kernel to GTFO */
+        r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
 
         return 0;
 }
 
-static int link_set_ipv6_privacy_extensions(Link *link) {
-        char buf[DECIMAL_STR_MAX(unsigned) + 1];
-        IPv6PrivacyExtensions s;
+static int link_set_ipv6_dad_transmits(Link *link) {
+        char buf[DECIMAL_STR_MAX(int) + 1];
         const char *p = NULL;
         int r;
 
@@ -1778,27 +1952,28 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
         if (!socket_ipv6_is_supported())
                 return 0;
 
-        s = link_ipv6_privacy_extensions(link);
-        if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID)
+        if (link->flags & IFF_LOOPBACK)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
-        xsprintf(buf, "%u", link->network->ipv6_privacy_extensions);
+        if (!link->network)
+                return 0;
 
-        r = write_string_file(p, buf, 0);
-        if (r < 0) {
-                /* If the right value is set anyway, don't complain */
-                if (verify_one_line_file(p, buf) > 0)
-                        return 0;
+        if (link->network->ipv6_dad_transmits < 0)
+                return 0;
 
-                log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
-        }
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
+        xsprintf(buf, "%i", link->network->ipv6_dad_transmits);
+
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
 
         return 0;
 }
 
-static int link_set_ipv6_accept_ra(Link *link) {
-        const char *p = NULL, *v = NULL;
+static int link_set_ipv6_hop_limit(Link *link) {
+        char buf[DECIMAL_STR_MAX(int) + 1];
+        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -1808,29 +1983,46 @@ static int link_set_ipv6_accept_ra(Link *link) {
         if (link->flags & IFF_LOOPBACK)
                 return 0;
 
-        /* If unset use system default (enabled if local forwarding is disabled.
-         * disabled if local forwarding is enabled).
-         * If set, ignore or enforce RA independent of local forwarding state.
-         */
-        if (link->network->ipv6_accept_ra < 0) {
-                /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
-                v = "1";
-        } else if (link->network->ipv6_accept_ra > 0) {
-                /* "2" means accept RA even if ip_forward is enabled */
-                v = "2";
-        } else {
-                /* "0" means ignore RA */
-                v = "0";
+        if (!link->network)
+                return 0;
+
+        if (link->network->ipv6_hop_limit < 0)
+                return 0;
+
+        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit");
+        xsprintf(buf, "%i", link->network->ipv6_hop_limit);
+
+        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
+
+        return 0;
+}
+
+static int link_drop_foreign_config(Link *link) {
+        Address *address;
+        Route *route;
+        Iterator i;
+        int r;
+
+        SET_FOREACH(address, link->addresses_foreign, i) {
+                /* we consider IPv6LL addresses to be managed by the kernel */
+                if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1)
+                        continue;
+
+                r = address_remove(address, link, link_address_remove_handler);
+                if (r < 0)
+                        return r;
         }
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
 
-        r = write_string_file(p, v, 0);
-        if (r < 0) {
-                /* If the right value is set anyway, don't complain */
-                if (verify_one_line_file(p, v) > 0)
-                        return 0;
+        SET_FOREACH(route, link->routes_foreign, i) {
+                /* do not touch routes managed by the kernel */
+                if (route->protocol == RTPROT_KERNEL)
+                        continue;
 
-                log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m");
+                r = route_remove(route, link, link_address_remove_handler);
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -1843,6 +2035,10 @@ static int link_configure(Link *link) {
         assert(link->network);
         assert(link->state == LINK_STATE_PENDING);
 
+        r = link_drop_foreign_config(link);
+        if (r < 0)
+                return r;
+
         r = link_set_bridge_fdb(link);
         if (r < 0)
                 return r;
@@ -1863,6 +2059,14 @@ static int link_configure(Link *link) {
         if (r < 0)
                 return r;
 
+        r = link_set_ipv6_dad_transmits(link);
+        if (r < 0)
+                return r;
+
+        r = link_set_ipv6_hop_limit(link);
+        if (r < 0)
+                return r;
+
         if (link_ipv4ll_enabled(link)) {
                 r = ipv4ll_configure(link);
                 if (r < 0)
@@ -1886,7 +2090,13 @@ static int link_configure(Link *link) {
         }
 
         if (link_dhcp6_enabled(link)) {
-                r = icmp6_configure(link);
+                r = dhcp6_configure(link);
+                if (r < 0)
+                        return r;
+        }
+
+        if (link_ipv6_accept_ra_enabled(link)) {
+                r = ndisc_configure(link);
                 if (r < 0)
                         return r;
         }
@@ -1910,6 +2120,12 @@ static int link_configure(Link *link) {
                 r = link_acquire_conf(link);
                 if (r < 0)
                         return r;
+
+                if (link->ipv6ll_address) {
+                        r = link_acquire_ipv6_conf(link);
+                        if (r < 0)
+                                return r;
+                }
         }
 
         return link_enter_join_netdev(link);
@@ -1938,28 +2154,30 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
         if (r < 0)
                 return r;
 
-        r = network_get(link->manager, link->udev_device, link->ifname,
-                        &link->mac, &network);
-        if (r == -ENOENT) {
-                link_enter_unmanaged(link);
-                return 1;
-        } else if (r < 0)
-                return r;
+        if (!link->network) {
+                r = network_get(link->manager, link->udev_device, link->ifname,
+                                &link->mac, &network);
+                if (r == -ENOENT) {
+                        link_enter_unmanaged(link);
+                        return 1;
+                } else if (r < 0)
+                        return r;
 
-        if (link->flags & IFF_LOOPBACK) {
-                if (network->link_local != ADDRESS_FAMILY_NO)
-                        log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
+                if (link->flags & IFF_LOOPBACK) {
+                        if (network->link_local != ADDRESS_FAMILY_NO)
+                                log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
 
-                if (network->dhcp != ADDRESS_FAMILY_NO)
-                        log_link_debug(link, "Ignoring DHCP clients for loopback link");
+                        if (network->dhcp != ADDRESS_FAMILY_NO)
+                                log_link_debug(link, "Ignoring DHCP clients for loopback link");
 
-                if (network->dhcp_server)
-                        log_link_debug(link, "Ignoring DHCP server for loopback link");
-        }
+                        if (network->dhcp_server)
+                                log_link_debug(link, "Ignoring DHCP server for loopback link");
+                }
 
-        r = network_apply(link->manager, network, link);
-        if (r < 0)
-                return r;
+                r = network_apply(link->manager, network, link);
+                if (r < 0)
+                        return r;
+        }
 
         r = link_new_bound_to_list(link);
         if (r < 0)
@@ -2011,177 +2229,191 @@ int link_initialized(Link *link, struct udev_device *device) {
         return 0;
 }
 
-static Address* link_get_equal_address(Link *link, Address *needle) {
-        Address *i;
+static int link_load(Link *link) {
+        _cleanup_free_ char *network_file = NULL,
+                            *addresses = NULL,
+                            *routes = NULL,
+                            *dhcp4_address = NULL,
+                            *ipv4ll_address = NULL;
+        union in_addr_union address;
+        union in_addr_union route_dst;
+        const char *p;
+        int r;
 
         assert(link);
-        assert(needle);
-
-        LIST_FOREACH(addresses, i, link->addresses)
-                if (address_equal(i, needle))
-                        return i;
 
-        return NULL;
-}
-
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
-        Manager *m = userdata;
-        Link *link = NULL;
-        uint16_t type;
-        _cleanup_address_free_ Address *address = NULL;
-        unsigned char flags;
-        Address *existing;
-        char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
-        const char *valid_str = NULL;
-        int r, ifindex;
+        r = parse_env_file(link->state_file, NEWLINE,
+                           "NETWORK_FILE", &network_file,
+                           "ADDRESSES", &addresses,
+                           "ROUTES", &routes,
+                           "DHCP4_ADDRESS", &dhcp4_address,
+                           "IPV4LL_ADDRESS", &ipv4ll_address,
+                           NULL);
+        if (r < 0 && r != -ENOENT)
+                return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
+
+        if (network_file) {
+                Network *network;
+                char *suffix;
+
+                /* drop suffix */
+                suffix = strrchr(network_file, '.');
+                if (!suffix) {
+                        log_link_debug(link, "Failed to get network name from %s", network_file);
+                        goto network_file_fail;
+                }
+                *suffix = '\0';
 
-        assert(rtnl);
-        assert(message);
-        assert(m);
+                r = network_get_by_name(link->manager, basename(network_file), &network);
+                if (r < 0) {
+                        log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
+                        goto network_file_fail;
+                }
 
-        if (sd_netlink_message_is_error(message)) {
-                r = sd_netlink_message_get_errno(message);
+                r = network_apply(link->manager, network, link);
                 if (r < 0)
-                        log_warning_errno(r, "rtnl: failed to receive address: %m");
-
-                return 0;
+                        return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
         }
 
-        r = sd_netlink_message_get_type(message, &type);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get message type: %m");
-                return 0;
-        } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
-                log_warning("rtnl: received unexpected message type when processing address");
-                return 0;
-        }
-
-        r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
-        if (r < 0) {
-                log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
-                return 0;
-        } else if (ifindex <= 0) {
-                log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
-                return 0;
-        } else {
-                r = link_get(m, ifindex, &link);
-                if (r < 0 || !link) {
-                        /* when enumerating we might be out of sync, but we will
-                         * get the address again, so just ignore it */
-                        if (!m->enumerating)
-                                log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
-                        return 0;
-                }
-        }
+network_file_fail:
 
-        r = address_new_dynamic(&address);
-        if (r < 0)
-                return r;
+        if (addresses) {
+                p = addresses;
 
-        r = sd_rtnl_message_addr_get_family(message, &address->family);
-        if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
-                log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
-                return 0;
-        }
+                for (;;) {
+                        _cleanup_free_ char *address_str = NULL;
+                        char *prefixlen_str;
+                        int family;
+                        unsigned char prefixlen;
 
-        r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
-                return 0;
-        }
+                        r = extract_first_word(&p, &address_str, NULL, 0);
+                        if (r < 0) {
+                                log_link_debug_errno(link, r, "Failed to extract next address string: %m");
+                                continue;
+                        } if (r == 0)
+                                break;
 
-        r = sd_rtnl_message_addr_get_scope(message, &address->scope);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
-                return 0;
-        }
+                        prefixlen_str = strchr(address_str, '/');
+                        if (!prefixlen_str) {
+                                log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
+                                continue;
+                        }
 
-        r = sd_rtnl_message_addr_get_flags(message, &flags);
-        if (r < 0) {
-                log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
-                return 0;
-        }
-        address->flags = flags;
+                        *prefixlen_str ++ = '\0';
 
-        switch (address->family) {
-        case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
-                        return 0;
-                }
+                        r = sscanf(prefixlen_str, "%hhu", &prefixlen);
+                        if (r != 1) {
+                                log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
+                                continue;
+                        }
 
-                break;
+                        r = in_addr_from_string_auto(address_str, &family, &address);
+                        if (r < 0) {
+                                log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
+                                continue;
+                        }
 
-        case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
-                        return 0;
+                        r = address_add(link, family, &address, prefixlen, NULL);
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Failed to add address: %m");
                 }
-
-                break;
-
-        default:
-                assert_not_reached("invalid address family");
         }
 
-        if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
-                log_link_warning(link, "Could not print address");
-                return 0;
-        }
+        if (routes) {
+                for (;;) {
+                        Route *route;
+                        _cleanup_free_ char *route_str = NULL;
+                        _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+                        usec_t lifetime;
+                        char *prefixlen_str;
+                        int family;
+                        unsigned char prefixlen, tos, table;
+                        uint32_t priority;
 
-        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
-        if (r >= 0) {
-                if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
-                        valid_str = "ever";
-                else
-                        valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
-                                                    address->cinfo.ifa_valid * USEC_PER_SEC,
-                                                    USEC_PER_SEC);
-        }
+                        r = extract_first_word(&p, &route_str, NULL, 0);
+                        if (r < 0) {
+                                log_link_debug_errno(link, r, "Failed to extract next route string: %m");
+                                continue;
+                        } if (r == 0)
+                                break;
 
-        existing = link_get_equal_address(link, address);
+                        prefixlen_str = strchr(route_str, '/');
+                        if (!prefixlen_str) {
+                                log_link_debug(link, "Failed to parse route %s", route_str);
+                                continue;
+                        }
 
-        switch (type) {
-        case RTM_NEWADDR:
-                if (existing) {
-                        log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+                        *prefixlen_str ++ = '\0';
 
+                        r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
+                        if (r != 5) {
+                                log_link_debug(link,
+                                               "Failed to parse destination prefix length, tos, priority, table or expiration %s",
+                                               prefixlen_str);
+                                continue;
+                        }
 
-                        existing->scope = address->scope;
-                        existing->flags = address->flags;
-                        existing->cinfo = address->cinfo;
+                        r = in_addr_from_string_auto(route_str, &family, &route_dst);
+                        if (r < 0) {
+                                log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
+                                continue;
+                        }
 
-                } else {
-                        log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+                        r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
+                        if (r < 0)
+                                return log_link_error_errno(link, r, "Failed to add route: %m");
 
-                        LIST_PREPEND(addresses, link->addresses, address);
-                        address_establish(address, link);
+                        if (lifetime != USEC_INFINITY) {
+                                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
+                                                      0, route_expire_handler, route);
+                                if (r < 0)
+                                        log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
+                        }
 
-                        address = NULL;
+                        route->lifetime = lifetime;
+                        sd_event_source_unref(route->expire);
+                        route->expire = expire;
+                        expire = NULL;
+                }
+        }
 
-                        link_save(link);
+        if (dhcp4_address) {
+                r = in_addr_from_string(AF_INET, dhcp4_address, &address);
+                if (r < 0) {
+                        log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address);
+                        goto dhcp4_address_fail;
                 }
 
-                break;
+                r = sd_dhcp_client_new(&link->dhcp_client);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m");
 
-        case RTM_DELADDR:
+                r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address);
+        }
 
-                if (existing) {
-                        log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-                        address_release(existing, link);
-                        LIST_REMOVE(addresses, link->addresses, existing);
-                        address_free(existing);
-                } else
-                        log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+dhcp4_address_fail:
 
-                break;
-        default:
-                assert_not_reached("Received invalid RTNL message type");
+        if (ipv4ll_address) {
+                r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
+                if (r < 0) {
+                        log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address);
+                        goto ipv4ll_address_fail;
+                }
+
+                r = sd_ipv4ll_new(&link->ipv4ll);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m");
+
+                r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address);
         }
 
-        return 1;
+ipv4ll_address_fail:
+
+        return 0;
 }
 
 int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
@@ -2203,12 +2435,18 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
 
         log_link_debug(link, "Link %d added", link->ifindex);
 
+        r = link_load(link);
+        if (r < 0)
+                return r;
+
         if (detect_container() <= 0) {
                 /* not in a container, udev will be around */
                 sprintf(ifindex_str, "n%d", link->ifindex);
                 device = udev_device_new_from_device_id(m->udev, ifindex_str);
-                if (!device)
-                        return log_link_warning_errno(link, errno, "Could not find udev device: %m");
+                if (!device) {
+                        r = log_link_warning_errno(link, errno, "Could not find udev device: %m");
+                        goto failed;
+                }
 
                 if (udev_device_get_is_initialized(device) <= 0) {
                         /* not yet ready */
@@ -2218,14 +2456,38 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
 
                 r = link_initialized(link, device);
                 if (r < 0)
-                        return r;
+                        goto failed;
         } else {
                 /* we are calling a callback directly, so must take a ref */
                 link_ref(link);
 
                 r = link_initialized_and_synced(m->rtnl, NULL, link);
                 if (r < 0)
+                        goto failed;
+        }
+
+        return 0;
+failed:
+        link_enter_failed(link);
+        return r;
+}
+
+int link_ipv6ll_gained(Link *link) {
+        int r;
+
+        assert(link);
+
+        log_link_info(link, "Gained IPv6LL");
+
+        link->ipv6ll_address = true;
+        link_check_ready(link);
+
+        if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
+                r = link_acquire_ipv6_conf(link);
+                if (r < 0) {
+                        link_enter_failed(link);
                         return r;
+                }
         }
 
         return 0;
@@ -2236,7 +2498,7 @@ static int link_carrier_gained(Link *link) {
 
         assert(link);
 
-        if (link->network) {
+        if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) {
                 r = link_acquire_conf(link);
                 if (r < 0) {
                         link_enter_failed(link);
@@ -2416,49 +2678,13 @@ int link_update(Link *link, sd_netlink_message *m) {
         return 0;
 }
 
-static void link_update_operstate(Link *link) {
-        LinkOperationalState operstate;
-        assert(link);
-
-        if (link->kernel_operstate == IF_OPER_DORMANT)
-                operstate = LINK_OPERSTATE_DORMANT;
-        else if (link_has_carrier(link)) {
-                Address *address;
-                uint8_t scope = RT_SCOPE_NOWHERE;
-
-                /* if we have carrier, check what addresses we have */
-                LIST_FOREACH(addresses, address, link->addresses) {
-                        if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
-                                continue;
-
-                        if (address->scope < scope)
-                                scope = address->scope;
-                }
-
-                if (scope < RT_SCOPE_SITE)
-                        /* universally accessible addresses found */
-                        operstate = LINK_OPERSTATE_ROUTABLE;
-                else if (scope < RT_SCOPE_HOST)
-                        /* only link or site local addresses found */
-                        operstate = LINK_OPERSTATE_DEGRADED;
-                else
-                        /* no useful addresses found */
-                        operstate = LINK_OPERSTATE_CARRIER;
-        } else if (link->flags & IFF_UP)
-                operstate = LINK_OPERSTATE_NO_CARRIER;
-        else
-                operstate = LINK_OPERSTATE_OFF;
-
-        if (link->operstate != operstate) {
-                link->operstate = operstate;
-                link_send_changed(link, "OperationalState", NULL);
-        }
-}
-
 int link_save(Link *link) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         const char *admin_state, *oper_state;
+        Address *a;
+        Route *route;
+        Iterator i;
         int r;
 
         assert(link);
@@ -2466,12 +2692,6 @@ int link_save(Link *link) {
         assert(link->lease_file);
         assert(link->manager);
 
-        link_update_operstate(link);
-
-        r = manager_save(link->manager);
-        if (r < 0)
-                return r;
-
         if (link->state == LINK_STATE_LINGER) {
                 unlink(link->state_file);
                 return 0;
@@ -2501,9 +2721,8 @@ int link_save(Link *link) {
                 sd_dhcp6_lease *dhcp6_lease = NULL;
 
                 if (link->dhcp6_client) {
-                        r = sd_dhcp6_client_get_lease(link->dhcp6_client,
-                                                      &dhcp6_lease);
-                        if (r < 0)
+                        r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
+                        if (r < 0 && r != -ENOMSG)
                                 log_link_debug(link, "No DHCPv6 lease");
                 }
 
@@ -2542,9 +2761,9 @@ int link_save(Link *link) {
                         }
                 }
 
-                fputs("\n", f);
+                fputc('\n', f);
 
-                fprintf(f, "NTP=");
+                fputs("NTP=", f);
                 space = false;
                 STRV_FOREACH(address, link->network->ntp) {
                         if (space)
@@ -2591,9 +2810,9 @@ int link_save(Link *link) {
                         }
                 }
 
-                fputs("\n", f);
+                fputc('\n', f);
 
-                fprintf(f, "DOMAINS=");
+                fputs("DOMAINS=", f);
                 space = false;
                 STRV_FOREACH(domain, link->network->domains) {
                         if (space)
@@ -2629,18 +2848,48 @@ int link_save(Link *link) {
                         }
                 }
 
-                fputs("\n", f);
+                fputc('\n', f);
 
                 fprintf(f, "WILDCARD_DOMAIN=%s\n",
                         yes_no(link->network->wildcard_domain));
 
                 fprintf(f, "LLMNR=%s\n",
                         resolve_support_to_string(link->network->llmnr));
+
+                fputs("ADDRESSES=", f);
+                space = false;
+                SET_FOREACH(a, link->addresses, i) {
+                        _cleanup_free_ char *address_str = NULL;
+
+                        r = in_addr_to_string(a->family, &a->in_addr, &address_str);
+                        if (r < 0)
+                                goto fail;
+
+                        fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
+                        space = true;
+                }
+
+                fputc('\n', f);
+
+                fputs("ROUTES=", f);
+                space = false;
+                SET_FOREACH(route, link->routes, i) {
+                        _cleanup_free_ char *route_str = NULL;
+
+                        r = in_addr_to_string(route->family, &route->dst, &route_str);
+                        if (r < 0)
+                                goto fail;
+
+                        fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
+                                route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
+                        space = true;
+                }
+
+                fputc('\n', f);
         }
 
         if (!hashmap_isempty(link->bound_to_links)) {
                 Link *carrier;
-                Iterator i;
                 bool space = false;
 
                 fputs("CARRIER_BOUND_TO=", f);
@@ -2651,12 +2900,11 @@ int link_save(Link *link) {
                         space = true;
                 }
 
-                fputs("\n", f);
+                fputc('\n', f);
         }
 
         if (!hashmap_isempty(link->bound_by_links)) {
                 Link *carrier;
-                Iterator i;
                 bool space = false;
 
                 fputs("CARRIER_BOUND_BY=", f);
@@ -2667,19 +2915,25 @@ int link_save(Link *link) {
                         space = true;
                 }
 
-                fputs("\n", f);
+                fputc('\n', f);
         }
 
         if (link->dhcp_lease) {
+                struct in_addr address;
                 const char *tz = NULL;
 
+                assert(link->network);
+
                 r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
                 if (r >= 0)
                         fprintf(f, "TIMEZONE=%s\n", tz);
-        }
 
-        if (link->dhcp_lease) {
-                assert(link->network);
+                r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
+                if (r >= 0) {
+                        fputs("DHCP4_ADDRESS=", f);
+                        serialize_in_addrs(f, &address, 1);
+                        fputc('\n', f);
+                }
 
                 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
                 if (r < 0)
@@ -2691,6 +2945,17 @@ int link_save(Link *link) {
         } else
                 unlink(link->lease_file);
 
+        if (link->ipv4ll) {
+                struct in_addr address;
+
+                r = sd_ipv4ll_get_address(link->ipv4ll, &address);
+                if (r >= 0) {
+                        fputs("IPV4LL_ADDRESS=", f);
+                        serialize_in_addrs(f, &address, 1);
+                        fputc('\n', f);
+                }
+        }
+
         if (link->lldp) {
                 assert(link->network);
 
@@ -2723,6 +2988,34 @@ fail:
         return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
 }
 
+/* The serialized state in /run is no longer up-to-date. */
+void link_dirty(Link *link) {
+        int r;
+
+        assert(link);
+
+        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 */
+                return;
+
+        link_ref(link);
+}
+
+/* The serialized state in /run is up-to-date */
+void link_clean(Link *link) {
+        assert(link);
+        assert(link->manager);
+
+        set_remove(link->manager->dirty_links, link);
+        link_unref(link);
+}
+
 static const char* const link_state_table[_LINK_STATE_MAX] = {
         [LINK_STATE_PENDING] = "pending",
         [LINK_STATE_ENSLAVING] = "configuring",
index 7b219c68542e8cbd94e65445f17ab0c01ac234d1..b564bcbca0c4f4700892e370c788b7eb39638b5a 100644 (file)
 
 #include "sd-dhcp-client.h"
 #include "sd-dhcp-server.h"
-#include "sd-ipv4ll.h"
-#include "sd-icmp6-nd.h"
 #include "sd-dhcp6-client.h"
+#include "sd-ipv4ll.h"
 #include "sd-lldp.h"
+#include "sd-ndisc.h"
 
 typedef struct Link Link;
 
@@ -83,7 +83,10 @@ struct Link {
         unsigned link_messages;
         unsigned enslaving;
 
-        LIST_HEAD(Address, addresses);
+        Set *addresses;
+        Set *addresses_foreign;
+        Set *routes;
+        Set *routes_foreign;
 
         sd_dhcp_client *dhcp_client;
         sd_dhcp_lease *dhcp_lease;
@@ -92,10 +95,13 @@ struct Link {
         unsigned dhcp4_messages;
         bool dhcp4_configured;
         bool dhcp6_configured;
+        unsigned ndisc_messages;
+        bool ndisc_configured;
 
         sd_ipv4ll *ipv4ll;
-        bool ipv4ll_address;
-        bool ipv4ll_route;
+        bool ipv4ll_address:1;
+        bool ipv4ll_route:1;
+        bool ipv6ll_address:1;
 
         bool static_configured;
 
@@ -103,7 +109,7 @@ struct Link {
 
         sd_dhcp_server *dhcp_server;
 
-        sd_icmp6_nd *icmp6_router_discovery;
+        sd_ndisc *ndisc_router_discovery;
         sd_dhcp6_client *dhcp6_client;
         bool rtnl_extended_attrs;
 
@@ -120,29 +126,35 @@ int link_get(Manager *m, int ifindex, Link **ret);
 int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
 void link_drop(Link *link);
 
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
 
 void link_enter_failed(Link *link);
 int link_initialized(Link *link, struct udev_device *device);
 
-void link_client_handler(Link *link);
+void link_check_ready(Link *link);
 
+void link_update_operstate(Link *link);
 int link_update(Link *link, sd_netlink_message *message);
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata);
 
+void link_dirty(Link *link);
+void link_clean(Link *link);
 int link_save(Link *link);
 
 int link_carrier_reset(Link *link);
 bool link_has_carrier(Link *link);
 
+int link_ipv6ll_gained(Link *link);
+
 int link_set_mtu(Link *link, uint32_t mtu);
 int link_set_hostname(Link *link, const char *hostname);
 int link_set_timezone(Link *link, const char *timezone);
 
 int ipv4ll_configure(Link *link);
 int dhcp4_configure(Link *link);
-int icmp6_configure(Link *link);
+int dhcp6_configure(Link *link);
+int dhcp6_request_address(Link *link);
+int ndisc_configure(Link *link);
 
 bool link_lldp_enabled(Link *link);
 bool link_ipv4ll_enabled(Link *link);
@@ -150,6 +162,7 @@ bool link_ipv6ll_enabled(Link *link);
 bool link_dhcp4_server_enabled(Link *link);
 bool link_dhcp4_enabled(Link *link);
 bool link_dhcp6_enabled(Link *link);
+bool link_ipv6_accept_ra_enabled(Link *link);
 
 const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
index b281f4fdb6c693eed704117dae86f2ab5a17fc6f..dafaf2daea61d062b7a2b56f124653744a1cadba 100644 (file)
@@ -19,8 +19,8 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "bus-util.h"
-
 #include "networkd.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
index b4259cafefa57e2162a8f7997b02061efd46cb7d..42f58fed197603ed032c175b9e797f49bff897ba 100644 (file)
 #include <sys/socket.h>
 #include <linux/if.h>
 
-#include "sd-netlink.h"
 #include "sd-daemon.h"
+#include "sd-netlink.h"
 
-#include "conf-parser.h"
-#include "path-util.h"
-#include "libudev-private.h"
-#include "udev-util.h"
-#include "netlink-util.h"
+#include "alloc-util.h"
 #include "bus-util.h"
+#include "conf-parser.h"
 #include "def.h"
-#include "virt.h"
-#include "set.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "libudev-private.h"
 #include "local-addresses.h"
-
+#include "netlink-util.h"
 #include "networkd.h"
+#include "path-util.h"
+#include "set.h"
+#include "udev-util.h"
+#include "virt.h"
 
 /* use 8 MB for receive socket kernel queue. */
 #define RCVBUF_SIZE    (8*1024*1024)
@@ -277,6 +279,350 @@ static int manager_connect_udev(Manager *m) {
         return 0;
 }
 
+int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+        Manager *m = userdata;
+        Link *link = NULL;
+        uint16_t type;
+        uint32_t ifindex, priority = 0;
+        unsigned char protocol, scope, tos, table;
+        int family;
+        unsigned char dst_prefixlen, src_prefixlen;
+        union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
+        Route *route = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(message);
+        assert(m);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_warning_errno(r, "rtnl: failed to receive route: %m");
+
+                return 0;
+        }
+
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type: %m");
+                return 0;
+        } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+                log_warning("rtnl: received unexpected message type when processing route");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
+        if (r == -ENODATA) {
+                log_debug("rtnl: received route without ifindex, ignoring");
+                return 0;
+        } else if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
+                return 0;
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
+                return 0;
+        } else {
+                r = link_get(m, ifindex, &link);
+                if (r < 0 || !link) {
+                        /* when enumerating we might be out of sync, but we will
+                         * get the route again, so just ignore it */
+                        if (!m->enumerating)
+                                log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex);
+                        return 0;
+                }
+        }
+
+        r = sd_rtnl_message_route_get_family(message, &family);
+        if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+                log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_protocol(message, &protocol);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get route protocol: %m");
+                return 0;
+        }
+
+        switch (family) {
+        case AF_INET:
+                r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        case AF_INET6:
+                r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        default:
+                log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_scope(message, &scope);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_tos(message, &tos);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_route_get_table(message, &table);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
+        if (r < 0 && r != -ENODATA) {
+                log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
+                return 0;
+        }
+
+        route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+
+        switch (type) {
+        case RTM_NEWROUTE:
+                if (!route) {
+                        /* A route appeared that we did not request */
+                        r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+                        if (r < 0)
+                                return 0;
+                }
+
+                route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol);
+
+                break;
+
+        case RTM_DELROUTE:
+
+                if (route)
+                        route_drop(route);
+
+                break;
+        default:
+                assert_not_reached("Received invalid RTNL message type");
+        }
+
+        return 1;
+}
+
+int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+        Manager *m = userdata;
+        Link *link = NULL;
+        uint16_t type;
+        unsigned char flags;
+        int family;
+        unsigned char prefixlen;
+        unsigned char scope;
+        union in_addr_union in_addr;
+        struct ifa_cacheinfo cinfo;
+        Address *address = NULL;
+        char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
+        const char *valid_str = NULL;
+        int r, ifindex;
+
+        assert(rtnl);
+        assert(message);
+        assert(m);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_warning_errno(r, "rtnl: failed to receive address: %m");
+
+                return 0;
+        }
+
+        r = sd_netlink_message_get_type(message, &type);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get message type: %m");
+                return 0;
+        } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+                log_warning("rtnl: received unexpected message type when processing address");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
+        if (r < 0) {
+                log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
+                return 0;
+        } else if (ifindex <= 0) {
+                log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
+                return 0;
+        } else {
+                r = link_get(m, ifindex, &link);
+                if (r < 0 || !link) {
+                        /* when enumerating we might be out of sync, but we will
+                         * get the address again, so just ignore it */
+                        if (!m->enumerating)
+                                log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
+                        return 0;
+                }
+        }
+
+        r = sd_rtnl_message_addr_get_family(message, &family);
+        if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+                log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_scope(message, &scope);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_rtnl_message_addr_get_flags(message, &flags);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
+                return 0;
+        }
+
+        switch (family) {
+        case AF_INET:
+                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        case AF_INET6:
+                r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+                        return 0;
+                }
+
+                break;
+
+        default:
+                log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+        }
+
+        if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
+                log_link_warning(link, "Could not print address");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
+        if (r >= 0) {
+                if (cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
+                        valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+                                                    cinfo.ifa_valid * USEC_PER_SEC,
+                                                    USEC_PER_SEC);
+        }
+
+        address_get(link, family, &in_addr, prefixlen, &address);
+
+        switch (type) {
+        case RTM_NEWADDR:
+                if (address)
+                        log_link_debug(link, "Updating address: %s/%u (valid %s%s)", buf, prefixlen,
+                                       valid_str ? "for " : "forever", valid_str ?: "");
+                else {
+                        /* An address appeared that we did not request */
+                        r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
+                                return 0;
+                        } else
+                                log_link_debug(link, "Adding address: %s/%u (valid %s%s)", buf, prefixlen,
+                                               valid_str ? "for " : "forever", valid_str ?: "");
+                }
+
+                address_update(address, flags, scope, &cinfo);
+
+                break;
+
+        case RTM_DELADDR:
+
+                if (address) {
+                        log_link_debug(link, "Removing address: %s/%u (valid %s%s)", buf, prefixlen,
+                                       valid_str ? "for " : "forever", valid_str ?: "");
+                        address_drop(address);
+                } else
+                        log_link_warning(link, "Removing non-existent address: %s/%u (valid %s%s)", buf, prefixlen,
+                                         valid_str ? "for " : "forever", valid_str ?: "");
+
+                break;
+        default:
+                assert_not_reached("Received invalid RTNL message type");
+        }
+
+        return 1;
+}
+
 static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
@@ -410,80 +756,291 @@ static int manager_connect_rtnl(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m);
         if (r < 0)
                 return r;
 
-        return 0;
-}
-
-int manager_new(Manager **ret) {
-        _cleanup_manager_free_ Manager *m = NULL;
-        int r;
-
-        m = new0(Manager, 1);
-        if (!m)
-                return -ENOMEM;
-
-        m->state_file = strdup("/run/systemd/netif/state");
-        if (!m->state_file)
-                return -ENOMEM;
-
-        r = sd_event_default(&m->event);
+        r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m);
         if (r < 0)
                 return r;
 
-        sd_event_set_watchdog(m->event, true);
-
-        sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
-        sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
-
-        r = manager_connect_rtnl(m);
+        r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m);
         if (r < 0)
                 return r;
 
-        r = manager_connect_udev(m);
-        if (r < 0)
-                return r;
+        return 0;
+}
 
-        m->netdevs = hashmap_new(&string_hash_ops);
-        if (!m->netdevs)
-                return -ENOMEM;
+static int set_put_in_addr(Set *s, const struct in_addr *address) {
+        char *p;
+        int r;
 
-        LIST_HEAD_INIT(m->networks);
+        assert(s);
 
-        r = setup_default_address_pool(m);
+        r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
         if (r < 0)
                 return r;
 
-        *ret = m;
-        m = NULL;
+        r = set_consume(s, p);
+        if (r == -EEXIST)
+                return 0;
 
-        return 0;
+        return r;
 }
 
-void manager_free(Manager *m) {
-        Network *network;
-        NetDev *netdev;
-        Link *link;
-        AddressPool *pool;
+static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
+        int r, i, c = 0;
 
-        if (!m)
+        assert(s);
+        assert(n <= 0 || addresses);
+
+        for (i = 0; i < n; i++) {
+                r = set_put_in_addr(s, addresses+i);
+                if (r < 0)
+                        return r;
+
+                c += r;
+        }
+
+        return c;
+}
+
+static void print_string_set(FILE *f, const char *field, Set *s) {
+        bool space = false;
+        Iterator i;
+        char *p;
+
+        if (set_isempty(s))
                 return;
 
-        free(m->state_file);
+        fputs(field, f);
 
-        sd_event_source_unref(m->udev_event_source);
-        udev_monitor_unref(m->udev_monitor);
-        udev_unref(m->udev);
+        SET_FOREACH(p, s, i) {
+                if (space)
+                        fputc(' ', f);
+                fputs(p, f);
+                space = true;
+        }
+        fputc('\n', f);
+}
 
-        sd_bus_unref(m->bus);
-        sd_bus_slot_unref(m->prepare_for_sleep_slot);
-        sd_event_source_unref(m->bus_retry_event_source);
+static int manager_save(Manager *m) {
+        _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
+        Link *link;
+        Iterator i;
+        _cleanup_free_ char *temp_path = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        LinkOperationalState operstate = LINK_OPERSTATE_OFF;
+        const char *operstate_str;
+        int r;
+
+        assert(m);
+        assert(m->state_file);
+
+        /* We add all NTP and DNS server to a set, to filter out duplicates */
+        dns = set_new(&string_hash_ops);
+        if (!dns)
+                return -ENOMEM;
+
+        ntp = set_new(&string_hash_ops);
+        if (!ntp)
+                return -ENOMEM;
+
+        domains = set_new(&string_hash_ops);
+        if (!domains)
+                return -ENOMEM;
+
+        HASHMAP_FOREACH(link, m->links, i) {
+                if (link->flags & IFF_LOOPBACK)
+                        continue;
+
+                if (link->operstate > operstate)
+                        operstate = link->operstate;
+
+                if (!link->network)
+                        continue;
+
+                /* First add the static configured entries */
+                r = set_put_strdupv(dns, link->network->dns);
+                if (r < 0)
+                        return r;
+
+                r = set_put_strdupv(ntp, link->network->ntp);
+                if (r < 0)
+                        return r;
+
+                r = set_put_strdupv(domains, link->network->domains);
+                if (r < 0)
+                        return r;
+
+                if (!link->dhcp_lease)
+                        continue;
+
+                /* Secondly, add the entries acquired via DHCP */
+                if (link->network->dhcp_dns) {
+                        const struct in_addr *addresses;
+
+                        r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
+                        if (r > 0) {
+                                r = set_put_in_addrv(dns, addresses, r);
+                                if (r < 0)
+                                        return r;
+                        } else if (r < 0 && r != -ENODATA)
+                                return r;
+                }
+
+                if (link->network->dhcp_ntp) {
+                        const struct in_addr *addresses;
+
+                        r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
+                        if (r > 0) {
+                                r = set_put_in_addrv(ntp, addresses, r);
+                                if (r < 0)
+                                        return r;
+                        } else if (r < 0 && r != -ENODATA)
+                                return r;
+                }
+
+                if (link->network->dhcp_domains) {
+                        const char *domainname;
+
+                        r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
+                        if (r >= 0) {
+                                r = set_put_strdup(domains, domainname);
+                                if (r < 0)
+                                        return r;
+                        } else if (r != -ENODATA)
+                                return r;
+                }
+        }
+
+        operstate_str = link_operstate_to_string(operstate);
+        assert(operstate_str);
+
+        r = fopen_temporary(m->state_file, &f, &temp_path);
+        if (r < 0)
+                return r;
+
+        fchmod(fileno(f), 0644);
+
+        fprintf(f,
+                "# This is private data. Do not parse.\n"
+                "OPER_STATE=%s\n", operstate_str);
+
+        print_string_set(f, "DNS=", dns);
+        print_string_set(f, "NTP=", ntp);
+        print_string_set(f, "DOMAINS=", domains);
+
+        r = fflush_and_check(f);
+        if (r < 0)
+                goto fail;
+
+        if (rename(temp_path, m->state_file) < 0) {
+                r = -errno;
+                goto fail;
+        }
+
+        if (m->operational_state != operstate) {
+                m->operational_state = operstate;
+                r = manager_send_changed(m, "OperationalState", NULL);
+                if (r < 0)
+                        log_error_errno(r, "Could not emit changed OperationalState: %m");
+        }
+
+        m->dirty = false;
+
+        return 0;
+
+fail:
+        (void) unlink(m->state_file);
+        (void) unlink(temp_path);
+
+        return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
+}
+
+static int manager_dirty_handler(sd_event_source *s, void *userdata) {
+        Manager *m = userdata;
+        Link *link;
+        Iterator i;
+        int r;
+
+        assert(m);
+
+        if (m->dirty)
+                manager_save(m);
+
+        SET_FOREACH(link, m->dirty_links, i) {
+                r = link_save(link);
+                if (r >= 0)
+                        link_clean(link);
+        }
+
+        return 1;
+}
+
+int manager_new(Manager **ret) {
+        _cleanup_manager_free_ Manager *m = NULL;
+        int r;
+
+        m = new0(Manager, 1);
+        if (!m)
+                return -ENOMEM;
+
+        m->state_file = strdup("/run/systemd/netif/state");
+        if (!m->state_file)
+                return -ENOMEM;
+
+        r = sd_event_default(&m->event);
+        if (r < 0)
+                return r;
+
+        sd_event_set_watchdog(m->event, true);
+
+        sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
+        sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+
+        r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
+        if (r < 0)
+                return r;
+
+        r = manager_connect_rtnl(m);
+        if (r < 0)
+                return r;
+
+        r = manager_connect_udev(m);
+        if (r < 0)
+                return r;
+
+        m->netdevs = hashmap_new(&string_hash_ops);
+        if (!m->netdevs)
+                return -ENOMEM;
+
+        LIST_HEAD_INIT(m->networks);
+
+        r = setup_default_address_pool(m);
+        if (r < 0)
+                return r;
+
+        *ret = m;
+        m = NULL;
+
+        return 0;
+}
+
+void manager_free(Manager *m) {
+        Network *network;
+        NetDev *netdev;
+        Link *link;
+        AddressPool *pool;
+
+        if (!m)
+                return;
+
+        free(m->state_file);
 
         while ((link = hashmap_first(m->links)))
                 link_unref(link);
@@ -504,6 +1061,14 @@ void manager_free(Manager *m) {
         sd_netlink_unref(m->rtnl);
         sd_event_unref(m->event);
 
+        sd_event_source_unref(m->udev_event_source);
+        udev_monitor_unref(m->udev_monitor);
+        udev_unref(m->udev);
+
+        sd_bus_unref(m->bus);
+        sd_bus_slot_unref(m->prepare_for_sleep_slot);
+        sd_event_source_unref(m->bus_retry_event_source);
+
         free(m);
 }
 
@@ -528,7 +1093,8 @@ static bool manager_check_idle(void *userdata) {
                     link_ipv4ll_enabled(link) ||
                     link_dhcp4_server_enabled(link) ||
                     link_dhcp4_enabled(link) ||
-                    link_dhcp6_enabled(link))
+                    link_dhcp6_enabled(link) ||
+                    link_ipv6_accept_ra_enabled(link))
                         return false;
         }
 
@@ -536,8 +1102,19 @@ static bool manager_check_idle(void *userdata) {
 }
 
 int manager_run(Manager *m) {
+        Link *link;
+        Iterator i;
+
         assert(m);
 
+        /* The dirty handler will deal with future serialization, but the first one
+           must be done explicitly. */
+
+        manager_save(m);
+
+        HASHMAP_FOREACH(link, m->links, i)
+                link_save(link);
+
         if (m->bus)
                 return bus_event_loop_with_idle(
                                 m->event,
@@ -633,7 +1210,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
 
                 m->enumerating = true;
 
-                k = link_rtnl_process_address(m->rtnl, addr, m);
+                k = manager_rtnl_process_address(m->rtnl, addr, m);
                 if (k < 0)
                         r = k;
 
@@ -643,189 +1220,39 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
         return r;
 }
 
-static int set_put_in_addr(Set *s, const struct in_addr *address) {
-        char *p;
+int manager_rtnl_enumerate_routes(Manager *m) {
+        _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+        sd_netlink_message *route;
         int r;
 
-        assert(s);
+        assert(m);
+        assert(m->rtnl);
 
-        r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
+        r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
         if (r < 0)
                 return r;
 
-        r = set_consume(s, p);
-        if (r == -EEXIST)
-                return 0;
-
-        return r;
-}
-
-static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
-        int r, i, c = 0;
-
-        assert(s);
-        assert(n <= 0 || addresses);
-
-        for (i = 0; i < n; i++) {
-                r = set_put_in_addr(s, addresses+i);
-                if (r < 0)
-                        return r;
-
-                c += r;
-        }
-
-        return c;
-}
-
-static void print_string_set(FILE *f, const char *field, Set *s) {
-        bool space = false;
-        Iterator i;
-        char *p;
-
-        if (set_isempty(s))
-                return;
-
-        fputs(field, f);
-
-        SET_FOREACH(p, s, i) {
-                if (space)
-                        fputc(' ', f);
-                fputs(p, f);
-                space = true;
-        }
-        fputc('\n', f);
-}
-
-int manager_save(Manager *m) {
-        _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
-        Link *link;
-        Iterator i;
-        _cleanup_free_ char *temp_path = NULL;
-        _cleanup_fclose_ FILE *f = NULL;
-        LinkOperationalState operstate = LINK_OPERSTATE_OFF;
-        const char *operstate_str;
-        int r;
-
-        assert(m);
-        assert(m->state_file);
-
-        /* We add all NTP and DNS server to a set, to filter out duplicates */
-        dns = set_new(&string_hash_ops);
-        if (!dns)
-                return -ENOMEM;
-
-        ntp = set_new(&string_hash_ops);
-        if (!ntp)
-                return -ENOMEM;
-
-        domains = set_new(&string_hash_ops);
-        if (!domains)
-                return -ENOMEM;
-
-        HASHMAP_FOREACH(link, m->links, i) {
-                if (link->flags & IFF_LOOPBACK)
-                        continue;
-
-                if (link->operstate > operstate)
-                        operstate = link->operstate;
-
-                if (!link->network)
-                        continue;
-
-                /* First add the static configured entries */
-                r = set_put_strdupv(dns, link->network->dns);
-                if (r < 0)
-                        return r;
-
-                r = set_put_strdupv(ntp, link->network->ntp);
-                if (r < 0)
-                        return r;
-
-                r = set_put_strdupv(domains, link->network->domains);
-                if (r < 0)
-                        return r;
-
-                if (!link->dhcp_lease)
-                        continue;
-
-                /* Secondly, add the entries acquired via DHCP */
-                if (link->network->dhcp_dns) {
-                        const struct in_addr *addresses;
-
-                        r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                r = set_put_in_addrv(dns, addresses, r);
-                                if (r < 0)
-                                        return r;
-                        } else if (r < 0 && r != -ENODATA)
-                                return r;
-                }
-
-                if (link->network->dhcp_ntp) {
-                        const struct in_addr *addresses;
-
-                        r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                r = set_put_in_addrv(ntp, addresses, r);
-                                if (r < 0)
-                                        return r;
-                        } else if (r < 0 && r != -ENODATA)
-                                return r;
-                }
-
-                if (link->network->dhcp_domains) {
-                        const char *domainname;
-
-                        r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
-                        if (r >= 0) {
-                                r = set_put_strdup(domains, domainname);
-                                if (r < 0)
-                                        return r;
-                        } else if (r != -ENODATA)
-                                return r;
-                }
-        }
-
-        operstate_str = link_operstate_to_string(operstate);
-        assert(operstate_str);
-
-        r = fopen_temporary(m->state_file, &f, &temp_path);
+        r = sd_netlink_message_request_dump(req, true);
         if (r < 0)
                 return r;
 
-        fchmod(fileno(f), 0644);
-
-        fprintf(f,
-                "# This is private data. Do not parse.\n"
-                "OPER_STATE=%s\n", operstate_str);
-
-        print_string_set(f, "DNS=", dns);
-        print_string_set(f, "NTP=", ntp);
-        print_string_set(f, "DOMAINS=", domains);
-
-        r = fflush_and_check(f);
+        r = sd_netlink_call(m->rtnl, req, 0, &reply);
         if (r < 0)
-                goto fail;
+                return r;
 
-        if (rename(temp_path, m->state_file) < 0) {
-                r = -errno;
-                goto fail;
-        }
+        for (route = reply; route; route = sd_netlink_message_next(route)) {
+                int k;
 
-        if (m->operational_state != operstate) {
-                m->operational_state = operstate;
-                r = manager_send_changed(m, "OperationalState", NULL);
-                if (r < 0)
-                        log_error_errno(r, "Could not emit changed OperationalState: %m");
-        }
+                m->enumerating = true;
 
-        return 0;
+                k = manager_rtnl_process_route(m->rtnl, route, m);
+                if (k < 0)
+                        r = k;
 
-fail:
-        (void) unlink(m->state_file);
-        (void) unlink(temp_path);
+                m->enumerating = false;
+        }
 
-        return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
+        return r;
 }
 
 int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
@@ -884,3 +1311,10 @@ Link* manager_find_uplink(Manager *m, Link *exclude) {
 
         return NULL;
 }
+
+void manager_dirty(Manager *manager) {
+        assert(manager);
+
+        /* the serialized state in /run is no longer up-to-date */
+        manager->dirty = true;
+}
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
new file mode 100644 (file)
index 0000000..126f9c0
--- /dev/null
@@ -0,0 +1,247 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  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 <netinet/ether.h>
+#include <netinet/icmp6.h>
+#include <linux/if.h>
+
+#include "sd-ndisc.h"
+
+#include "networkd-link.h"
+
+static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+        _cleanup_link_unref_ Link *link = userdata;
+        int r;
+
+        assert(link);
+        assert(link->ndisc_messages > 0);
+
+        link->ndisc_messages --;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EEXIST) {
+                log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
+                link_enter_failed(link);
+        }
+
+        if (link->ndisc_messages == 0) {
+                link->ndisc_configured = true;
+                link_check_ready(link);
+        }
+
+        return 1;
+}
+
+static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
+                                            unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) {
+        _cleanup_address_free_ Address *address = NULL;
+        Link *link = userdata;
+        usec_t time_now;
+        int r;
+
+        assert(nd);
+        assert(link);
+        assert(link->network);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
+        r = address_new(&address);
+        if (r < 0) {
+                log_link_error_errno(link, r, "Could not allocate address: %m");
+                return;
+        }
+
+        assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+        address->family = AF_INET6;
+        address->in_addr.in6 = *prefix;
+        if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
+                memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8);
+        else {
+                /* see RFC4291 section 2.5.1 */
+                address->in_addr.in6.__in6_u.__u6_addr8[8]  = link->mac.ether_addr_octet[0];
+                address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1;
+                address->in_addr.in6.__in6_u.__u6_addr8[9]  = link->mac.ether_addr_octet[1];
+                address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2];
+                address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff;
+                address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe;
+                address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3];
+                address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4];
+                address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5];
+        }
+        address->prefixlen = prefixlen;
+        address->flags = IFA_F_NOPREFIXROUTE;
+        address->cinfo.ifa_prefered = lifetime_preferred;
+        address->cinfo.ifa_valid = lifetime_valid;
+
+        r = address_configure(address, link, ndisc_netlink_handler, true);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
+                link_enter_failed(link);
+                return;
+        }
+
+        link->ndisc_messages ++;
+}
+
+static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
+        _cleanup_route_free_ Route *route = NULL;
+        Link *link = userdata;
+        usec_t time_now;
+        int r;
+
+        assert(nd);
+        assert(link);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
+        r = route_new(&route);
+        if (r < 0) {
+                log_link_error_errno(link, r, "Could not allocate route: %m");
+                return;
+        }
+
+        assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+        route->family = AF_INET6;
+        route->table = RT_TABLE_MAIN;
+        route->protocol = RTPROT_RA;
+        route->flags = RTM_F_PREFIX;
+        route->dst.in6 = *prefix;
+        route->dst_prefixlen = prefixlen;
+        route->lifetime = time_now + lifetime * USEC_PER_SEC;
+
+        r = route_configure(route, link, ndisc_netlink_handler);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Could not set prefix route: %m");
+                link_enter_failed(link);
+                return;
+        }
+
+        link->ndisc_messages ++;
+}
+
+static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
+        _cleanup_route_free_ Route *route = NULL;
+        Link *link = userdata;
+        usec_t time_now;
+        int r;
+
+        assert(link);
+        assert(link->network);
+        assert(link->manager);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
+        if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
+                if (flags & ND_RA_FLAG_MANAGED)
+                        dhcp6_request_address(link);
+
+                r = sd_dhcp6_client_start(link->dhcp6_client);
+                if (r < 0 && r != -EALREADY)
+                        log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
+        }
+
+        if (!gateway)
+                return;
+
+        r = route_new(&route);
+        if (r < 0) {
+                log_link_error_errno(link, r, "Could not allocate route: %m");
+                return;
+        }
+
+        assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+        route->family = AF_INET6;
+        route->table = RT_TABLE_MAIN;
+        route->protocol = RTPROT_RA;
+        route->pref = pref;
+        route->gw.in6 = *gateway;
+        route->lifetime = time_now + lifetime * USEC_PER_SEC;
+
+        r = route_configure(route, link, ndisc_netlink_handler);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Could not set default route: %m");
+                link_enter_failed(link);
+                return;
+        }
+
+        link->ndisc_messages ++;
+}
+
+static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
+        Link *link = userdata;
+        int r;
+
+        assert(link);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
+        switch (event) {
+        case SD_NDISC_EVENT_TIMEOUT:
+                dhcp6_request_address(link);
+
+                r = sd_dhcp6_client_start(link->dhcp6_client);
+                if (r < 0 && r != -EALREADY)
+                        log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
+                break;
+        case SD_NDISC_EVENT_STOP:
+                break;
+        default:
+                log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
+        }
+}
+
+int ndisc_configure(Link *link) {
+        int r;
+
+        assert_return(link, -EINVAL);
+
+        r = sd_ndisc_new(&link->ndisc_router_discovery);
+        if (r < 0)
+                return r;
+
+        r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
+        if (r < 0)
+                return r;
+
+        r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
+        if (r < 0)
+                return r;
+
+        r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);
+        if (r < 0)
+                return r;
+
+        r = sd_ndisc_set_callback(link->ndisc_router_discovery,
+                                  ndisc_router_handler,
+                                  ndisc_prefix_onlink_handler,
+                                  ndisc_prefix_autonomous_handler,
+                                  ndisc_handler,
+                                  link);
+
+        return r;
+}
index bcaba57937a8dbb8ed3728fa1d0dc7555115e4d4..4e4755f86f92fb1e984dfae7f1834b34876287d8 100644 (file)
 #include <netinet/ether.h>
 #include <linux/if_bonding.h>
 
-#include "conf-parser.h"
 #include "sd-netlink.h"
-#include "networkd-netdev-bond.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
 #include "missing.h"
+#include "networkd-netdev-bond.h"
+#include "string-util.h"
+#include "string-table.h"
 
 /*
  * Number of seconds between instances where the bonding
@@ -178,15 +182,18 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
 }
 
 static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Bond *b = BOND(netdev);
+        Bond *b;
         ArpIpTarget *target = NULL;
         int r, i = 0;
 
         assert(netdev);
         assert(!link);
-        assert(b);
         assert(m);
 
+        b = BOND(netdev);
+
+        assert(b);
+
         if (b->mode != _NETDEV_BOND_MODE_INVALID) {
                 r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
                                               bond_mode_to_kernel(b->mode));
@@ -333,8 +340,6 @@ int config_parse_arp_ip_target_address(const char *unit,
                                        void *data,
                                        void *userdata) {
         Bond *b = userdata;
-        const char *word, *state;
-        size_t l;
         int r;
 
         assert(filename);
@@ -342,14 +347,19 @@ int config_parse_arp_ip_target_address(const char *unit,
         assert(rvalue);
         assert(data);
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
+        for (;;) {
                 _cleanup_free_ ArpIpTarget *buffer = NULL;
                 _cleanup_free_ char *n = NULL;
                 int f;
 
-                n = strndup(word, l);
-                if (!n)
-                        return -ENOMEM;
+                r = extract_first_word(&rvalue, &n, NULL, 0);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
+
+                if (r == 0)
+                        break;
 
                 buffer = new0(ArpIpTarget, 1);
                 if (!buffer)
@@ -373,16 +383,21 @@ int config_parse_arp_ip_target_address(const char *unit,
         }
 
         if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
-                log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
+                           b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
 
         return 0;
 }
 
 static void bond_done(NetDev *netdev) {
         ArpIpTarget *t = NULL, *n = NULL;
-        Bond *b = BOND(netdev);
+        Bond *b;
 
         assert(netdev);
+
+        b = BOND(netdev);
+
         assert(b);
 
         LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
@@ -392,9 +407,12 @@ static void bond_done(NetDev *netdev) {
 }
 
 static void bond_init(NetDev *netdev) {
-        Bond *b = BOND(netdev);
+        Bond *b;
 
         assert(netdev);
+
+        b = BOND(netdev);
+
         assert(b);
 
         b->mode = _NETDEV_BOND_MODE_INVALID;
index 2eeb86a683b0ea0d787c3cfa9451a67a008e71b2..57c58d83b4c33bfffe3ebbc2a1d101566e194015 100644 (file)
@@ -72,20 +72,21 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
+        /* convert to jiffes */
         if (b->forward_delay > 0) {
-                r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, b->forward_delay / USEC_PER_SEC);
+                r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
         }
 
         if (b->hello_time > 0) {
-                r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, b->hello_time / USEC_PER_SEC );
+                r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
         }
 
         if (b->max_age > 0) {
-                r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, b->max_age / USEC_PER_SEC);
+                r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
         }
index 4aac2398503b4962a41c25a19f229fc3aa62a49f..4a4b400e416793c8782151090564efd2a18e974e 100644 (file)
@@ -56,6 +56,7 @@ VXLAN.UDP6ZeroCheckSumRx,    config_parse_bool,                  0,
 VXLAN.UDP6ZeroCheckSumTx,    config_parse_bool,                  0,                             offsetof(VxLan, udp6zerocsumtx)
 VXLAN.FDBAgeingSec,          config_parse_sec,                   0,                             offsetof(VxLan, fdb_ageing)
 VXLAN.GroupPolicyExtension,  config_parse_bool,                  0,                             offsetof(VxLan, group_policy)
+VXLAN.MaximumFDBEntries,     config_parse_unsigned,              0,                             offsetof(VxLan, max_fdb)
 Tun.OneQueue,                config_parse_bool,                  0,                             offsetof(TunTap, one_queue)
 Tun.MultiQueue,              config_parse_bool,                  0,                             offsetof(TunTap, multi_queue)
 Tun.PacketInfo,              config_parse_bool,                  0,                             offsetof(TunTap, packet_info)
index 5eb4a1eb36a32b7f8804bc304f6e1b1d4117a23e..27cb7d1bf012da15f4921793329436f80ea04ff8 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <net/if.h>
 
-#include "networkd-netdev-ipvlan.h"
 #include "conf-parser.h"
+#include "networkd-netdev-ipvlan.h"
+#include "string-table.h"
 
 static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
         [NETDEV_IPVLAN_MODE_L2] = "L2",
@@ -33,14 +34,17 @@ DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
 
 static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
-        IPVlan *m = IPVLAN(netdev);
+        IPVlan *m;
         int r;
 
         assert(netdev);
-        assert(m);
         assert(link);
         assert(netdev->ifname);
 
+        m = IPVLAN(netdev);
+
+        assert(m);
+
         if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) {
                 r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode);
                 if (r < 0)
@@ -51,9 +55,12 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netl
 }
 
 static void ipvlan_init(NetDev *n) {
-        IPVlan *m = IPVLAN(n);
+        IPVlan *m;
 
         assert(n);
+
+        m = IPVLAN(n);
+
         assert(m);
 
         m->mode = _NETDEV_IPVLAN_MODE_INVALID;
index e17de793ce64afd3d30e1a1f6f06582714612a87..7144823b2da17d47ea344a42d5a7de56ff2c3792 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <net/if.h>
 
-#include "networkd-netdev-macvlan.h"
 #include "conf-parser.h"
+#include "networkd-netdev-macvlan.h"
+#include "string-table.h"
 
 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
         [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
index c9b7fa96e27977913ffa80fcb6470d70ec2674e4..385338849f40a317495c760a994c5a2b4d7e9474 100644 (file)
 #include <linux/ip6_tunnel.h>
 
 #include "sd-netlink.h"
-#include "networkd-netdev-tunnel.h"
+
+#include "conf-parser.h"
+#include "missing.h"
 #include "networkd-link.h"
+#include "networkd-netdev-tunnel.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "util.h"
-#include "missing.h"
-#include "conf-parser.h"
 
 #define DEFAULT_TNL_HOP_LIMIT   64
 #define IP6_FLOWINFO_FLOWLABEL  htonl(0x000FFFFF)
index 6a808b6205bccc396b46fcfb751a5b25e1748867..851e83537e7cf66964ebe0a78f81f5898089c95e 100644 (file)
 #include <net/if.h>
 #include <linux/if_tun.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "networkd-netdev-tuntap.h"
+#include "user-util.h"
 
 #define TUN_DEV "/dev/net/tun"
 
index e20f9f74e2ed9edd95f59da8b580507f98e5a520..bee1a167263379701dacacb8209792c3dac93854 100644 (file)
 #include "networkd-netdev-veth.h"
 
 static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Veth *v = VETH(netdev);
+        Veth *v;
         int r;
 
         assert(netdev);
         assert(!link);
-        assert(v);
         assert(m);
 
+        v = VETH(netdev);
+
+        assert(v);
+
         r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m");
@@ -58,13 +61,16 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin
 }
 
 static int netdev_veth_verify(NetDev *netdev, const char *filename) {
-        Veth *v = VETH(netdev);
+        Veth *v;
         int r;
 
         assert(netdev);
-        assert(v);
         assert(filename);
 
+        v = VETH(netdev);
+
+        assert(v);
+
         if (!v->ifname_peer) {
                 log_warning("Veth NetDev without peer name configured in %s. Ignoring",
                             filename);
@@ -84,9 +90,12 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) {
 }
 
 static void veth_done(NetDev *n) {
-        Veth *v = VETH(n);
+        Veth *v;
 
         assert(n);
+
+        v = VETH(n);
+
         assert(v);
 
         free(v->ifname_peer);
index 195d1a944e522a1c20d3570020134673f6c394b7..75fbdd355ed42bf57f52091db61db9daae4ca056 100644 (file)
 #include "networkd-netdev-vlan.h"
 
 static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
-        VLan *v = VLAN(netdev);
+        VLan *v;
         int r;
 
         assert(netdev);
-        assert(v);
         assert(link);
         assert(req);
 
+        v = VLAN(netdev);
+
+        assert(v);
+
         if (v->id <= VLANID_MAX) {
                 r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
                 if (r < 0)
@@ -42,12 +45,15 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin
 }
 
 static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
-        VLan *v = VLAN(netdev);
+        VLan *v;
 
         assert(netdev);
-        assert(v);
         assert(filename);
 
+        v = VLAN(netdev);
+
+        assert(v);
+
         if (v->id > VLANID_MAX) {
                 log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename);
                 return -EINVAL;
index 03a599c0d47851af3780b4a8ea6ba561a0457523..755ad2f9347485c644175b77c2500f89d95def8e 100644 (file)
 #include "missing.h"
 
 static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        VxLan *v = VXLAN(netdev);
+        VxLan *v;
         int r;
 
         assert(netdev);
-        assert(v);
         assert(link);
         assert(m);
 
+        v = VXLAN(netdev);
+
+        assert(v);
 
         if (v->id <= VXLAN_VID_MAX) {
                 r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id);
@@ -89,6 +91,12 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
         }
 
+        if (v->max_fdb) {
+                r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m");
+        }
+
         r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_CSUM attribute: %m");
@@ -162,9 +170,12 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
 }
 
 static void vxlan_init(NetDev *netdev) {
-        VxLan *v = VXLAN(netdev);
+        VxLan *v;
 
         assert(netdev);
+
+        v = VXLAN(netdev);
+
         assert(v);
 
         v->id = VXLAN_VID_MAX + 1;
index 4ec33946cce6b6cc56e3079c255a1d7250aafaff..d21f355f5dce4a82618e424507185ad8bc588dcd 100644 (file)
@@ -39,6 +39,7 @@ struct VxLan {
 
         unsigned tos;
         unsigned ttl;
+        unsigned max_fdb;
 
         usec_t fdb_ageing;
 
index 3d4865a780b98f435c33125ff98277a55e39fc8f..dd0b400c6a0a8cb1337837e9b7cd4bc7c6582c33 100644 (file)
 
 #include <net/if.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "fd-util.h"
 #include "list.h"
-#include "siphash24.h"
 #include "netlink-util.h"
 #include "network-internal.h"
-
-#include "networkd.h"
 #include "networkd-netdev.h"
+#include "networkd.h"
+#include "siphash24.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
 
 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
 
index 5717a153273ef21061981e29836be563ba679a92..120760a986d3ef696be1f0494a3e07cea1fae484 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "strv.h"
-
+#include "alloc-util.h"
 #include "networkd.h"
+#include "string-util.h"
+#include "strv.h"
 
 static int property_get_ether_addrs(
                 sd_bus *bus,
index b6f70e191dee7056f0d475f1ada4a7928c587160..de2c66d15372493d8a8f215844ef09b4618adb26 100644 (file)
@@ -51,6 +51,8 @@ Network.IPForward,                      config_parse_address_family_boolean_with
 Network.IPMasquerade,                   config_parse_bool,                              0,                             offsetof(Network, ip_masquerade)
 Network.IPv6PrivacyExtensions,          config_parse_ipv6_privacy_extensions,           0,                             offsetof(Network, 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.BindCarrier,                    config_parse_strv,                              0,                             offsetof(Network, bind_carrier)
 Address.Address,                        config_parse_address,                           0,                             0
 Address.Peer,                           config_parse_address,                           0,                             0
index 5d22598fc02730a96bc6cb743e1216b5db5409b4..29723a852fb6d32a951a14803518f81a2cf29a16 100644 (file)
 #include <ctype.h>
 #include <net/if.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
-#include "util.h"
-#include "hostname-util.h"
 #include "dns-domain.h"
+#include "fd-util.h"
+#include "hostname-util.h"
 #include "network-internal.h"
-
-#include "networkd.h"
 #include "networkd-network.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
 
 static int network_load_one(Manager *manager, const char *filename) {
         _cleanup_network_free_ Network *network = NULL;
@@ -121,6 +126,8 @@ static int network_load_one(Manager *manager, const char *filename) {
 
         network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
         network->ipv6_accept_ra = -1;
+        network->ipv6_dad_transmits = -1;
+        network->ipv6_hop_limit = -1;
 
         r = config_parse(NULL, filename, file,
                          "Match\0"
@@ -326,12 +333,12 @@ int network_get(Manager *manager, struct udev_device *device,
                                         (void) safe_atou8(attr, &name_assign_type);
 
                                 if (name_assign_type == NET_NAME_ENUM)
-                                        log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
-                                                    IFNAMSIZ, ifname, network->filename);
+                                        log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
+                                                    ifname, network->filename);
                                 else
-                                        log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+                                        log_debug("%s: found matching network '%s'", ifname, network->filename);
                         } else
-                                log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+                                log_debug("%s: found matching network '%s'", ifname, network->filename);
 
                         *ret = network;
                         return 0;
@@ -346,6 +353,10 @@ int network_get(Manager *manager, struct udev_device *device,
 int network_apply(Manager *manager, Network *network, Link *link) {
         int r;
 
+        assert(manager);
+        assert(network);
+        assert(link);
+
         link->network = network;
 
         if (network->ipv4ll_route) {
@@ -355,7 +366,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
                 if (r < 0)
                         return r;
 
-                r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
+                r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
                 if (r == 0)
                         return -EINVAL;
                 if (r < 0)
@@ -364,14 +375,13 @@ int network_apply(Manager *manager, Network *network, Link *link) {
                 route->family = AF_INET;
                 route->dst_prefixlen = 16;
                 route->scope = RT_SCOPE_LINK;
-                route->metrics = IPV4LL_ROUTE_METRIC;
+                route->priority = IPV4LL_ROUTE_METRIC;
                 route->protocol = RTPROT_STATIC;
         }
 
-        if (network->dns || network->ntp) {
-                r = link_save(link);
-                if (r < 0)
-                        return r;
+        if (network->dns || network->ntp || network->domains) {
+                manager_dirty(manager);
+                link_dirty(link);
         }
 
         return 0;
index 2a43b6b347e0bbceed605e0b3a2edea5733ecb03..a27c67eea58e7f3bf998af8daf9c163385d3a5dc 100644 (file)
@@ -121,6 +121,8 @@ struct Network {
         bool ip_masquerade;
 
         int ipv6_accept_ra;
+        int ipv6_dad_transmits;
+        int ipv6_hop_limit;
 
         union in_addr_union ipv6_token;
         IPv6PrivacyExtensions ipv6_privacy_extensions;
index ee1ddd81fe84c6983986e2a1ed94a9dce688199f..ed06c21160b5ea89e19094b0043994883fb9793b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
 #include "conf-parser.h"
+#include "event-util.h"
+#include "in-addr-util.h"
 #include "netlink-util.h"
-
-#include "networkd.h"
 #include "networkd-route.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "util.h"
+
+int route_new(Route **ret) {
+        _cleanup_route_free_ Route *route = NULL;
+
+        route = new0(Route, 1);
+        if (!route)
+                return -ENOMEM;
+
+        route->family = AF_UNSPEC;
+        route->scope = RT_SCOPE_UNIVERSE;
+        route->protocol = RTPROT_UNSPEC;
+        route->table = RT_TABLE_DEFAULT;
+        route->lifetime = USEC_INFINITY;
+
+        *ret = route;
+        route = NULL;
+
+        return 0;
+}
 
 int route_new_static(Network *network, unsigned section, Route **ret) {
         _cleanup_route_free_ Route *route = NULL;
+        int r;
 
         if (section) {
                 route = hashmap_get(network->routes_by_section,
@@ -40,14 +65,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
                 }
         }
 
-        route = new0(Route, 1);
-        if (!route)
-                return -ENOMEM;
+        r = route_new(&route);
+        if (r < 0)
+                return r;
 
-        route->family = AF_UNSPEC;
-        route->scope = RT_SCOPE_UNIVERSE;
         route->protocol = RTPROT_STATIC;
-
         route->network = network;
 
         LIST_PREPEND(routes, network->static_routes, route);
@@ -64,23 +86,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
         return 0;
 }
 
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
-        _cleanup_route_free_ Route *route = NULL;
-
-        route = new0(Route, 1);
-        if (!route)
-                return -ENOMEM;
-
-        route->family = AF_UNSPEC;
-        route->scope = RT_SCOPE_UNIVERSE;
-        route->protocol = rtm_protocol;
-
-        *ret = route;
-        route = NULL;
-
-        return 0;
-}
-
 void route_free(Route *route) {
         if (!route)
                 return;
@@ -93,10 +98,241 @@ void route_free(Route *route) {
                                        UINT_TO_PTR(route->section));
         }
 
+        if (route->link) {
+                set_remove(route->link->routes, route);
+                set_remove(route->link->routes_foreign, route);
+        }
+
+        sd_event_source_unref(route->expire);
+
         free(route);
 }
 
-int route_drop(Route *route, Link *link,
+static void route_hash_func(const void *b, struct siphash *state) {
+        const Route *route = b;
+
+        assert(route);
+
+        siphash24_compress(&route->family, sizeof(route->family), state);
+
+        switch (route->family) {
+        case AF_INET:
+        case AF_INET6:
+                /* Equality of routes are given by the 4-touple
+                   (dst_prefix,dst_prefixlen,tos,priority,table) */
+                siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
+                siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
+                siphash24_compress(&route->tos, sizeof(route->tos), state);
+                siphash24_compress(&route->priority, sizeof(route->priority), state);
+                siphash24_compress(&route->table, sizeof(route->table), state);
+
+                break;
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                break;
+        }
+}
+
+static int route_compare_func(const void *_a, const void *_b) {
+        const Route *a = _a, *b = _b;
+
+        if (a->family < b->family)
+                return -1;
+        if (a->family > b->family)
+                return 1;
+
+        switch (a->family) {
+        case AF_INET:
+        case AF_INET6:
+                if (a->dst_prefixlen < b->dst_prefixlen)
+                        return -1;
+                if (a->dst_prefixlen > b->dst_prefixlen)
+                        return 1;
+
+                if (a->tos < b->tos)
+                        return -1;
+                if (a->tos > b->tos)
+                        return 1;
+
+                if (a->priority < b->priority)
+                        return -1;
+                if (a->priority > b->priority)
+                        return 1;
+
+                if (a->table < b->table)
+                        return -1;
+                if (a->table > b->table)
+                        return 1;
+
+                return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
+        default:
+                /* treat any other address family as AF_UNSPEC */
+                return 0;
+        }
+}
+
+static const struct hash_ops route_hash_ops = {
+        .hash = route_hash_func,
+        .compare = route_compare_func
+};
+
+int route_get(Link *link,
+              int family,
+              union in_addr_union *dst,
+              unsigned char dst_prefixlen,
+              unsigned char tos,
+              uint32_t priority,
+              unsigned char table,
+              Route **ret) {
+        Route route = {
+                .family = family,
+                .dst_prefixlen = dst_prefixlen,
+                .tos = tos,
+                .priority = priority,
+                .table = table,
+        }, *existing;
+
+        assert(link);
+        assert(dst);
+        assert(ret);
+
+        route.dst = *dst;
+
+        existing = set_get(link->routes, &route);
+        if (existing) {
+                *ret = existing;
+                return 1;
+        } else {
+                existing = set_get(link->routes_foreign, &route);
+                if (!existing)
+                        return -ENOENT;
+        }
+
+        *ret = existing;
+
+        return 0;
+}
+
+static int route_add_internal(Link *link, Set **routes,
+                              int family,
+                              union in_addr_union *dst,
+                              unsigned char dst_prefixlen,
+                              unsigned char tos,
+                              uint32_t priority,
+                              unsigned char table, Route **ret) {
+        _cleanup_route_free_ Route *route = NULL;
+        int r;
+
+        assert(link);
+        assert(routes);
+        assert(dst);
+
+        r = route_new(&route);
+        if (r < 0)
+                return r;
+
+        route->family = family;
+        route->dst = *dst;
+        route->dst_prefixlen = dst_prefixlen;
+        route->tos = tos;
+        route->priority = priority;
+        route->table = table;
+
+        r = set_ensure_allocated(routes, &route_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = set_put(*routes, route);
+        if (r < 0)
+                return r;
+
+        route->link = link;
+
+        if (ret)
+                *ret = route;
+
+        route = NULL;
+
+        return 0;
+}
+
+int route_add_foreign(Link *link,
+                      int family,
+                      union in_addr_union *dst,
+                      unsigned char dst_prefixlen,
+                      unsigned char tos,
+                      uint32_t priority,
+                      unsigned char table, Route **ret) {
+        return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
+}
+
+int route_add(Link *link,
+              int family,
+              union in_addr_union *dst,
+              unsigned char dst_prefixlen,
+              unsigned char tos,
+              uint32_t priority,
+              unsigned char table, Route **ret) {
+        Route *route;
+        int r;
+
+        r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
+        if (r == -ENOENT) {
+                /* Route does not exist, create a new one */
+                r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
+                if (r < 0)
+                        return r;
+        } else if (r == 0) {
+                /* Take over a foreign route */
+                r = set_ensure_allocated(&link->routes, &route_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = set_put(link->routes, route);
+                if (r < 0)
+                        return r;
+
+                set_remove(link->routes_foreign, route);
+        } else if (r == 1) {
+                /* Route exists, do nothing */
+                ;
+        } else
+                return r;
+
+        *ret = route;
+
+        return 0;
+}
+
+int route_update(Route *route,
+                 union in_addr_union *src,
+                 unsigned char src_prefixlen,
+                 union in_addr_union *gw,
+                 union in_addr_union *prefsrc,
+                 unsigned char scope,
+                 unsigned char protocol) {
+        assert(route);
+        assert(src);
+        assert(gw);
+        assert(prefsrc);
+
+        route->src = *src;
+        route->src_prefixlen = src_prefixlen;
+        route->gw = *gw;
+        route->prefsrc = *prefsrc;
+        route->scope = scope;
+        route->protocol = protocol;
+
+        return 0;
+}
+
+void route_drop(Route *route) {
+        assert(route);
+
+        route_free(route);
+}
+
+int route_remove(Route *route, Link *link,
                sd_netlink_message_handler_t callback) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
         int r;
@@ -113,20 +349,20 @@ int route_drop(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
 
-        if (!in_addr_is_null(route->family, &route->in_addr)) {
+        if (!in_addr_is_null(route->family, &route->gw)) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
         }
 
         if (route->dst_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -137,9 +373,9 @@ int route_drop(Route *route, Link *link,
 
         if (route->src_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -148,11 +384,11 @@ int route_drop(Route *route, Link *link,
                         return log_error_errno(r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+        if (!in_addr_is_null(route->family, &route->prefsrc)) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
         }
@@ -161,7 +397,7 @@ int route_drop(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
 
-        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
 
@@ -178,9 +414,24 @@ int route_drop(Route *route, Link *link,
         return 0;
 }
 
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+        Route *route = userdata;
+        int r;
+
+        assert(route);
+
+        r = route_remove(route, route->link, NULL);
+        if (r < 0)
+                log_warning_errno(r, "Could not remove route: %m");
+
+        return 1;
+}
+
 int route_configure(Route *route, Link *link,
                     sd_netlink_message_handler_t callback) {
         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+        _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+        usec_t lifetime;
         int r;
 
         assert(link);
@@ -195,20 +446,20 @@ int route_configure(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
 
-        if (!in_addr_is_null(route->family, &route->in_addr)) {
+        if (!in_addr_is_null(route->family, &route->gw)) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
         }
 
         if (route->dst_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_DST attribute: %m");
 
@@ -219,9 +470,9 @@ int route_configure(Route *route, Link *link,
 
         if (route->src_prefixlen) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
 
@@ -230,11 +481,11 @@ int route_configure(Route *route, Link *link,
                         return log_error_errno(r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+        if (!in_addr_is_null(route->family, &route->prefsrc)) {
                 if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
                 else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
                 if (r < 0)
                         return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
         }
@@ -243,10 +494,18 @@ int route_configure(Route *route, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
 
-        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+        r = sd_rtnl_message_route_set_flags(req, route->flags);
+        if (r < 0)
+                return log_error_errno(r, "Colud not set flags: %m");
+
+        r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
 
+        r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
+        if (r < 0)
+                return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
+
         r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
         if (r < 0)
                 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
@@ -257,6 +516,26 @@ int route_configure(Route *route, Link *link,
 
         link_ref(link);
 
+        lifetime = route->lifetime;
+
+        r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
+        if (r < 0)
+                return log_error_errno(r, "Could not add route: %m");
+
+        /* TODO: drop expiration handling once it can be pushed into the kernel */
+        route->lifetime = lifetime;
+
+        if (route->lifetime != USEC_INFINITY) {
+                r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
+                                      route->lifetime, 0, route_expire_handler, route);
+                if (r < 0)
+                        return log_error_errno(r, "Could not arm expiration timer: %m");
+        }
+
+        sd_event_source_unref(route->expire);
+        route->expire = expire;
+        expire = NULL;
+
         return 0;
 }
 
@@ -299,7 +578,7 @@ int config_parse_gateway(const char *unit,
         }
 
         n->family = f;
-        n->in_addr = buffer;
+        n->gw = buffer;
         n = NULL;
 
         return 0;
@@ -339,7 +618,7 @@ int config_parse_preferred_src(const char *unit,
         }
 
         n->family = f;
-        n->prefsrc_addr = buffer;
+        n->prefsrc = buffer;
         n = NULL;
 
         return 0;
@@ -413,10 +692,10 @@ int config_parse_destination(const char *unit,
 
         n->family = f;
         if (streq(lvalue, "Destination")) {
-                n->dst_addr = buffer;
+                n->dst = buffer;
                 n->dst_prefixlen = prefixlen;
         } else if (streq(lvalue, "Source")) {
-                n->src_addr = buffer;
+                n->src = buffer;
                 n->src_prefixlen = prefixlen;
         } else
                 assert_not_reached(lvalue);
@@ -450,9 +729,9 @@ int config_parse_route_priority(const char *unit,
         if (r < 0)
                 return r;
 
-        r = config_parse_unsigned(unit, filename, line, section,
-                                  section_line, lvalue, ltype,
-                                  rvalue, &n->metrics, userdata);
+        r = config_parse_uint32(unit, filename, line, section,
+                                section_line, lvalue, ltype,
+                                rvalue, &n->priority, userdata);
         if (r < 0)
                 return r;
 
index 11e94d44fbf1fcf69ad8cb48d23bc7ab91532d4a..b2767566745c47dc226abe0d67bfb57c03e898b8 100644 (file)
@@ -30,26 +30,43 @@ struct Route {
         Network *network;
         unsigned section;
 
+        Link *link;
+
         int family;
         unsigned char dst_prefixlen;
         unsigned char src_prefixlen;
         unsigned char scope;
-        uint32_t metrics;
         unsigned char protocol;  /* RTPROT_* */
+        unsigned char tos;
+        uint32_t priority; /* note that ip(8) calls this 'metric' */
+        unsigned char table;
+        unsigned char pref;
+        unsigned flags;
+
+        union in_addr_union gw;
+        union in_addr_union dst;
+        union in_addr_union src;
+        union in_addr_union prefsrc;
 
-        union in_addr_union in_addr;
-        union in_addr_union dst_addr;
-        union in_addr_union src_addr;
-        union in_addr_union prefsrc_addr;
+        usec_t lifetime;
+        sd_event_source *expire;
 
         LIST_FIELDS(Route, routes);
 };
 
 int route_new_static(Network *network, unsigned section, Route **ret);
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol);
+int route_new(Route **ret);
 void route_free(Route *route);
 int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
+
+int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
+void route_drop(Route *route);
+
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
 #define _cleanup_route_free_ _cleanup_(route_freep)
index dde6b327ed927d9f67fbd55d263da48b7f24a671..2545621a93d448c17a955eb2d24e8fe107c6b039 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "conf-parser.h"
-
 #include "networkd-util.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
 
 const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
         if (b == ADDRESS_FAMILY_YES ||
@@ -77,12 +79,20 @@ int config_parse_address_family_boolean_with_kernel(
         assert(rvalue);
         assert(data);
 
+        /* This function is mostly obsolete now. It simply redirects
+         * "kernel" to "no". In older networkd versions we used to
+         * distuingish IPForward=off from IPForward=kernel, where the
+         * former would explicitly turn off forwarding while the
+         * latter would simply not touch the setting. But that logic
+         * is gone, hence silently accept the old setting, but turn it
+         * to "no". */
+
         s = address_family_boolean_from_string(rvalue);
         if (s < 0) {
                 if (streq(rvalue, "kernel"))
-                        s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
+                        s = ADDRESS_FAMILY_NO;
                 else {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForwarding= option, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue);
                         return 0;
                 }
         }
index cacb4c257e5440379dfcb5ba1b1b7f51d5a5b768..c2779ff773e42c5757b3a6cc374647ca572685fe 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
 #include "sd-network.h"
 
+#include "alloc-util.h"
 #include "networkd-wait-online-link.h"
+#include "string-util.h"
 
 int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
         _cleanup_(link_freep) Link *l = NULL;
index 112d92a568a74f4b2449dceec4bb61ac35068870..0c40ab2bb8ae3fda778da480fd45a293e29b0141 100644 (file)
 #include <linux/if.h>
 #include <fnmatch.h>
 
+#include "alloc-util.h"
 #include "netlink-util.h"
-
 #include "network-internal.h"
 #include "networkd-wait-online-link.h"
 #include "networkd-wait-online.h"
-
-#include "util.h"
 #include "time-util.h"
+#include "util.h"
 
 bool manager_ignore_link(Manager *m, Link *link) {
         char **ignore;
index e6259043fa2ad524515d1b879411263a6adc5334..ef394e0c04570c7518b51aaa884e67e9ec3fdf05 100644 (file)
 ***/
 
 #include "sd-daemon.h"
-#include "capability.h"
-#include "signal-util.h"
+
+#include "capability-util.h"
 #include "networkd.h"
+#include "signal-util.h"
+#include "user-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_manager_free_ Manager *m = NULL;
@@ -107,6 +109,12 @@ int main(int argc, char *argv[]) {
                 goto out;
         }
 
+        r = manager_rtnl_enumerate_routes(m);
+        if (r < 0) {
+                log_error_errno(r, "Could not enumerate routes: %m");
+                goto out;
+        }
+
         log_info("Enumeration completed");
 
         sd_notify(false,
index eea57ac15843a4243e3779a97e6acf9b540d0633..97665fac7aa4e2fc4e108268fef09e44d5d6e85c 100644 (file)
@@ -48,7 +48,10 @@ struct Manager {
         struct udev_monitor *udev_monitor;
         sd_event_source *udev_event_source;
 
-        bool enumerating;
+        bool enumerating:1;
+        bool dirty:1;
+
+        Set *dirty_links;
 
         char *state_file;
         LinkOperationalState operational_state;
@@ -79,9 +82,13 @@ bool manager_should_reload(Manager *m);
 
 int manager_rtnl_enumerate_links(Manager *m);
 int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_rtnl_enumerate_routes(Manager *m);
+
+int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
 
 int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
-int manager_save(Manager *m);
+void manager_dirty(Manager *m);
 
 int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);
 
index 5909cc790e842af25a94b462f16edaf4234dbbe8..dbed3795e3ffca16cf57243d808eae1fe6abee90 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "networkd.h"
 #include "network-internal.h"
 #include "dhcp-lease-internal.h"
@@ -143,8 +144,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
 static void test_address_equality(void) {
         _cleanup_address_free_ Address *a1 = NULL, *a2 = NULL;
 
-        assert_se(address_new_dynamic(&a1) >= 0);
-        assert_se(address_new_dynamic(&a2) >= 0);
+        assert_se(address_new(&a1) >= 0);
+        assert_se(address_new(&a2) >= 0);
 
         assert_se(address_equal(NULL, NULL));
         assert_se(!address_equal(a1, NULL));
@@ -158,17 +159,18 @@ static void test_address_equality(void) {
         assert_se(address_equal(a1, a2));
 
         assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in));
-        assert_se(address_equal(a1, a2));
+        assert_se(!address_equal(a1, a2));
         assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in));
         assert_se(address_equal(a1, a2));
+        assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in));
+        assert_se(address_equal(a1, a2));
+        assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in));
+        assert_se(address_equal(a1, a2));
         a1->prefixlen = 10;
         assert_se(!address_equal(a1, a2));
         a2->prefixlen = 10;
         assert_se(address_equal(a1, a2));
 
-        assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in));
-        assert_se(address_equal(a1, a2));
-
         a1->family = AF_INET6;
         assert_se(!address_equal(a1, a2));
 
index 805ea1a6277663d5badc6a09c80c34fb3170f9ed..b1445547023a027b811162d9e0c3922ef4b836e0 100644 (file)
 
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
 #include "env-util.h"
 #include "formats-util.h"
 #include "log.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
index c0e9ccd7a44596e530d8010917540401c1f0873e..270bcf010fcfa46be24af468a1791818188b3af8 100644 (file)
 
 #include <sys/mount.h>
 
-#include "util.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "fileio.h"
+#include "alloc-util.h"
 #include "cgroup-util.h"
-
+#include "fd-util.h"
+#include "fileio.h"
+#include "mkdir.h"
 #include "nspawn-cgroup.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 int chown_cgroup(pid_t pid, uid_t uid_shift) {
         _cleanup_free_ char *path = NULL, *fs = NULL;
index 3658f45381b4dce6f621e03c05fc482c092a75e5..38245434da8bd202451cae65573a691d119596d6 100644 (file)
 
 #include "sd-netlink.h"
 
-#include "util.h"
-#include "in-addr-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "firewall-util.h"
+#include "in-addr-util.h"
 #include "local-addresses.h"
 #include "netlink-util.h"
-
 #include "nspawn-expose-ports.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
 
 int expose_port_parse(ExposePort **l, const char *s) {
 
index b5127a387c3660f2084244ea3fa3787f8910717e..58f9f4c63544a2c9dcbc6570683507b325037cc4 100644 (file)
@@ -15,24 +15,25 @@ struct ConfigPerfItem;
 %struct-type
 %includes
 %%
-Exec.Boot,                 config_parse_tristate,      0, offsetof(Settings, boot)
-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)
-Exec.Capability,           config_parse_capability,    0, offsetof(Settings, capability)
-Exec.DropCapability,       config_parse_capability,    0, offsetof(Settings, drop_capability)
-Exec.KillSignal,           config_parse_signal,        0, offsetof(Settings, kill_signal)
-Exec.Personality,          config_parse_personality,   0, offsetof(Settings, personality)
-Exec.MachineID,            config_parse_id128,         0, offsetof(Settings, machine_id)
-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
-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)
-Network.IPVLAN,            config_parse_strv,          0, offsetof(Settings, network_ipvlan)
-Network.VirtualEthernet,   config_parse_tristate,      0, offsetof(Settings, network_veth)
-Network.Bridge,            config_parse_string,        0, offsetof(Settings, network_bridge)
-Network.Port,              config_parse_expose_port,   0, 0
+Exec.Boot,                    config_parse_tristate,      0, offsetof(Settings, boot)
+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)
+Exec.Capability,              config_parse_capability,    0, offsetof(Settings, capability)
+Exec.DropCapability,          config_parse_capability,    0, offsetof(Settings, drop_capability)
+Exec.KillSignal,              config_parse_signal,        0, offsetof(Settings, kill_signal)
+Exec.Personality,             config_parse_personality,   0, offsetof(Settings, personality)
+Exec.MachineID,               config_parse_id128,         0, offsetof(Settings, machine_id)
+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
+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)
+Network.IPVLAN,               config_parse_strv,          0, offsetof(Settings, network_ipvlan)
+Network.VirtualEthernet,      config_parse_tristate,      0, offsetof(Settings, network_veth)
+Network.VirtualEthernetExtra, config_parse_veth_extra,    0, 0
+Network.Bridge,               config_parse_string,        0, offsetof(Settings, network_bridge)
+Network.Port,                 config_parse_expose_port,   0, 0
index 6c8b1d7a2651fcaec73539b6757944a13e446a35..c8e627ac78b41fba114f43ce53c969503cdf903d 100644 (file)
 ***/
 
 #include <sys/mount.h>
+#include <linux/magic.h>
 
-#include "util.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "label.h"
-#include "set.h"
+#include "alloc-util.h"
 #include "cgroup-util.h"
-
+#include "escape.h"
+#include "fs-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "mount-util.h"
 #include "nspawn-mount.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "set.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) {
         CustomMount *c, *ret;
@@ -218,8 +226,19 @@ static int tmpfs_patch_options(
 
 int mount_sysfs(const char *dest) {
         const char *full, *top, *x;
+        int r;
 
         top = prefix_roota(dest, "/sys");
+        r = path_check_fstype(top, SYSFS_MAGIC);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top);
+        /* /sys might already be mounted as sysfs by the outer child in the
+         * !netns case. In this case, it's all good. Don't touch it because we
+         * don't have the right to do so, see https://github.com/systemd/systemd/issues/1555.
+         */
+        if (r > 0)
+                return 0;
+
         full = prefix_roota(top, "/full");
 
         (void) mkdir(full, 0755);
@@ -264,6 +283,7 @@ int mount_sysfs(const char *dest) {
 
 int mount_all(const char *dest,
               bool use_userns, bool in_userns,
+              bool use_netns,
               uid_t uid_shift, uid_t uid_range,
               const char *selinux_apifs_context) {
 
@@ -274,21 +294,23 @@ int mount_all(const char *dest,
                 const char *options;
                 unsigned long flags;
                 bool fatal;
-                bool userns;
+                bool in_userns;
+                bool use_netns;
         } MountPoint;
 
         static const MountPoint mount_table[] = {
-                { "proc",      "/proc",          "proc",   NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV,                              true,  true  },
-                { "/proc/sys", "/proc/sys",      NULL,     NULL,        MS_BIND,                                                   true,  true  },   /* Bind mount first */
-                { NULL,        "/proc/sys",      NULL,     NULL,        MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true,  true  },   /* Then, make it r/o */
-                { "tmpfs",     "/sys",           "tmpfs",  "mode=755",  MS_NOSUID|MS_NOEXEC|MS_NODEV,                              true,  false },
-                { "tmpfs",     "/dev",           "tmpfs",  "mode=755",  MS_NOSUID|MS_STRICTATIME,                                  true,  false },
-                { "tmpfs",     "/dev/shm",       "tmpfs",  "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,                         true,  false },
-                { "tmpfs",     "/run",           "tmpfs",  "mode=755",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,                         true,  false },
-                { "tmpfs",     "/tmp",           "tmpfs",  "mode=1777", MS_STRICTATIME,                                            true,  false },
+                { "proc",      "/proc",          "proc",   NULL,        MS_NOSUID|MS_NOEXEC|MS_NODEV,                              true,  true, false  },
+                { "/proc/sys", "/proc/sys",      NULL,     NULL,        MS_BIND,                                                   true,  true, false  },   /* Bind mount first */
+                { NULL,        "/proc/sys",      NULL,     NULL,        MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true,  true, false  },   /* Then, make it r/o */
+                { "tmpfs",     "/sys",           "tmpfs",  "mode=755",  MS_NOSUID|MS_NOEXEC|MS_NODEV,                              true,  false, true },
+                { "sysfs",     "/sys",           "sysfs",  NULL,        MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,                    true,  false, false },
+                { "tmpfs",     "/dev",           "tmpfs",  "mode=755",  MS_NOSUID|MS_STRICTATIME,                                  true,  false, false },
+                { "tmpfs",     "/dev/shm",       "tmpfs",  "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,                         true,  false, false },
+                { "tmpfs",     "/run",           "tmpfs",  "mode=755",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,                         true,  false, false },
+                { "tmpfs",     "/tmp",           "tmpfs",  "mode=1777", MS_STRICTATIME,                                            true,  false, false },
 #ifdef HAVE_SELINUX
-                { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL,     MS_BIND,                                                   false, false },  /* Bind mount first */
-                { NULL,              "/sys/fs/selinux", NULL, NULL,     MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false },  /* Then, make it r/o */
+                { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL,     MS_BIND,                                                   false, false, false },  /* Bind mount first */
+                { NULL,              "/sys/fs/selinux", NULL, NULL,     MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false },  /* Then, make it r/o */
 #endif
         };
 
@@ -299,7 +321,10 @@ int mount_all(const char *dest,
                 _cleanup_free_ char *where = NULL, *options = NULL;
                 const char *o;
 
-                if (in_userns != mount_table[k].userns)
+                if (in_userns != mount_table[k].in_userns)
+                        continue;
+
+                if (!use_netns && mount_table[k].use_netns)
                         continue;
 
                 where = prefix_root(dest, mount_table[k].where);
@@ -416,8 +441,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to make parents of %s: %m", where);
         } else {
-                log_error_errno(errno, "Failed to stat %s: %m", where);
-                return -errno;
+                return log_error_errno(errno, "Failed to stat %s: %m", where);
         }
 
         /* Create the mount point. Any non-directory file can be
index 54cab87665dd9c95807f564d26bf9c508e66c640..bdab23bcca2476ffeeeb3d18692df6046a178bb5 100644 (file)
@@ -57,7 +57,7 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s);
 
 int custom_mount_compare(const void *a, const void *b);
 
-int mount_all(const char *dest, bool use_userns, bool in_userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
 int mount_sysfs(const char *dest);
 
 int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
index 74abe5379a5d1d2d1d3a8f83091efb7ed07765a4..c71552879d83e38aa4fb609302470669174829c1 100644 (file)
 #include <linux/veth.h>
 #include <net/if.h>
 
+#include "libudev.h"
 #include "sd-id128.h"
 #include "sd-netlink.h"
-#include "libudev.h"
 
-#include "util.h"
+#include "alloc-util.h"
 #include "ether-addr-util.h"
-#include "siphash24.h"
 #include "netlink-util.h"
+#include "siphash24.h"
+#include "string-util.h"
 #include "udev-util.h"
-
+#include "util.h"
 #include "nspawn-network.h"
 
 #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
 #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
+#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
+#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
 #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
 
 static int generate_mac(
@@ -83,42 +86,32 @@ static int generate_mac(
         return 0;
 }
 
-int setup_veth(const char *machine_name,
-               pid_t pid,
-               char iface_name[IFNAMSIZ],
-               bool bridge) {
+static int add_veth(
+                sd_netlink *rtnl,
+                pid_t pid,
+                const char *ifname_host,
+                const struct ether_addr *mac_host,
+                const char *ifname_container,
+                const struct ether_addr *mac_container) {
 
         _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
-        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
-        struct ether_addr mac_host, mac_container;
-        int r, i;
-
-        /* Use two different interface name prefixes depending whether
-         * we are in bridge mode or not. */
-        snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
-                 bridge ? "vb" : "ve", machine_name);
-
-        r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
-        if (r < 0)
-                return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
-
-        r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
-        if (r < 0)
-                return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
+        int r;
 
-        r = sd_netlink_open(&rtnl);
-        if (r < 0)
-                return log_error_errno(r, "Failed to connect to netlink: %m");
+        assert(rtnl);
+        assert(ifname_host);
+        assert(mac_host);
+        assert(ifname_container);
+        assert(mac_container);
 
         r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
         if (r < 0)
                 return log_error_errno(r, "Failed to allocate netlink message: %m");
 
-        r = sd_netlink_message_append_string(m, IFLA_IFNAME, iface_name);
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host);
+        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink MAC address: %m");
 
@@ -134,11 +127,11 @@ int setup_veth(const char *machine_name,
         if (r < 0)
                 return log_error_errno(r, "Failed to open netlink container: %m");
 
-        r = sd_netlink_message_append_string(m, IFLA_IFNAME, "host0");
+        r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink interface name: %m");
 
-        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container);
+        r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
         if (r < 0)
                 return log_error_errno(r, "Failed to add netlink MAC address: %m");
 
@@ -160,7 +153,44 @@ int setup_veth(const char *machine_name,
 
         r = sd_netlink_call(rtnl, m, 0, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name);
+                return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
+
+        return 0;
+}
+
+int setup_veth(const char *machine_name,
+               pid_t pid,
+               char iface_name[IFNAMSIZ],
+               bool bridge) {
+
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        struct ether_addr mac_host, mac_container;
+        int r, i;
+
+        assert(machine_name);
+        assert(pid > 0);
+        assert(iface_name);
+
+        /* Use two different interface name prefixes depending whether
+         * we are in bridge mode or not. */
+        snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
+                 bridge ? "vb" : "ve", machine_name);
+
+        r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
+
+        r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
+
+        r = sd_netlink_open(&rtnl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to netlink: %m");
+
+        r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
+        if (r < 0)
+                return r;
 
         i = (int) if_nametoindex(iface_name);
         if (i <= 0)
@@ -169,6 +199,47 @@ int setup_veth(const char *machine_name,
         return i;
 }
 
+int setup_veth_extra(
+                const char *machine_name,
+                pid_t pid,
+                char **pairs) {
+
+        _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+        uint64_t idx = 0;
+        char **a, **b;
+        int r;
+
+        assert(machine_name);
+        assert(pid > 0);
+
+        if (strv_isempty(pairs))
+                return 0;
+
+        r = sd_netlink_open(&rtnl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to netlink: %m");
+
+        STRV_FOREACH_PAIR(a, b, pairs) {
+                struct ether_addr mac_host, mac_container;
+
+                r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
+
+                r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
+
+                r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
+                if (r < 0)
+                        return r;
+
+                idx ++;
+        }
+
+        return 0;
+}
+
 int setup_bridge(const char *veth_name, const char *bridge_name) {
         _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL;
         _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
@@ -438,3 +509,34 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
 
         return 0;
 }
+
+int veth_extra_parse(char ***l, const char *p) {
+        _cleanup_free_ char *a = NULL, *b = NULL;
+        int r;
+
+        r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+        if (r < 0)
+                return r;
+        if (r == 0 || isempty(a))
+                return -EINVAL;
+
+        r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+        if (r < 0)
+                return r;
+        if (r == 0 || isempty(b)) {
+                free(b);
+                b = strdup(a);
+                if (!b)
+                        return -ENOMEM;
+        }
+
+        if (p)
+                return -EINVAL;
+
+        r = strv_push_pair(l, a, b);
+        if (r < 0)
+                return -ENOMEM;
+
+        a = b = NULL;
+        return 0;
+}
index 311e6d06cb2964880d15f9c06ef6254b6ba10a53..b86effef47cb14e9b076ae47946227572100da2a 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 
 int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
+int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
 
 int setup_bridge(const char *veth_name, const char *bridge_name);
 
@@ -34,3 +35,5 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces);
 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);
index b2776a61c26a2761fbc2ded117bc1a41f976c633..374f958c2032dc4369a45fffd583eccb4913567d 100644 (file)
 
 #include "sd-bus.h"
 
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
 #include "bus-error.h"
-
+#include "bus-util.h"
 #include "nspawn-register.h"
+#include "stat-util.h"
+#include "strv.h"
+#include "util.h"
 
 int register_machine(
                 const char *machine_name,
@@ -39,7 +39,8 @@ int register_machine(
                 unsigned n_mounts,
                 int kill_signal,
                 char **properties,
-                bool keep_unit) {
+                bool keep_unit,
+                const char *service) {
 
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
@@ -61,7 +62,7 @@ int register_machine(
                                 "sayssusai",
                                 machine_name,
                                 SD_BUS_MESSAGE_APPEND_ID128(uuid),
-                                "nspawn",
+                                service,
                                 "container",
                                 (uint32_t) pid,
                                 strempty(directory),
@@ -86,7 +87,7 @@ int register_machine(
                                 "sayssusai",
                                 machine_name,
                                 SD_BUS_MESSAGE_APPEND_ID128(uuid),
-                                "nspawn",
+                                service,
                                 "container",
                                 (uint32_t) pid,
                                 strempty(directory),
index b27841ff59011603d93d46d952bbff6d984d7481..d3bfd84e5e98986e7e4e810b5fce30e3b8e40b3d 100644 (file)
@@ -27,5 +27,5 @@
 
 #include "nspawn-mount.h"
 
-int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit);
+int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service);
 int terminate_machine(pid_t pid);
index b920391b3871100f29e699b38a4b5f20a09cbceb..d6b64d8d5a05c4edf2c471dccb5a7204654c5959 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "conf-parser.h"
-#include "strv.h"
+#include "alloc-util.h"
 #include "cap-list.h"
-
+#include "conf-parser.h"
+#include "nspawn-network.h"
 #include "nspawn-settings.h"
+#include "process-util.h"
+#include "strv.h"
+#include "util.h"
 
 int settings_load(FILE *f, const char *path, Settings **ret) {
         _cleanup_(settings_freep) Settings *s = NULL;
@@ -76,6 +78,7 @@ Settings* settings_free(Settings *s) {
         strv_free(s->network_interfaces);
         strv_free(s->network_macvlan);
         strv_free(s->network_ipvlan);
+        strv_free(s->network_veth_extra);
         free(s->network_bridge);
         expose_port_free_all(s->expose_ports);
 
@@ -85,6 +88,27 @@ Settings* settings_free(Settings *s) {
         return NULL;
 }
 
+bool settings_private_network(Settings *s) {
+        assert(s);
+
+        return
+                s->private_network > 0 ||
+                s->network_veth > 0 ||
+                s->network_bridge ||
+                s->network_interfaces ||
+                s->network_macvlan ||
+                s->network_ipvlan ||
+                s->network_veth_extra;
+}
+
+bool settings_network_veth(Settings *s) {
+        assert(s);
+
+        return
+                s->network_veth > 0 ||
+                s->network_bridge;
+}
+
 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
 
 int config_parse_expose_port(
@@ -248,15 +272,33 @@ int config_parse_tmpfs(
                 return 0;
         }
 
-        if (settings->network_bridge)
-                settings->network_veth = true;
+        return 0;
+}
 
-        if (settings->network_interfaces ||
-            settings->network_macvlan ||
-            settings->network_ipvlan ||
-            settings->network_bridge ||
-            settings->network_veth)
-                settings->private_network = true;
+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) {
+
+        Settings *settings = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+
+        r = veth_extra_parse(&settings->network_veth_extra, rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
+                return 0;
+        }
 
         return 0;
 }
index 4cec40c1b7152fa0ae43bd8122492e406f2652bf..dde0d8bd450fa1a1630bd0b612654a7b359e4cd4 100644 (file)
@@ -69,12 +69,16 @@ typedef struct Settings {
         char **network_interfaces;
         char **network_macvlan;
         char **network_ipvlan;
+        char **network_veth_extra;
         ExposePort *expose_ports;
 } Settings;
 
 int settings_load(FILE *f, const char *path, Settings **ret);
 Settings* settings_free(Settings *s);
 
+bool settings_network_veth(Settings *s);
+bool settings_private_network(Settings *s);
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
 
 const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length);
@@ -85,3 +89,4 @@ int config_parse_expose_port(const char *unit, const char *filename, unsigned li
 int config_parse_volatile_mode(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_bind(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_tmpfs(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_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);
index eda7f62900ab75e83e75798bcd5fca02f7a09537..aa6a16309c988d416c7610c9678dc09a114ac7af 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <grp.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <grp.h>
 
-#include "util.h"
-#include "signal-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "mkdir.h"
-#include "process-util.h"
-
 #include "nspawn-setuid.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
 
 static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
         int pipe_fds[2];
index ab93f98df41f87816a7c10897be07ee935a68b0f..d2ce731c7289b89b67b4f508c132f4ceafd8fc07 100644 (file)
 #include "sd-daemon.h"
 #include "sd-id128.h"
 
+#include "alloc-util.h"
 #include "barrier.h"
 #include "base-filesystem.h"
 #include "blkid-util.h"
 #include "btrfs-util.h"
 #include "cap-list.h"
-#include "capability.h"
+#include "capability-util.h"
 #include "cgroup-util.h"
 #include "copy.h"
 #include "dev-setup.h"
 #include "env-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "fdset.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "gpt.h"
 #include "hostname-util.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "mount-util.h"
 #include "netlink-util.h"
+#include "nspawn-cgroup.h"
+#include "nspawn-expose-ports.h"
+#include "nspawn-mount.h"
+#include "nspawn-network.h"
+#include "nspawn-register.h"
+#include "nspawn-settings.h"
+#include "nspawn-setuid.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "ptyfwd.h"
 #include "seccomp-util.h"
 #endif
 #include "signal-util.h"
+#include "socket-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "udev-util.h"
+#include "umask-util.h"
+#include "user-util.h"
 #include "util.h"
 
-#include "nspawn-cgroup.h"
-#include "nspawn-expose-ports.h"
-#include "nspawn-mount.h"
-#include "nspawn-network.h"
-#include "nspawn-register.h"
-#include "nspawn-settings.h"
-#include "nspawn-setuid.h"
-
 typedef enum ContainerStatus {
         CONTAINER_TERMINATED,
         CONTAINER_REBOOTED
@@ -155,6 +165,7 @@ static char **arg_network_interfaces = NULL;
 static char **arg_network_macvlan = NULL;
 static char **arg_network_ipvlan = NULL;
 static bool arg_network_veth = false;
+static char **arg_network_veth_extra = NULL;
 static char *arg_network_bridge = NULL;
 static unsigned long arg_personality = PERSONALITY_INVALID;
 static char *arg_image = NULL;
@@ -168,6 +179,7 @@ static bool arg_unified_cgroup_hierarchy = false;
 static SettingsMask arg_settings_mask = 0;
 static int arg_settings_trusted = -1;
 static char **arg_parameters = NULL;
+static const char *arg_container_service_name = "systemd-nspawn";
 
 static void help(void) {
         printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -199,10 +211,13 @@ static void help(void) {
                "     --network-ipvlan=INTERFACE\n"
                "                            Create a ipvlan network interface based on an\n"
                "                            existing network interface to the container\n"
-               "  -n --network-veth         Add a virtual ethernet connection between host\n"
+               "  -n --network-veth         Add a virtual Ethernet connection between host\n"
                "                            and container\n"
+               "     --network-veth-extra=HOSTIF[:CONTAINERIF]\n"
+               "                            Add an additional virtual Ethernet link between\n"
+               "                            host and container\n"
                "     --network-bridge=INTERFACE\n"
-               "                            Add a virtual ethernet connection between host\n"
+               "                            Add a virtual Ethernet connection between host\n"
                "                            and container and add it to an existing bridge on\n"
                "                            the host\n"
                "  -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
@@ -276,27 +291,6 @@ static int custom_mounts_prepare(void) {
         return 0;
 }
 
-static int set_sanitized_path(char **b, const char *path) {
-        char *p;
-
-        assert(b);
-        assert(path);
-
-        p = canonicalize_file_name(path);
-        if (!p) {
-                if (errno != ENOENT)
-                        return -errno;
-
-                p = path_make_absolute_cwd(path);
-                if (!p)
-                        return -ENOMEM;
-        }
-
-        free(*b);
-        *b = path_kill_slashes(p);
-        return 0;
-}
-
 static int detect_unified_cgroup_hierarchy(void) {
         const char *e;
         int r;
@@ -344,6 +338,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_NETWORK_MACVLAN,
                 ARG_NETWORK_IPVLAN,
                 ARG_NETWORK_BRIDGE,
+                ARG_NETWORK_VETH_EXTRA,
                 ARG_PERSONALITY,
                 ARG_VOLATILE,
                 ARG_TEMPLATE,
@@ -385,6 +380,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "network-macvlan",       required_argument, NULL, ARG_NETWORK_MACVLAN   },
                 { "network-ipvlan",        required_argument, NULL, ARG_NETWORK_IPVLAN    },
                 { "network-veth",          no_argument,       NULL, 'n'                   },
+                { "network-veth-extra",    required_argument, NULL, ARG_NETWORK_VETH_EXTRA},
                 { "network-bridge",        required_argument, NULL, ARG_NETWORK_BRIDGE    },
                 { "personality",           required_argument, NULL, ARG_PERSONALITY       },
                 { "image",                 required_argument, NULL, 'i'                   },
@@ -398,6 +394,7 @@ static int parse_argv(int argc, char *argv[]) {
         };
 
         int c, r;
+        const char *p, *e;
         uint64_t plus = 0, minus = 0;
         bool mask_all_settings = false, mask_no_settings = false;
 
@@ -416,24 +413,21 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case 'D':
-                        r = set_sanitized_path(&arg_directory, optarg);
+                        r = parse_path_argument_and_warn(optarg, false, &arg_directory);
                         if (r < 0)
-                                return log_error_errno(r, "Invalid root directory: %m");
-
+                                return r;
                         break;
 
                 case ARG_TEMPLATE:
-                        r = set_sanitized_path(&arg_template, optarg);
+                        r = parse_path_argument_and_warn(optarg, false, &arg_template);
                         if (r < 0)
-                                return log_error_errno(r, "Invalid template directory: %m");
-
+                                return r;
                         break;
 
                 case 'i':
-                        r = set_sanitized_path(&arg_image, optarg);
+                        r = parse_path_argument_and_warn(optarg, false, &arg_image);
                         if (r < 0)
-                                return log_error_errno(r, "Invalid image path: %m");
-
+                                return r;
                         break;
 
                 case 'x':
@@ -461,6 +455,15 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_settings_mask |= SETTING_NETWORK;
                         break;
 
+                case ARG_NETWORK_VETH_EXTRA:
+                        r = veth_extra_parse(&arg_network_veth_extra, optarg);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --network-veth-extra= parameter: %s", optarg);
+
+                        arg_private_network = true;
+                        arg_settings_mask |= SETTING_NETWORK;
+                        break;
+
                 case ARG_NETWORK_INTERFACE:
                         if (strv_extend(&arg_network_interfaces, optarg) < 0)
                                 return log_oom();
@@ -538,15 +541,16 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_CAPABILITY:
                 case ARG_DROP_CAPABILITY: {
-                        const char *state, *word;
-                        size_t length;
+                        p = optarg;
+                        for(;;) {
+                                _cleanup_free_ char *t = NULL;
 
-                        FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
-                                _cleanup_free_ char *t;
+                                r = extract_first_word(&p, &t, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse capability %s.", t);
 
-                                t = strndup(word, length);
-                                if (!t)
-                                        return log_oom();
+                                if (r == 0)
+                                        break;
 
                                 if (streq(t, "all")) {
                                         if (c == ARG_CAPABILITY)
@@ -921,6 +925,10 @@ static int parse_argv(int argc, char *argv[]) {
         if (r < 0)
                 return r;
 
+        e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE");
+        if (e)
+                arg_container_service_name = e;
+
         return 1;
 }
 
@@ -1189,6 +1197,7 @@ static int copy_devnodes(const char *dest) {
 static int setup_pts(const char *dest) {
         _cleanup_free_ char *options = NULL;
         const char *p;
+        int r;
 
 #ifdef HAVE_SELINUX
         if (arg_selinux_apifs_context)
@@ -1211,20 +1220,23 @@ static int setup_pts(const char *dest) {
                 return log_error_errno(errno, "Failed to create /dev/pts: %m");
         if (mount("devpts", p, "devpts", MS_NOSUID|MS_NOEXEC, options) < 0)
                 return log_error_errno(errno, "Failed to mount /dev/pts: %m");
-        if (userns_lchown(p, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to chown /dev/pts: %m");
+        r = userns_lchown(p, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to chown /dev/pts: %m");
 
         /* Create /dev/ptmx symlink */
         p = prefix_roota(dest, "/dev/ptmx");
         if (symlink("pts/ptmx", p) < 0)
                 return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m");
-        if (userns_lchown(p, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to chown /dev/ptmx: %m");
+        r = userns_lchown(p, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to chown /dev/ptmx: %m");
 
         /* And fix /dev/pts/ptmx ownership */
         p = prefix_roota(dest, "/dev/pts/ptmx");
-        if (userns_lchown(p, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to chown /dev/pts/ptmx: %m");
+        r = userns_lchown(p, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m");
 
         return 0;
 }
@@ -1406,7 +1418,7 @@ static int setup_journal(const char *directory) {
 
                         r = userns_mkdir(directory, p, 0755, 0, 0);
                         if (r < 0)
-                                log_warning_errno(errno, "Failed to create directory %s: %m", q);
+                                log_warning_errno(r, "Failed to create directory %s: %m", q);
                         return 0;
                 }
 
@@ -1420,15 +1432,11 @@ static int setup_journal(const char *directory) {
                         if (errno == ENOTDIR) {
                                 log_error("%s already exists and is neither a symlink nor a directory", p);
                                 return r;
-                        } else {
-                                log_error_errno(errno, "Failed to remove %s: %m", p);
-                                return -errno;
-                        }
+                        } else
+                                return log_error_errno(errno, "Failed to remove %s: %m", p);
                 }
-        } else if (r != -ENOENT) {
-                log_error_errno(errno, "readlink(%s) failed: %m", p);
-                return r;
-        }
+        } else if (r != -ENOENT)
+                return log_error_errno(r, "readlink(%s) failed: %m", p);
 
         if (arg_link_journal == LINK_GUEST) {
 
@@ -1436,15 +1444,13 @@ static int setup_journal(const char *directory) {
                         if (arg_link_journal_try) {
                                 log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p);
                                 return 0;
-                        } else {
-                                log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p);
-                                return -errno;
-                        }
+                        } else
+                                return log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p);
                 }
 
                 r = userns_mkdir(directory, p, 0755, 0, 0);
                 if (r < 0)
-                        log_warning_errno(errno, "Failed to create directory %s: %m", q);
+                        log_warning_errno(r, "Failed to create directory %s: %m", q);
                 return 0;
         }
 
@@ -1456,10 +1462,8 @@ static int setup_journal(const char *directory) {
                         if (arg_link_journal_try) {
                                 log_debug_errno(errno, "Failed to create %s, skipping journal setup: %m", p);
                                 return 0;
-                        } else {
-                                log_error_errno(errno, "Failed to create %s: %m", p);
-                                return r;
-                        }
+                        } else
+                                return log_error_errno(errno, "Failed to create %s: %m", p);
                 }
 
         } else if (access(p, F_OK) < 0)
@@ -1469,10 +1473,8 @@ static int setup_journal(const char *directory) {
                 log_warning("%s is not empty, proceeding anyway.", q);
 
         r = userns_mkdir(directory, p, 0755, 0, 0);
-        if (r < 0) {
-                log_error_errno(errno, "Failed to create %s: %m", q);
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to create %s: %m", q);
 
         if (mount(p, q, NULL, MS_BIND, NULL) < 0)
                 return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m");
@@ -1613,20 +1615,24 @@ finish:
 
 static int setup_propagate(const char *root) {
         const char *p, *q;
+        int r;
 
         (void) mkdir_p("/run/systemd/nspawn/", 0755);
         (void) mkdir_p("/run/systemd/nspawn/propagate", 0600);
         p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
         (void) mkdir_p(p, 0600);
 
-        if (userns_mkdir(root, "/run/systemd", 0755, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to create /run/systemd: %m");
+        r = userns_mkdir(root, "/run/systemd", 0755, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create /run/systemd: %m");
 
-        if (userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to create /run/systemd/nspawn: %m");
+        r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m");
 
-        if (userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0) < 0)
-                return log_error_errno(errno, "Failed to create /run/systemd/nspawn/incoming: %m");
+        r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m");
 
         q = prefix_roota(root, "/run/systemd/nspawn/incoming");
         if (mount(p, q, NULL, MS_BIND, NULL) < 0)
@@ -1676,7 +1682,7 @@ static int setup_image(char **device_path, int *loop_nr) {
         }
 
         if (!S_ISREG(st.st_mode)) {
-                log_error_errno(errno, "%s is not a regular file or block device: %m", arg_image);
+                log_error("%s is not a regular file or block device.", arg_image);
                 return -EINVAL;
         }
 
@@ -1768,8 +1774,7 @@ static int dissect_image(
                 if (errno == 0)
                         return log_oom();
 
-                log_error_errno(errno, "Failed to set device on blkid probe: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to set device on blkid probe: %m");
         }
 
         blkid_probe_enable_partitions(b, 1);
@@ -1785,8 +1790,7 @@ static int dissect_image(
         } else if (r != 0) {
                 if (errno == 0)
                         errno = EIO;
-                log_error_errno(errno, "Failed to probe: %m");
-                return -errno;
+                return log_error_errno(errno, "Failed to probe: %m");
         }
 
         (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
@@ -1909,8 +1913,7 @@ static int dissect_image(
                         if (!errno)
                                 errno = ENOMEM;
 
-                        log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image);
-                        return -errno;
+                        return log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image);
                 }
 
                 qn = udev_device_get_devnum(q);
@@ -2117,8 +2120,7 @@ static int mount_device(const char *what, const char *where, const char *directo
         if (!b) {
                 if (errno == 0)
                         return log_oom();
-                log_error_errno(errno, "Failed to allocate prober for %s: %m", what);
-                return -errno;
+                return log_error_errno(errno, "Failed to allocate prober for %s: %m", what);
         }
 
         blkid_probe_enable_superblocks(b, 1);
@@ -2132,8 +2134,7 @@ static int mount_device(const char *what, const char *where, const char *directo
         } else if (r != 0) {
                 if (errno == 0)
                         errno = EIO;
-                log_error_errno(errno, "Failed to probe %s: %m", what);
-                return -errno;
+                return log_error_errno(errno, "Failed to probe %s: %m", what);
         }
 
         errno = 0;
@@ -2322,9 +2323,9 @@ static int determine_names(void) {
                         }
 
                         if (i->type == IMAGE_RAW)
-                                r = set_sanitized_path(&arg_image, i->path);
+                                r = free_and_strdup(&arg_image, i->path);
                         else
-                                r = set_sanitized_path(&arg_directory, i->path);
+                                r = free_and_strdup(&arg_directory, i->path);
                         if (r < 0)
                                 return log_error_errno(r, "Invalid image directory: %m");
 
@@ -2416,10 +2417,10 @@ static int inner_child(
                 FDSet *fds) {
 
         _cleanup_free_ char *home = NULL;
-        unsigned n_env = 2;
+        unsigned n_env = 1;
         const char *envp[] = {
                 "PATH=" DEFAULT_PATH_SPLIT_USR,
-                "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
+                NULL, /* container */
                 NULL, /* TERM */
                 NULL, /* HOME */
                 NULL, /* USER */
@@ -2450,7 +2451,7 @@ static int inner_child(
                 }
         }
 
-        r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context);
         if (r < 0)
                 return r;
 
@@ -2497,8 +2498,9 @@ static int inner_child(
                 rtnl_socket = safe_close(rtnl_socket);
         }
 
-        if (drop_capabilities() < 0)
-                return log_error_errno(errno, "drop_capabilities() failed: %m");
+        r = drop_capabilities();
+        if (r < 0)
+                return log_error_errno(r, "drop_capabilities() failed: %m");
 
         setup_hostname();
 
@@ -2520,6 +2522,9 @@ static int inner_child(
         if (r < 0)
                 return r;
 
+        /* LXC sets container=lxc, so follow the scheme here */
+        envp[n_env++] = strjoina("container=", arg_container_service_name);
+
         envp[n_env] = strv_find_prefix(environ, "TERM=");
         if (envp[n_env])
                 n_env ++;
@@ -2598,8 +2603,9 @@ static int inner_child(
                 execle("/bin/sh", "-sh", NULL, env_use);
         }
 
+        r = -errno;
         (void) log_open();
-        return log_error_errno(errno, "execv() failed: %m");
+        return log_error_errno(r, "execv() failed: %m");
 }
 
 static int outer_child(
@@ -2705,7 +2711,7 @@ static int outer_child(
                         return log_error_errno(r, "Failed to make tree read-only: %m");
         }
 
-        r = mount_all(directory, arg_userns, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+        r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
         if (r < 0)
                 return r;
 
@@ -2840,7 +2846,7 @@ static int load_settings(void) {
                         p = j;
                         j = NULL;
 
-                        /* By default we trust configuration from /etc and /run */
+                        /* By default, we trust configuration from /etc and /run */
                         if (arg_settings_trusted < 0)
                                 arg_settings_trusted = true;
 
@@ -2870,7 +2876,7 @@ static int load_settings(void) {
                         if (!f && errno != ENOENT)
                                 return log_error_errno(errno, "Failed to open %s: %m", p);
 
-                        /* By default we do not trust configuration from /var/lib/machines */
+                        /* By default, we do not trust configuration from /var/lib/machines */
                         if (arg_settings_trusted < 0)
                                 arg_settings_trusted = false;
                 }
@@ -2912,11 +2918,17 @@ static int load_settings(void) {
         }
 
         if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
+                uint64_t plus;
 
-                if (!arg_settings_trusted && settings->capability != 0)
-                        log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
-                else
-                        arg_retain |= settings->capability;
+                plus = settings->capability;
+                if (settings_private_network(settings))
+                        plus |= (1ULL << CAP_NET_ADMIN);
+
+                if (!arg_settings_trusted && plus != 0) {
+                        if (settings->capability != 0)
+                                log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
+                } else
+                        arg_retain |= plus;
 
                 arg_retain &= ~settings->drop_capability;
         }
@@ -2967,11 +2979,15 @@ static int load_settings(void) {
              settings->network_bridge ||
              settings->network_interfaces ||
              settings->network_macvlan ||
-             settings->network_ipvlan)) {
+             settings->network_ipvlan ||
+             settings->network_veth_extra)) {
 
                 if (!arg_settings_trusted)
                         log_warning("Ignoring network settings, file %s is not trusted.", p);
                 else {
+                        arg_network_veth = settings_network_veth(settings);
+                        arg_private_network = settings_private_network(settings);
+
                         strv_free(arg_network_interfaces);
                         arg_network_interfaces = settings->network_interfaces;
                         settings->network_interfaces = NULL;
@@ -2984,13 +3000,13 @@ static int load_settings(void) {
                         arg_network_ipvlan = settings->network_ipvlan;
                         settings->network_ipvlan = NULL;
 
+                        strv_free(arg_network_veth_extra);
+                        arg_network_veth_extra = settings->network_veth_extra;
+                        settings->network_veth_extra = NULL;
+
                         free(arg_network_bridge);
                         arg_network_bridge = settings->network_bridge;
                         settings->network_bridge = NULL;
-
-                        arg_network_veth = settings->network_veth > 0 || settings->network_bridge;
-
-                        arg_private_network = true; /* all these settings imply private networking */
                 }
         }
 
@@ -3096,7 +3112,7 @@ int main(int argc, char *argv[]) {
                                 goto finish;
                         }
 
-                        r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
+                        r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
                         if (r < 0) {
                                 log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
                                 goto finish;
@@ -3120,7 +3136,7 @@ int main(int argc, char *argv[]) {
                         }
 
                         if (arg_template) {
-                                r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
+                                r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
                                 if (r == -EEXIST) {
                                         if (!arg_quiet)
                                                 log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
@@ -3143,10 +3159,9 @@ int main(int argc, char *argv[]) {
                 } else {
                         const char *p;
 
-                        p = strjoina(arg_directory,
-                                       argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/");
-                        if (access(p, F_OK) < 0) {
-                                log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory);
+                        p = strjoina(arg_directory, "/usr/");
+                        if (laccess(p, F_OK) < 0) {
+                                log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory);
                                 r = -EINVAL;
                                 goto finish;
                         }
@@ -3235,8 +3250,7 @@ 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 };
+                _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 = {
@@ -3415,6 +3429,10 @@ int main(int argc, char *argv[]) {
                                 }
                         }
 
+                        r = setup_veth_extra(arg_machine, pid, arg_network_veth_extra);
+                        if (r < 0)
+                                goto finish;
+
                         r = setup_macvlan(arg_machine, pid, arg_network_macvlan);
                         if (r < 0)
                                 goto finish;
@@ -3435,7 +3453,8 @@ int main(int argc, char *argv[]) {
                                         arg_custom_mounts, arg_n_custom_mounts,
                                         arg_kill_signal,
                                         arg_property,
-                                        arg_keep_unit);
+                                        arg_keep_unit,
+                                        arg_container_service_name);
                         if (r < 0)
                                 goto finish;
                 }
@@ -3591,7 +3610,7 @@ finish:
         if (remove_subvol && arg_directory) {
                 int k;
 
-                k = btrfs_subvol_remove(arg_directory, true);
+                k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                 if (k < 0)
                         log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
         }
@@ -3615,6 +3634,7 @@ finish:
         strv_free(arg_network_interfaces);
         strv_free(arg_network_macvlan);
         strv_free(arg_network_ipvlan);
+        strv_free(arg_network_veth_extra);
         strv_free(arg_parameters);
         custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
         expose_port_free_all(arg_expose_ports);
index 0dca8914479b1e7532e2db608c133ec55a90863e..ee10b105eab86f364d61e5020fab788232b9e660 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <nss.h>
-#include <netdb.h>
 #include <errno.h>
-#include <string.h>
 #include <net/if.h>
+#include <netdb.h>
+#include <nss.h>
 #include <stdlib.h>
+#include <string.h>
 
+#include "alloc-util.h"
+#include "hostname-util.h"
 #include "local-addresses.h"
 #include "macro.h"
 #include "nss-util.h"
-#include "hostname-util.h"
+#include "string-util.h"
 #include "util.h"
 
 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
index 604130ed250551497dbdb72e03be99c558603e47..969fa9619e17454070a4ed6335eeef38f8dc85ac 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <nss.h>
 #include <netdb.h>
+#include <nss.h>
 
 #include "sd-bus.h"
 #include "sd-login.h"
-#include "macro.h"
-#include "util.h"
-#include "nss-util.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
 #include "bus-common-errors.h"
-#include "in-addr-util.h"
+#include "bus-util.h"
 #include "hostname-util.h"
+#include "in-addr-util.h"
+#include "macro.h"
+#include "nss-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
 NSS_GETPW_PROTOTYPES(mymachines);
index ef5eb7b4cfeef8def9085741616f6976d331b588..ed59a71e3d3acd810d8288c9179b81f5fbd5fa99 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <nss.h>
-#include <netdb.h>
+#include <dlfcn.h>
 #include <errno.h>
-#include <string.h>
+#include <netdb.h>
+#include <nss.h>
 #include <stdlib.h>
-#include <dlfcn.h>
+#include <string.h>
 
 #include "sd-bus.h"
-#include "bus-util.h"
+
 #include "bus-common-errors.h"
+#include "bus-util.h"
+#include "in-addr-util.h"
 #include "macro.h"
 #include "nss-util.h"
+#include "string-util.h"
 #include "util.h"
-#include "in-addr-util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
index 73b7bd2c01c485c2779879bde648ccc918fed4ea..0ece72f6fe23b3ea9097397446addbe53b0cf84e 100644 (file)
 
 #include "sd-path.h"
 
+#include "alloc-util.h"
 #include "log.h"
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
 
 static const char *arg_suffix = NULL;
index cf6a2394029d3e7272967c645243c0a92aa35345..dc2911e4e8b2558b8f779462838eb8f95be5ef60 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <stdbool.h>
 #include <errno.h>
-#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
 #include <sys/prctl.h>
+#include <unistd.h>
 
-#include "util.h"
 #include "process-util.h"
 #include "signal-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "proc-cmdline.h"
 
 static bool arg_skip = false;
 static bool arg_force = false;
index f4778fc16a7d04e938da87478baedf46a1935e63..d857ade36a0a4cdf579ac09bd544f20fb6a11810 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "log.h"
-#include "util.h"
 #include "mkdir.h"
+#include "string-util.h"
+#include "util.h"
 
 #define POOL_SIZE_MIN 512
 
index d4e6ba4bf91a297171df17e2532514415e5f4399..6ecadbf3e5eef9aef238eb86abf006257dde5dce 100644 (file)
 #include <stdio.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "log.h"
-#include "util.h"
 #include "mkdir.h"
+#include "string-util.h"
+#include "util.h"
 
 #ifndef RC_LOCAL_SCRIPT_PATH_START
 #define RC_LOCAL_SCRIPT_PATH_START "/etc/rc.d/rc.local"
@@ -60,8 +62,7 @@ static int add_symlink(const char *service, const char *where) {
                 if (errno == EEXIST)
                         return 0;
 
-                log_error_errno(errno, "Failed to create symlink %s: %m", to);
-                return -errno;
+                return log_error_errno(errno, "Failed to create symlink %s: %m", to);
         }
 
         return 1;
index f904e48e753d35c5a80c40ef16f5c2b8f03e444e..57f99c9ef0cc83c17f7b7a0361d3a45278f3ea63 100644 (file)
 #include <sys/wait.h>
 #include <mntent.h>
 
+#include "exit-status.h"
 #include "log.h"
-#include "util.h"
+#include "mount-setup.h"
+#include "mount-util.h"
 #include "path-util.h"
 #include "signal-util.h"
-#include "mount-setup.h"
-#include "exit-status.h"
+#include "util.h"
 
 /* Goes through /etc/fstab and remounts all API file systems, applying
  * options that are in /etc/fstab that systemd might not have
index d0d61b98ed3102e1d1b670ab0e9f051e8acdc005..166ab470edc51620afdb33e9fee10f17db37040b 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
-#include <string.h>
 #include <errno.h>
-#include <sys/un.h>
 #include <stddef.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
+#include "fd-util.h"
 #include "log.h"
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
 
 static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
@@ -50,9 +52,10 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
 }
 
 int main(int argc, char *argv[]) {
-        int fd = -1, r = EXIT_FAILURE;
+        _cleanup_close_ int fd = -1;
         char packet[LINE_MAX];
         size_t length;
+        int r;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -60,14 +63,14 @@ int main(int argc, char *argv[]) {
 
         if (argc != 3) {
                 log_error("Wrong number of arguments.");
-                goto finish;
+                return EXIT_FAILURE;
         }
 
         if (streq(argv[1], "1")) {
 
                 packet[0] = '+';
                 if (!fgets(packet+1, sizeof(packet)-1, stdin)) {
-                        log_error_errno(errno, "Failed to read password: %m");
+                        r = log_error_errno(errno, "Failed to read password: %m");
                         goto finish;
                 }
 
@@ -78,22 +81,20 @@ int main(int argc, char *argv[]) {
                 length = 1;
         } else {
                 log_error("Invalid first argument %s", argv[1]);
+                r = -EINVAL;
                 goto finish;
         }
 
         fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
         if (fd < 0) {
-                log_error_errno(errno, "socket() failed: %m");
+                r = log_error_errno(errno, "socket() failed: %m");
                 goto finish;
         }
 
-        if (send_on_socket(fd, argv[2], packet, length) < 0)
-                goto finish;
-
-        r = EXIT_SUCCESS;
+        r = send_on_socket(fd, argv[2], packet, length);
 
 finish:
-        safe_close(fd);
+        memory_erase(packet, sizeof(packet));
 
-        return r;
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 97516a87a8c8d859d5de3a3f177da36738864118..432e62dd9f8efd0177bd3345dae10ae18c151d2d 100644 (file)
 #include "sd-bus.h"
 
 #include "af-list.h"
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "in-addr-util.h"
+#include "parse-util.h"
 #include "resolved-def.h"
 #include "resolved-dns-packet.h"
 
@@ -298,8 +300,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
 
         percent = strchr(s, '%');
         if (percent) {
-                r = safe_atoi(percent+1, &ifi);
-                if (r < 0 || ifi <= 0) {
+                if (parse_ifindex(percent+1, &ifi) < 0) {
                         ifi = if_nametoindex(percent+1);
                         if (ifi <= 0)
                                 return -EINVAL;
@@ -519,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) {
                 case 'i': {
                         int ifi;
 
-                        if (safe_atoi(optarg, &ifi) >= 0 && ifi > 0)
+                        if (parse_ifindex(optarg, &ifi) >= 0)
                                 arg_ifindex = ifi;
                         else {
                                 ifi = if_nametoindex(optarg);
index bf1b7c8ab449b965f5eea69ab07775682cca0d4d..f0a3b607d4a85d7716e7a088b4f31bcde7098059 100644 (file)
@@ -19,9 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-util.h"
-
 #include "dns-domain.h"
 #include "resolved-bus.h"
 #include "resolved-def.h"
index cc8d5fa76a2cd0cd261cae75b8028a6adeb031c5..920771955136d3ab56658578271b158520003b4c 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
+#include "alloc-util.h"
 #include "conf-parser.h"
-
+#include "def.h"
+#include "extract-word.h"
+#include "parse-util.h"
 #include "resolved-conf.h"
+#include "string-util.h"
 
 int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) {
-        const char *word, *state;
-        size_t length;
         DnsServer *first;
         int r;
 
@@ -34,19 +36,22 @@ int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string)
 
         first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers;
 
-        FOREACH_WORD_QUOTED(word, length, string, state) {
-                char buffer[length+1];
-                int family;
+        for(;;) {
+                _cleanup_free_ char *word = NULL;
                 union in_addr_union addr;
                 bool found = false;
                 DnsServer *s;
+                int family;
 
-                memcpy(buffer, word, length);
-                buffer[length] = 0;
+                r = extract_first_word(&string, &word, NULL, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string);
+                if (r == 0)
+                        break;
 
-                r = in_addr_from_string_auto(buffer, &family, &addr);
+                r = in_addr_from_string_auto(word, &family, &addr);
                 if (r < 0) {
-                        log_warning("Ignoring invalid DNS address '%s'", buffer);
+                        log_warning("Ignoring invalid DNS address '%s'", word);
                         continue;
                 }
 
@@ -92,7 +97,7 @@ int config_parse_dnsv(
                 /* Empty assignment means clear the list */
                 manager_flush_dns_servers(m, ltype);
         else {
-                /* Otherwise add to the list */
+                /* Otherwise, add to the list */
                 r = manager_parse_dns_server(m, ltype, rvalue);
                 if (r < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
@@ -145,8 +150,8 @@ int config_parse_support(
 int manager_parse_config_file(Manager *m) {
         assert(m);
 
-        return config_parse_many("/etc/systemd/resolved.conf",
-                                 CONF_DIRS_NULSTR("systemd/resolved.conf"),
+        return config_parse_many(PKGSYSCONFDIR "/resolved.conf",
+                                 CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
                                  "Resolve\0",
                                  config_item_perf_lookup, resolved_gperf_lookup,
                                  false, m);
index 89b9b0e1ea034fcd90844b13f98197648d81ca57..3cf9c6807477f815e6929ef6854d4291bee51413 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "resolved-dns-answer.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "resolved-dns-answer.h"
+#include "string-util.h"
 
 DnsAnswer *dns_answer_new(unsigned n) {
         DnsAnswer *a;
index ab13636bc182d3bb99ff2b3e038c7042932af08d..04f64022e01c4444e404e8f6e6f9c598afff04a5 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "resolved-dns-cache.h"
 #include "resolved-dns-packet.h"
 
index bebd1ee4a6e55f64d32ddd80c496d2b520769bdb..f23b3cf89340d120119ed20c53900250611e66e6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
-#include "utf8.h"
-#include "util.h"
-#include "strv.h"
-#include "unaligned.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
 #include "resolved-dns-packet.h"
+#include "string-table.h"
+#include "strv.h"
+#include "unaligned.h"
+#include "utf8.h"
+#include "util.h"
 
 int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
         DnsPacket *p;
index 4b1d18b2ef1ef4158d552ce80bed2a2cd11bde8c..f7cb84e2a62fed26af548d5b06f2d41ad7405c32 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "hostname-util.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "hostname-util.h"
 #include "local-addresses.h"
-
 #include "resolved-dns-query.h"
 
 /* How long to wait for the query in total */
index 1507f22da0998cfdd05b7cc9e82ead6c505507c5..48951221dc9ccbd090c3573d469aa40e9888968a 100644 (file)
@@ -19,8 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "resolved-dns-question.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "resolved-dns-question.h"
 
 DnsQuestion *dns_question_new(unsigned n) {
         DnsQuestion *q;
index 2bc8cc16397ad2d1f4c0c76ca76e849381dea344..ba2ea686f33ec13d75841f624590fbde71d1ca7e 100644 (file)
 
 #include <math.h>
 
-#include "strv.h"
-
+#include "alloc-util.h"
 #include "dns-domain.h"
-#include "resolved-dns-rr.h"
-#include "resolved-dns-packet.h"
 #include "dns-type.h"
+#include "hexdecoct.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-rr.h"
+#include "string-util.h"
+#include "strv.h"
 
 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
         DnsResourceKey *k;
index 9e6f595a1b720d818305a757ae0948e0cc1ccd46..b15370b017b8e9d5c06c74ddbf369608364c7233 100644 (file)
 
 #include <netinet/tcp.h>
 
-#include "missing.h"
-#include "strv.h"
-#include "socket-util.h"
 #include "af-list.h"
-#include "random-util.h"
-#include "hostname-util.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
-#include "resolved-llmnr.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "missing.h"
+#include "random-util.h"
 #include "resolved-dns-scope.h"
+#include "resolved-llmnr.h"
+#include "socket-util.h"
+#include "strv.h"
 
 #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
 #define MULTICAST_RATELIMIT_BURST 1000
index 8693911e65440180ccd1aedababa4c0937137bde..e803f635abda8835e93e0eba1638ac4383fc9756 100644 (file)
@@ -19,9 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "siphash24.h"
-
+#include "alloc-util.h"
 #include "resolved-dns-server.h"
+#include "siphash24.h"
 
 /* After how much time to repeat classic DNS requests */
 #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
index 7f47e7223a8a79379005605f775d5e218861cebe..1c501182fb77e5bba2321d23295e12a5093d6afb 100644 (file)
@@ -21,6 +21,9 @@
 
 #include <netinet/tcp.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "missing.h"
 #include "resolved-dns-stream.h"
 
index b30473dd7e9686978b2a4987843601eed23d706c..6545f6cd8a7ed39a37b9fd4d945e2257f1b608c9 100644 (file)
 ***/
 
 #include "af-list.h"
-
-#include "resolved-llmnr.h"
-#include "resolved-dns-transaction.h"
-#include "random-util.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "fd-util.h"
+#include "random-util.h"
+#include "resolved-dns-transaction.h"
+#include "resolved-llmnr.h"
+#include "string-table.h"
 
 DnsTransaction* dns_transaction_free(DnsTransaction *t) {
         DnsQuery *q;
index 8a59bd1c3ceb056a62a577d67e32092bd1a55f74..48dcf76daac9bf40e252c2c56516467176ad3aea 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "list.h"
-
-#include "resolved-dns-zone.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "list.h"
 #include "resolved-dns-packet.h"
+#include "resolved-dns-zone.h"
+#include "string-util.h"
 
 /* Never allow more than 1K entries */
 #define ZONE_MAX 1024
index b9fd8e3dbcdba47f8d89365358398e652c1b4447..28926410753ffae5925bd94e7731808cab5ef640 100644 (file)
 #include <net/if.h>
 
 #include "sd-network.h"
-#include "strv.h"
+
+#include "alloc-util.h"
 #include "missing.h"
+#include "parse-util.h"
 #include "resolved-link.h"
+#include "string-util.h"
+#include "strv.h"
 
 int link_new(Manager *m, Link **ret, int ifindex) {
         _cleanup_(link_freep) Link *l = NULL;
index 8afaf8db6e6dfe4854705c71eb38a990358047c7..5c3a4a00c30a446a7365863a5cda9fafb7487694 100644 (file)
@@ -22,8 +22,9 @@
 #include <resolv.h>
 #include <netinet/in.h>
 
-#include "resolved-manager.h"
+#include "fd-util.h"
 #include "resolved-llmnr.h"
+#include "resolved-manager.h"
 
 void manager_llmnr_stop(Manager *m) {
         assert(m);
index de924e3ed95e3cb9591c946d6fc33db6c5ee92b7..a588538b52afa2eb892804444ba4cbcd1b212531 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
+#include <netinet/in.h>
+#include <poll.h>
 #include <resolv.h>
 #include <sys/ioctl.h>
-#include <poll.h>
-#include <netinet/in.h>
 
-#include "netlink-util.h"
-#include "network-internal.h"
-#include "socket-util.h"
 #include "af-list.h"
-#include "utf8.h"
+#include "alloc-util.h"
+#include "dns-domain.h"
+#include "fd-util.h"
 #include "fileio-label.h"
+#include "hostname-util.h"
+#include "io-util.h"
+#include "netlink-util.h"
+#include "network-internal.h"
 #include "ordered-set.h"
+#include "parse-util.h"
 #include "random-util.h"
-#include "hostname-util.h"
-
-#include "dns-domain.h"
-#include "resolved-conf.h"
 #include "resolved-bus.h"
-#include "resolved-manager.h"
+#include "resolved-conf.h"
 #include "resolved-llmnr.h"
+#include "resolved-manager.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "utf8.h"
 
 #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
 
index 32e61af9251dff82b44da75f4aa3eb170f03239c..7ba0546f4a8b698ba80d87079f32d33dd79be682 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "sd-event.h"
 #include "sd-daemon.h"
+#include "sd-event.h"
+
+#include "capability-util.h"
 #include "mkdir.h"
-#include "capability.h"
+#include "resolved-conf.h"
+#include "resolved-manager.h"
 #include "selinux-util.h"
 #include "signal-util.h"
-
-#include "resolved-manager.h"
-#include "resolved-conf.h"
+#include "user-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_(manager_freep) Manager *m = NULL;
index d8a2f3694eaae2a649c8a21c675ef6d78a7bd0a2..5c45a3ae6c519d17f2edb290c0e2faaea6ce16c3 100644 (file)
 #include "libudev.h"
 #include "sd-daemon.h"
 
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "io-util.h"
 #include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "udev-util.h"
 #include "util.h"
 
@@ -40,8 +48,8 @@ static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
         [RFKILL_TYPE_WIMAX] = "wimax",
         [RFKILL_TYPE_WWAN] = "wwan",
         [RFKILL_TYPE_GPS] = "gps",
-        [RFKILL_TYPE_FM] "fm",
-        [RFKILL_TYPE_NFC] "nfc",
+        [RFKILL_TYPE_FM] "fm",
+        [RFKILL_TYPE_NFC] "nfc",
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
@@ -204,7 +212,7 @@ static int load_state(
         assert(udev);
         assert(event);
 
-        if (!shall_restore_state())
+        if (shall_restore_state() == 0)
                 return 0;
 
         r = find_device(udev, event, &device);
index 93d8cd1d08076ee8a83e21157bd41b1a2fac4e02..38a482bb117a23e6f3a0f59869907fccf76bde82 100644 (file)
 #include "sd-bus.h"
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-util.h"
 #include "calendarspec.h"
 #include "env-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
 #include "path-util.h"
 #include "ptyfwd.h"
@@ -38,6 +40,8 @@
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
+#include "user-util.h"
+#include "parse-util.h"
 
 static bool arg_ask_password = true;
 static bool arg_scope = false;
@@ -1153,14 +1157,15 @@ int main(int argc, char* argv[]) {
         if (r <= 0)
                 goto finish;
 
-        if (argc > optind) {
-                r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command);
+        if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) {
+                /* Patch in an absolute path */
+
+                r = find_binary(argv[optind], &command);
                 if (r < 0) {
-                        log_error_errno(r, "Failed to find executable %s%s: %m",
-                                        argv[optind],
-                                        arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system");
+                        log_error_errno(r, "Failed to find executable %s: %m", argv[optind]);
                         goto finish;
                 }
+
                 argv[optind] = command;
         }
 
index bd8c9887515d79ec817751ca50fda6db6cbbdbd9..79f5a605796ad3688f4358fe65920b9c7c2677cf 100644 (file)
 #include <errno.h>
 #include <stdbool.h>
 
+#include "alloc-util.h"
 #include "acl-util.h"
-#include "util.h"
+#include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
         acl_entry_t i;
index 64e50401b9d0a586a390cbdba8e11fa9af9d3044..8e36067f7458af1d0becf3b277c42a58fbbeec18 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
+#include <fcntl.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-#include <fcntl.h>
 
-#include <util.h>
-#include <fileio.h>
-#include <time-util.h>
-#include <acpi-fpdt.h>
+#include "alloc-util.h"
+#include "acpi-fpdt.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "time-util.h"
+#include "util.h"
 
 struct acpi_table_header {
         char signature[4];
index c2bbd330bdd212051bbe5418d1f0ec7987b80a01..f6ac43adfe7756536b6da19532a8b473adaaff21 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
-#include "util.h"
-#include "fileio.h"
+#include "alloc-util.h"
 #include "apparmor-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "util.h"
 
 bool mac_apparmor_use(void) {
         static int cached_use = -1;
index 8e72e7a36a7e3adb3887b56dad4a8c8a53de6e1a..e2efa4272b7c556f46f385169a2ed0a5329e312d 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <sys/utsname.h>
 
+#include "string-table.h"
+#include "string-util.h"
 #include "architecture.h"
 
 int uname_architecture(void) {
index f8cf11b297434aad908977eee5395e9a6e610b93..fbe2b6fecb95e7d6911641069b05f9d076cb0cae 100644 (file)
 #include <termios.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "io-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "random-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "umask-util.h"
 #include "util.h"
-#include "ask-password-api.h"
 
 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
 
@@ -78,6 +84,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
                 if (n < m)
                         break;
 
+                memory_erase(p, n);
                 free(p);
                 m *= 2;
         }
@@ -86,12 +93,14 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
         if (!l)
                 return -ENOMEM;
 
+        memory_erase(p, n);
+
         *ret = l;
         return 0;
 }
 
 static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
-        _cleanup_strv_free_ char **l = NULL;
+        _cleanup_strv_free_erase_ char **l = NULL;
         _cleanup_free_ char *p = NULL;
         key_serial_t serial;
         size_t n;
@@ -124,6 +133,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
         assert(p[n-1] == 0);
 
         serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING);
+        memory_erase(p, n);
         if (serial == -1)
                 return -errno;
 
@@ -361,9 +371,12 @@ int ask_password_tty(
 
                         dirty = true;
                 }
+
+                c = 'x';
         }
 
         x = strndup(passphrase, p);
+        memory_erase(passphrase, p);
         if (!x) {
                 r = -ENOMEM;
                 goto finish;
@@ -459,7 +472,7 @@ int ask_password_agent(
 
         fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
         if (fd < 0) {
-                r = -errno;
+                r = fd;
                 goto finish;
         }
 
@@ -620,6 +633,7 @@ int ask_password_agent(
                                 l = strv_new("", NULL);
                         else
                                 l = strv_parse_nulstr(passphrase+1, n-1);
+                        memory_erase(passphrase, n);
                         if (!l) {
                                 r = -ENOMEM;
                                 goto finish;
@@ -688,9 +702,12 @@ int ask_password_auto(
                 if (r < 0)
                         return r;
 
-                r = strv_consume(&l, s);
-                if (r < 0)
+                r = strv_push(&l, s);
+                if (r < 0) {
+                        string_erase(s);
+                        free(s);
                         return -ENOMEM;
+                }
 
                 *ret = l;
                 return 0;
index 48492ed13d2d459c3e71435b1c6a70db637483c8..e605490c3211c58c8ccafab1f09aff0317d9e6c6 100644 (file)
 ***/
 
 #include <errno.h>
-#include <sys/stat.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "base-filesystem.h"
+#include "fd-util.h"
 #include "log.h"
 #include "macro.h"
+#include "string-util.h"
+#include "umask-util.h"
+#include "user-util.h"
 #include "util.h"
 
 typedef struct BaseFilesystem {
index 52ec7eee7f62f9f35b74aa8c7b59ca555843524c..73ceeba18f986289698cecc7cb1f83e8183950a1 100644 (file)
 
 #include <sys/socket.h>
 
+#include "sd-bus.h"
 #include "sd-daemon.h"
 #include "sd-event.h"
-#include "sd-bus.h"
 
+#include "alloc-util.h"
 #include "bus-error.h"
 #include "bus-internal.h"
 #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 "fd-util.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 "unit-name.h"
+#include "user-util.h"
+#include "utf8.h"
 #include "util.h"
 
-#include "bus-util.h"
-
 static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         sd_event *e = userdata;
 
@@ -1416,6 +1428,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                         return bus_log_create_error(r);
 
                 return 0;
+        } else if (streq(field, "EnvironmentFile")) {
+                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles");
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(m, "v", "a(sb)", 1,
+                                          eq[0] == '-' ? eq + 1 : eq,
+                                          eq[0] == '-');
+                if (r < 0)
+                        return r;
+                return 0;
         }
 
         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
@@ -1427,7 +1450,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                        "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
                        "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
                        "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
-                       "SyslogLevelPrefix")) {
+                       "SyslogLevelPrefix", "Delegate")) {
 
                 r = parse_boolean(eq);
                 if (r < 0) {
@@ -1494,10 +1517,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                               "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
                               "StandardInput", "StandardOutput", "StandardError",
                               "Description", "Slice", "Type", "WorkingDirectory",
-                              "RootDirectory", "SyslogIdentifier"))
+                              "RootDirectory", "SyslogIdentifier", "ProtectSystem",
+                              "ProtectHome"))
                 r = sd_bus_message_append(m, "v", "s", eq);
 
-        else if (streq(field, "DeviceAllow")) {
+        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);
@@ -1608,9 +1654,52 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
 
                 r = sd_bus_message_append(m, "v", "i", i);
 
-        } else if (streq(field, "Environment")) {
+        } 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;
 
-                r = sd_bus_message_append(m, "v", "as", 1, 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;
@@ -1633,6 +1722,113 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                 }
 
                 r = sd_bus_message_append(m, "v", "t", u);
+        } 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);
@@ -2138,3 +2334,42 @@ bool is_kdbus_available(void) {
 
         return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
 }
+
+int bus_property_get_rlimit(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        struct rlimit *rl;
+        uint64_t u;
+        rlim_t x;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        rl = *(struct rlimit**) userdata;
+        if (rl)
+                x = rl->rlim_max;
+        else {
+                struct rlimit buf = {};
+                int z;
+
+                z = rlimit_from_string(strstr(property, "Limit"));
+                assert(z >= 0);
+
+                getrlimit(z, &buf);
+                x = buf.rlim_max;
+        }
+
+        /* rlim_t might have different sizes, let's map
+         * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
+         * all archs */
+        u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
+
+        return sd_bus_message_append(reply, "t", u);
+}
index f03f951dc7c1c10a819ba232997360ea52fd27c8..3925c10fde4d8df3a29d141d7a87553007d2ae7d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "sd-event.h"
 #include "sd-bus.h"
+#include "sd-event.h"
+
 #include "hashmap.h"
 #include "install.h"
+#include "string-util.h"
 #include "time-util.h"
 
 typedef enum BusTransport {
@@ -200,3 +202,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
 
 bool is_kdbus_wanted(void);
 bool is_kdbus_available(void);
+
+int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
index 31b4f6c684a9d7fa82aab08e4f3858e85f04d081..129ffc7056bebbd62be6829d5f3f6b8294900053 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <string.h>
 #include <dirent.h>
 #include <errno.h>
+#include <stdio.h>
+#include <string.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "cgroup-show.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
-#include "process-util.h"
+#include "locale-util.h"
 #include "macro.h"
 #include "path-util.h"
-#include "cgroup-util.h"
-#include "cgroup-show.h"
+#include "process-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "util.h"
 
 static int compare(const void *a, const void *b) {
         const pid_t *p = a, *q = b;
index d1cdb151b20fd112fcca7feab2d0410a2044199b..835fe524234dd9f5100eff20990ee5eba4a9a310 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <dirent.h>
+#include <fcntl.h>
+#include <mqueue.h>
 #include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/sem.h>
 #include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <mqueue.h>
 
-#include "util.h"
+#include "clean-ipc.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "clean-ipc.h"
+#include "util.h"
+#include "dirent-util.h"
 
 static int clean_sysvipc_shm(uid_t delete_uid) {
         _cleanup_fclose_ FILE *f = NULL;
@@ -44,8 +48,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
         }
 
         FOREACH_LINE(line, f, goto fail) {
@@ -87,8 +90,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
         return ret;
 
 fail:
-        log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
-        return -errno;
+        return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
 }
 
 static int clean_sysvipc_sem(uid_t delete_uid) {
@@ -102,8 +104,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
         }
 
         FOREACH_LINE(line, f, goto fail) {
@@ -140,8 +141,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
         return ret;
 
 fail:
-        log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
-        return -errno;
+        return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
 }
 
 static int clean_sysvipc_msg(uid_t delete_uid) {
@@ -155,8 +155,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
         }
 
         FOREACH_LINE(line, f, goto fail) {
@@ -194,8 +193,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
         return ret;
 
 fail:
-        log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
-        return -errno;
+        return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
 }
 
 static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
@@ -273,8 +271,7 @@ static int clean_posix_shm(uid_t uid) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_warning_errno(errno, "Failed to open /dev/shm: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to open /dev/shm: %m");
         }
 
         return clean_posix_shm_internal(dir, uid);
@@ -290,8 +287,7 @@ static int clean_posix_mq(uid_t uid) {
                 if (errno == ENOENT)
                         return 0;
 
-                log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
-                return -errno;
+                return log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
         }
 
         FOREACH_DIRENT(de, dir, goto fail) {
@@ -330,8 +326,7 @@ static int clean_posix_mq(uid_t uid) {
         return ret;
 
 fail:
-        log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
-        return -errno;
+        return log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
 }
 
 int clean_ipc(uid_t uid) {
index 1d7dd49e042ce2148f8eec444efa7f84aa689e24..a69719116c9907e06f8fa5b3845c0a4147090bad 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
+#include <fnmatch.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <fnmatch.h>
 
 #include "sd-id128.h"
-#include "util.h"
-#include "virt.h"
-#include "path-util.h"
-#include "architecture.h"
-#include "smack-util.h"
+
+#include "alloc-util.h"
 #include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
-#include "audit.h"
+#include "architecture.h"
+#include "audit-util.h"
 #include "cap-list.h"
-#include "hostname-util.h"
 #include "condition.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "glob-util.h"
+#include "hostname-util.h"
+#include "ima-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+#include "virt.h"
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
         Condition *c;
index c282fb1231bab04953ec4a90304b79f074dab07e..486122b0fd68ac9bfd35c0212aa7fc87222c1945 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <string.h>
-#include <stdio.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "sd-messages.h"
+
+#include "alloc-util.h"
 #include "conf-files.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
+#include "conf-parser.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "log.h"
-#include "utf8.h"
+#include "macro.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "signal-util.h"
-#include "conf-parser.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "utf8.h"
+#include "util.h"
 
 int config_item_table_lookup(
                 const void *table,
@@ -694,9 +702,6 @@ int config_parse_strv(const char *unit,
                       void *userdata) {
 
         char ***sv = data;
-        const char *word, *state;
-        size_t l;
-        int r;
 
         assert(filename);
         assert(lvalue);
@@ -719,25 +724,28 @@ int config_parse_strv(const char *unit,
                 return 0;
         }
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                char *n;
-
-                n = strndup(word, l);
-                if (!n)
+        for (;;) {
+                char *word = NULL;
+                int r;
+                r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+                if (r == 0)
+                        break;
+                if (r == -ENOMEM)
                         return log_oom();
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+                        break;
+                }
 
-                if (!utf8_is_valid(n)) {
+                if (!utf8_is_valid(word)) {
                         log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
-                        free(n);
+                        free(word);
                         continue;
                 }
-
-                r = strv_consume(sv, n);
+                r = strv_consume(sv, word);
                 if (r < 0)
                         return log_oom();
         }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
         return 0;
 }
index 25ad918b85d16946b478a4e0b93df86a0ce0502e..ad3c17d5bd108262fef6fad863a030086d90dc22 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "dev-setup.h"
 #include "label.h"
 #include "path-util.h"
-#include "dev-setup.h"
+#include "user-util.h"
+#include "util.h"
 
 int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
         static const char symlinks[] =
index 5680f01bd91ded78a632c107645458685d905077..7af15e00984e077f3a27cb35912b98749f2973ea 100644 (file)
 #include <stringprep.h>
 #endif
 
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "string-util.h"
 
 int dns_label_unescape(const char **name, char *dest, size_t sz) {
         const char *n;
index 1845068adb138623c62d3d22212e05a8ee65b1d5..0d44401cc2ed914fd5ad976ea62a0642b9fae0ea 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "conf-files.h"
 #include "dropin.h"
-#include "util.h"
-#include "strv.h"
-#include "mkdir.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio-label.h"
-#include "conf-files.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 int drop_in_file(const char *dir, const char *unit, unsigned level,
                  const char *name, char **_p, char **_q) {
index f087c2a5663974bbd2cc61f56a7d361428f269aa..86bb0b57c3d61227be98e3361783c4703bcc5ada 100644 (file)
 #include <string.h>
 #include <fcntl.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "stdio-util.h"
 #include "utf8.h"
+#include "util.h"
 #include "virt.h"
-#include "efivars.h"
 
 #ifdef ENABLE_EFI
 
index effc6e8e703b2451a1937a89eaf48cd39a647056..e1782878726cc95a54b54d4962f91294919e468a 100644 (file)
@@ -27,8 +27,9 @@
 #include <linux/netfilter/xt_addrtype.h>
 #include <libiptc/libiptc.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "firewall-util.h"
+#include "util.h"
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
 
index db2146f8c112c52f844ad669e8d8dab05034cfab..eb2845cddf4f8b4eb23b9db080ad97434853b1e9 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "device-nodes.h"
 #include "fstab-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
 bool fstab_is_mount_point(const char *mount) {
-        _cleanup_free_ char *device = NULL;
         _cleanup_endmntent_ FILE *f = NULL;
         struct mntent *m;
 
@@ -195,3 +199,60 @@ int fstab_find_pri(const char *options, int *ret) {
         *ret = (int) pri;
         return 1;
 }
+
+static char *unquote(const char *s, const char* quotes) {
+        size_t l;
+        assert(s);
+
+        /* This is rather stupid, simply removes the heading and
+         * trailing quotes if there is one. Doesn't care about
+         * escaping or anything.
+         *
+         * DON'T USE THIS FOR NEW CODE ANYMORE!*/
+
+        l = strlen(s);
+        if (l < 2)
+                return strdup(s);
+
+        if (strchr(quotes, s[0]) && s[l-1] == s[0])
+                return strndup(s+1, l-2);
+
+        return strdup(s);
+}
+
+static char *tag_to_udev_node(const char *tagvalue, const char *by) {
+        _cleanup_free_ char *t = NULL, *u = NULL;
+        size_t enc_len;
+
+        u = unquote(tagvalue, QUOTES);
+        if (!u)
+                return NULL;
+
+        enc_len = strlen(u) * 4 + 1;
+        t = new(char, enc_len);
+        if (!t)
+                return NULL;
+
+        if (encode_devnode_name(u, t, enc_len) < 0)
+                return NULL;
+
+        return strjoin("/dev/disk/by-", by, "/", t, NULL);
+}
+
+char *fstab_node_to_udev_node(const char *p) {
+        assert(p);
+
+        if (startswith(p, "LABEL="))
+                return tag_to_udev_node(p+6, "label");
+
+        if (startswith(p, "UUID="))
+                return tag_to_udev_node(p+5, "uuid");
+
+        if (startswith(p, "PARTUUID="))
+                return tag_to_udev_node(p+9, "partuuid");
+
+        if (startswith(p, "PARTLABEL="))
+                return tag_to_udev_node(p+10, "partlabel");
+
+        return strdup(p);
+}
index 872b2363cd500ea36812c5ee6d64886b6910aaff..5ebea4401983ec770e97ce998b847f3778081979 100644 (file)
 
 #include <stdbool.h>
 #include <stddef.h>
+
 #include "macro.h"
 
 bool fstab_is_mount_point(const char *mount);
-int fstab_filter_options(const char *opts, const char *names,
-                         const char **namefound, char **value, char **filtered);
+
+int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
 
 int fstab_extract_values(const char *opts, const char *name, char ***values);
 
@@ -49,3 +50,5 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
 
         return opt == yes_no;
 }
+
+char *fstab_node_to_udev_node(const char *p);
index e58bbea77ccf7ec306fa009a853056c315a13cdd..9998c6441605b827dee50226a8d3648fc7706fb4 100644 (file)
 
 #include <unistd.h>
 
-#include "util.h"
-#include "special.h"
-#include "mkdir.h"
-#include "unit-name.h"
+#include "alloc-util.h"
+#include "dropin.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
 #include "generator.h"
+#include "mkdir.h"
+#include "mount-util.h"
 #include "path-util.h"
-#include "fstab-util.h"
-#include "fileio.h"
-#include "dropin.h"
+#include "special.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "util.h"
 
 static int write_fsck_sysroot_service(const char *dir, const char *what) {
-        const char *unit;
-        _cleanup_free_ char *device = NULL;
-        _cleanup_free_ char *escaped;
+        _cleanup_free_ char *device = NULL, *escaped = NULL;
         _cleanup_fclose_ FILE *f = NULL;
+        const char *unit;
         int r;
 
         escaped = cescape(what);
@@ -60,7 +64,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
                 "Description=File System Check on %2$s\n"
                 "DefaultDependencies=no\n"
                 "BindsTo=%3$s\n"
-                "After=%3$s\n"
+                "After=%3$s local-fs-pre.target\n"
                 "Before=shutdown.target\n"
                 "\n"
                 "[Service]\n"
@@ -101,16 +105,17 @@ int generator_write_fsck_deps(
 
         if (!isempty(fstype) && !streq(fstype, "auto")) {
                 r = fsck_exists(fstype);
-                if (r == -ENOENT) {
+                if (r < 0)
+                        log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
+                else if (r == 0) {
                         /* treat missing check as essentially OK */
-                        log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype);
+                        log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
                         return 0;
-                } else if (r < 0)
-                        return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
+                }
         }
 
         if (path_equal(where, "/")) {
-                char *lnk;
+                const char *lnk;
 
                 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
 
@@ -137,7 +142,7 @@ int generator_write_fsck_deps(
                 }
 
                 fprintf(f,
-                        "RequiresOverridable=%1$s\n"
+                        "Requires=%1$s\n"
                         "After=%1$s\n",
                         fsck);
         }
index 001a8a37e81667746af704a7d38ff2c44300e04a..ddc8c00a2d5644930bd71c919f03fd74ee42a223 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
+#include "btrfs-util.h"
 #include "import-util.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
 
 int import_url_last_component(const char *url, char **ret) {
         const char *e, *p;
@@ -201,3 +206,29 @@ bool dkr_id_is_valid(const char *id) {
 
         return true;
 }
+
+int import_assign_pool_quota_and_warn(const char *path) {
+        int r;
+
+        r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
+        if (r == -ENOTTY)  {
+                log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring.");
+                return 0;
+        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m");
+        if (r > 0)
+                log_info("Set up default quota hierarchy for /var/lib/machines.");
+
+        r = btrfs_subvol_auto_qgroup(path, 0, true);
+        if (r == -ENOTTY) {
+                log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path);
+                return 0;
+        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
+        if (r > 0)
+                log_info("Set up default quota hierarchy for %s.", path);
+
+        return 0;
+}
index 7bf7d4ca406e4e8e523b6e976e3cbf037c713816..9120a5119f47739b42586670b0217a054455c0f4 100644 (file)
@@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id);
 bool dkr_ref_is_valid(const char *ref);
 bool dkr_digest_is_valid(const char *digest);
 #define dkr_tag_is_valid(tag) filename_is_valid(tag)
+
+int import_assign_pool_quota_and_warn(const char *path);
index cbe984d2fba3ec4ea1333ca6b7414f285a432823..74b909d34d742dc397fb9efd89b987ceb7ae573d 100644 (file)
 
 #include <stdlib.h>
 
+#include "alloc-util.h"
+#include "formats-util.h"
+#include "install-printf.h"
 #include "specifier.h"
 #include "unit-name.h"
+#include "user-util.h"
 #include "util.h"
-#include "install-printf.h"
-#include "formats-util.h"
 
 static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
         UnitFileInstallInfo *i = userdata;
@@ -65,42 +67,28 @@ static int specifier_instance(char specifier, void *data, void *userdata, char *
 }
 
 static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
-        UnitFileInstallInfo *i = userdata;
-        const char *username;
-        _cleanup_free_ char *tmp = NULL;
-        char *printed = NULL;
-
-        assert(i);
+        char *t;
 
-        if (i->user)
-                username = i->user;
-        else
-                /* get USER env from env or our own uid */
-                username = tmp = getusername_malloc();
-
-        switch (specifier) {
-        case 'u':
-                printed = strdup(username);
-                break;
-        case 'U': {
-                /* fish username from passwd */
-                uid_t uid;
-                int r;
-
-                r = get_user_creds(&username, &uid, NULL, NULL, NULL);
-                if (r < 0)
-                        return r;
-
-                if (asprintf(&printed, UID_FMT, uid) < 0)
-                        return -ENOMEM;
-                break;
-        }}
+        /* If we are UID 0 (root), this will not result in NSS,
+         * otherwise it might. This is good, as we want to be able to
+         * run this in PID 1, where our user ID is 0, but where NSS
+         * lookups are not allowed. */
 
+        t = getusername_malloc();
+        if (!t)
+                return -ENOMEM;
 
-        *ret = printed;
+        *ret = t;
         return 0;
 }
 
+static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
+
+        if (asprintf(ret, UID_FMT, getuid()) < 0)
+                return -ENOMEM;
+
+        return 0;
+}
 
 int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) {
 
@@ -112,8 +100,8 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret)
          * %p: the prefix                              (foo)
          * %i: the instance                            (bar)
 
-         * %U the UID of the configured user or running user
-         * %u the username of the configured user or running user
+         * %U the UID of the running user
+         * %u the username of running user
          * %m the machine ID of the running system
          * %H the host name of the running system
          * %b the boot ID of the running system
@@ -126,7 +114,7 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret)
                 { 'p', specifier_prefix,              NULL },
                 { 'i', specifier_instance,            NULL },
 
-                { 'U', specifier_user_name,           NULL },
+                { 'U', specifier_user_id,             NULL },
                 { 'u', specifier_user_name,           NULL },
 
                 { 'm', specifier_machine_id,          NULL },
index 238433c808074570c849eb85d11e193d2979f476..9b6464ba9dc0b15d283205f0e93b16d04ab5b62f 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
 #include <fnmatch.h>
+#include <string.h>
+#include <unistd.h>
 
-#include "util.h"
-#include "mkdir.h"
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "conf-parser.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "hashmap.h"
-#include "set.h"
-#include "path-util.h"
+#include "install-printf.h"
+#include "install.h"
+#include "mkdir.h"
 #include "path-lookup.h"
+#include "path-util.h"
+#include "set.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
-#include "install.h"
-#include "conf-parser.h"
-#include "conf-files.h"
-#include "install-printf.h"
-#include "special.h"
+#include "util.h"
+
+#define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
+
+typedef enum SearchFlags {
+        SEARCH_LOAD = 1,
+        SEARCH_FOLLOW_CONFIG_SYMLINKS = 2,
+} SearchFlags;
 
 typedef struct {
-        OrderedHashmap *will_install;
-        OrderedHashmap *have_installed;
+        OrderedHashmap *will_process;
+        OrderedHashmap *have_processed;
 } InstallContext;
 
 static int in_search_path(const char *path, char **search) {
         _cleanup_free_ char *parent = NULL;
-        int r;
+        char **i;
 
         assert(path);
 
-        r = path_get_parent(path, &parent);
-        if (r < 0)
-                return r;
+        parent = dirname_malloc(path);
+        if (!parent)
+                return -ENOMEM;
+
+        STRV_FOREACH(i, search)
+                if (path_equal(parent, *i))
+                        return true;
 
-        return strv_contains(search, parent);
+        return false;
 }
 
 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
@@ -65,6 +84,9 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(ret);
 
+        /* This determines where we shall create or remove our
+         * installation ("configuration") symlinks */
+
         switch (scope) {
 
         case UNIT_FILE_SYSTEM:
@@ -95,9 +117,10 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d
                         r = user_runtime_dir(&p);
                 else
                         r = user_config_home(&p);
-
-                if (r <= 0)
-                        return r < 0 ? r : -ENOENT;
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -ENOENT;
 
                 break;
 
@@ -112,6 +135,185 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d
         return 0;
 }
 
+static bool is_config_path(UnitFileScope scope, const char *path) {
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(path);
+
+        /* Checks whether the specified path is intended for
+         * configuration or is outside of it */
+
+        switch (scope) {
+
+        case UNIT_FILE_SYSTEM:
+        case UNIT_FILE_GLOBAL:
+                return path_startswith(path, "/etc") ||
+                        path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) ||
+                        path_startswith(path, "/run");
+
+
+        case UNIT_FILE_USER: {
+                _cleanup_free_ char *p = NULL;
+
+                r = user_config_home(&p);
+                if (r < 0)
+                        return r;
+                if (r > 0 && path_startswith(path, p))
+                        return true;
+
+                p = mfree(p);
+
+                r = user_runtime_dir(&p);
+                if (r < 0)
+                        return r;
+                if (r > 0 && path_startswith(path, p))
+                        return true;
+
+                return false;
+        }
+
+        default:
+                assert_not_reached("Bad scope");
+        }
+}
+
+
+static int verify_root_dir(UnitFileScope scope, const char **root_dir) {
+        int r;
+
+        assert(root_dir);
+
+        /* 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 */
+
+        if (isempty(*root_dir) || path_equal(*root_dir, "/")) {
+                *root_dir = NULL;
+                return 0;
+        }
+
+        if (scope != UNIT_FILE_SYSTEM)
+                return -EINVAL;
+
+        r = is_dir(*root_dir, true);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -ENOTDIR;
+
+        return 0;
+}
+
+int unit_file_changes_add(
+                UnitFileChange **changes,
+                unsigned *n_changes,
+                UnitFileChangeType type,
+                const char *path,
+                const char *source) {
+
+        UnitFileChange *c;
+        unsigned i;
+
+        assert(path);
+        assert(!changes == !n_changes);
+
+        if (!changes)
+                return 0;
+
+        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);
+
+        if (source) {
+                c[i].source = strdup(source);
+                if (!c[i].source) {
+                        free(c[i].path);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(c[i].path);
+        } else
+                c[i].source = NULL;
+
+        *n_changes = i+1;
+        return 0;
+}
+
+void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
+        unsigned i;
+
+        assert(changes || n_changes == 0);
+
+        if (!changes)
+                return;
+
+        for (i = 0; i < n_changes; i++) {
+                free(changes[i].path);
+                free(changes[i].source);
+        }
+
+        free(changes);
+}
+
+static int create_symlink(
+                const char *old_path,
+                const char *new_path,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_free_ char *dest = NULL;
+        int r;
+
+        assert(old_path);
+        assert(new_path);
+
+        /* Actually create a symlink, and remember that we did. Is
+         * smart enough to check if there's already a valid symlink in
+         * place. */
+
+        mkdir_parents_label(new_path, 0755);
+
+        if (symlink(old_path, new_path) >= 0) {
+                unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+                return 0;
+        }
+
+        if (errno != EEXIST)
+                return -errno;
+
+        r = readlink_malloc(new_path, &dest);
+        if (r < 0)
+                return r;
+
+        if (path_equal(dest, old_path))
+                return 0;
+
+        if (!force)
+                return -EEXIST;
+
+        r = symlink_atomic(old_path, new_path);
+        if (r < 0)
+                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;
+}
+
 static int mark_symlink_for_removal(
                 Set **remove_symlinks_to,
                 const char *p) {
@@ -132,10 +334,12 @@ static int mark_symlink_for_removal(
         path_kill_slashes(n);
 
         r = set_consume(*remove_symlinks_to, n);
+        if (r == -EEXIST)
+                return 0;
         if (r < 0)
-                return r == -EEXIST ? 0 : r;
+                return r;
 
-        return 0;
+        return 1;
 }
 
 static int remove_marked_symlinks_fd(
@@ -143,19 +347,19 @@ static int remove_marked_symlinks_fd(
                 int fd,
                 const char *path,
                 const char *config_path,
-                bool *deleted,
+                bool *restart,
                 UnitFileChange **changes,
-                unsigned *n_changes,
-                char** instance_whitelist) {
+                unsigned *n_changes) {
 
         _cleanup_closedir_ DIR *d = NULL;
+        struct dirent *de;
         int r = 0;
 
         assert(remove_symlinks_to);
         assert(fd >= 0);
         assert(path);
         assert(config_path);
-        assert(deleted);
+        assert(restart);
 
         d = fdopendir(fd);
         if (!d) {
@@ -165,27 +369,13 @@ static int remove_marked_symlinks_fd(
 
         rewinddir(d);
 
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0) {
-                        r = -errno;
-                        break;
-                }
-
-                if (!de)
-                        break;
-
-                if (hidden_file(de->d_name))
-                        continue;
+        FOREACH_DIRENT(de, d, return -errno) {
 
                 dirent_ensure_type(d, de);
 
                 if (de->d_type == DT_DIR) {
-                        int nfd, q;
                         _cleanup_free_ char *p = NULL;
+                        int nfd, q;
 
                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
                         if (nfd < 0) {
@@ -204,42 +394,23 @@ 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, deleted, changes, n_changes, instance_whitelist);
+                        q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, 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;
-                        int q;
                         bool found;
+                        int q;
 
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
-                        if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) &&
-                            instance_whitelist &&
-                            !strv_contains(instance_whitelist, de->d_name)) {
-
-                                _cleanup_free_ char *w = NULL;
-
-                                /* OK, the file is not listed directly
-                                 * in the whitelist, so let's check if
-                                 * the template of it might be
-                                 * listed. */
-
-                                r = unit_name_template(de->d_name, &w);
-                                if (r < 0)
-                                        return r;
-
-                                if (!strv_contains(instance_whitelist, w))
-                                        continue;
-                        }
-
                         p = path_make_absolute(de->d_name, path);
                         if (!p)
                                 return -ENOMEM;
 
-                        q = readlink_and_canonicalize(p, &dest);
+                        q = readlink_malloc(p, &dest);
                         if (q < 0) {
                                 if (q == -ENOENT)
                                         continue;
@@ -249,9 +420,15 @@ static int remove_marked_symlinks_fd(
                                 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. */
+
                         found =
-                                set_get(remove_symlinks_to, dest) ||
-                                set_get(remove_symlinks_to, basename(dest));
+                                set_contains(remove_symlinks_to, dest) ||
+                                set_contains(remove_symlinks_to, basename(dest)) ||
+                                set_contains(remove_symlinks_to, de->d_name);
 
                         if (!found)
                                 continue;
@@ -263,18 +440,15 @@ static int remove_marked_symlinks_fd(
                         }
 
                         path_kill_slashes(p);
-                        rmdir_parents(p, config_path);
-                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
+                        (void) rmdir_parents(p, config_path);
 
-                        if (!set_get(remove_symlinks_to, p)) {
+                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
 
-                                q = mark_symlink_for_removal(&remove_symlinks_to, p);
-                                if (q < 0) {
-                                        if (r == 0)
-                                                r = q;
-                                } else
-                                        *deleted = true;
-                        }
+                        q = mark_symlink_for_removal(&remove_symlinks_to, p);
+                        if (q < 0)
+                                return q;
+                        if (q > 0)
+                                *restart = true;
                 }
         }
 
@@ -285,12 +459,11 @@ static int remove_marked_symlinks(
                 Set *remove_symlinks_to,
                 const char *config_path,
                 UnitFileChange **changes,
-                unsigned *n_changes,
-                char** instance_whitelist) {
+                unsigned *n_changes) {
 
         _cleanup_close_ int fd = -1;
+        bool restart;
         int r = 0;
-        bool deleted;
 
         assert(config_path);
 
@@ -303,32 +476,32 @@ static int remove_marked_symlinks(
 
         do {
                 int q, cfd;
-                deleted = false;
+                restart = false;
 
                 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-                if (cfd < 0) {
-                        r = -errno;
-                        break;
-                }
+                if (cfd < 0)
+                        return -errno;
 
                 /* This takes possession of cfd and closes it */
-                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist);
+                q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes);
                 if (r == 0)
                         r = q;
-        } while (deleted);
+        } while (restart);
 
         return r;
 }
 
 static int find_symlinks_fd(
+                const char *root_dir,
                 const char *name,
                 int fd,
                 const char *path,
                 const char *config_path,
                 bool *same_name_link) {
 
-        int r = 0;
         _cleanup_closedir_ DIR *d = NULL;
+        struct dirent *de;
+        int r = 0;
 
         assert(name);
         assert(fd >= 0);
@@ -342,25 +515,13 @@ static int find_symlinks_fd(
                 return -errno;
         }
 
-        for (;;) {
-                struct dirent *de;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return -errno;
-
-                if (!de)
-                        return r;
-
-                if (hidden_file(de->d_name))
-                        continue;
+        FOREACH_DIRENT(de, d, return -errno) {
 
                 dirent_ensure_type(d, de);
 
                 if (de->d_type == DT_DIR) {
-                        int nfd, q;
                         _cleanup_free_ char *p = NULL;
+                        int nfd, q;
 
                         nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
                         if (nfd < 0) {
@@ -379,7 +540,7 @@ static int find_symlinks_fd(
                         }
 
                         /* This will close nfd, regardless whether it succeeds or not */
-                        q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
+                        q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
                         if (q > 0)
                                 return 1;
                         if (r == 0)
@@ -396,16 +557,27 @@ static int find_symlinks_fd(
                                 return -ENOMEM;
 
                         /* Acquire symlink destination */
-                        q = readlink_and_canonicalize(p, &dest);
+                        q = readlink_malloc(p, &dest);
+                        if (q == -ENOENT)
+                                continue;
                         if (q < 0) {
-                                if (q == -ENOENT)
-                                        continue;
-
                                 if (r == 0)
                                         r = q;
                                 continue;
                         }
 
+                        /* Make absolute */
+                        if (!path_is_absolute(dest)) {
+                                char *x;
+
+                                x = prefix_root(root_dir, dest);
+                                if (!x)
+                                        return -ENOMEM;
+
+                                free(dest);
+                                dest = x;
+                        }
+
                         /* Check if the symlink itself matches what we
                          * are looking for */
                         if (path_is_absolute(name))
@@ -438,9 +610,12 @@ static int find_symlinks_fd(
                                 return 1;
                 }
         }
+
+        return r;
 }
 
 static int find_symlinks(
+                const char *root_dir,
                 const char *name,
                 const char *config_path,
                 bool *same_name_link) {
@@ -459,7 +634,7 @@ static int find_symlinks(
         }
 
         /* This takes possession of fd and closes it */
-        return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
+        return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
 }
 
 static int find_symlinks_in_scope(
@@ -468,350 +643,59 @@ static int find_symlinks_in_scope(
                 const char *name,
                 UnitFileState *state) {
 
-        int r;
         _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(name);
 
-        /* First look in runtime config path */
-        r = get_config_path(scope, true, root_dir, &normal_path);
+        /* 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(name, normal_path, &same_name_link_runtime);
+        r = find_symlinks(root_dir, name, normal_path, &same_name_link);
         if (r < 0)
                 return r;
-        else if (r > 0) {
-                *state = UNIT_FILE_ENABLED_RUNTIME;
+        if (r > 0) {
+                *state = UNIT_FILE_ENABLED;
                 return r;
         }
 
-        /* Then look in the normal config path */
-        r = get_config_path(scope, false, root_dir, &runtime_path);
+        /* Then look in runtime config path */
+        r = get_config_path(scope, true, root_dir, &runtime_path);
         if (r < 0)
                 return r;
 
-        r = find_symlinks(name, runtime_path, &same_name_link);
+        r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime);
         if (r < 0)
                 return r;
-        else if (r > 0) {
-                *state = UNIT_FILE_ENABLED;
+        if (r > 0) {
+                *state = UNIT_FILE_ENABLED_RUNTIME;
                 return r;
         }
 
         /* Hmm, we didn't find it, but maybe we found the same name
          * link? */
-        if (same_name_link_runtime) {
-                *state = UNIT_FILE_LINKED_RUNTIME;
-                return 1;
-        } else if (same_name_link) {
+        if (same_name_link) {
                 *state = UNIT_FILE_LINKED;
                 return 1;
         }
-
-        return 0;
-}
-
-int unit_file_mask(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char **files,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **i;
-        _cleanup_free_ char *prefix = NULL;
-        int r;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        r = get_config_path(scope, runtime, root_dir, &prefix);
-        if (r < 0)
-                return r;
-
-        STRV_FOREACH(i, files) {
-                _cleanup_free_ char *path = NULL;
-
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                path = path_make_absolute(*i, prefix);
-                if (!path) {
-                        r = -ENOMEM;
-                        break;
-                }
-
-                if (symlink("/dev/null", path) >= 0) {
-                        unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
-                        continue;
-                }
-
-                if (errno == EEXIST) {
-
-                        if (null_or_empty_path(path) > 0)
-                                continue;
-
-                        if (force) {
-                                if (symlink_atomic("/dev/null", path) >= 0) {
-                                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-                                        unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
-                                        continue;
-                                }
-                        }
-
-                        if (r == 0)
-                                r = -EEXIST;
-                } else {
-                        if (r == 0)
-                                r = -errno;
-                }
-        }
-
-        return r;
-}
-
-int unit_file_unmask(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char **files,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        char **i, *config_path = NULL;
-        int r, q;
-        Set *remove_symlinks_to = NULL;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        r = get_config_path(scope, runtime, root_dir, &config_path);
-        if (r < 0)
-                goto finish;
-
-        STRV_FOREACH(i, files) {
-                _cleanup_free_ char *path = NULL;
-
-                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                path = path_make_absolute(*i, config_path);
-                if (!path) {
-                        r = -ENOMEM;
-                        break;
-                }
-
-                q = null_or_empty_path(path);
-                if (q > 0) {
-                        if (unlink(path) < 0)
-                                q = -errno;
-                        else {
-                                q = mark_symlink_for_removal(&remove_symlinks_to, path);
-                                unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-                        }
-                }
-
-                if (q != -ENOENT && r == 0)
-                        r = q;
-        }
-
-
-finish:
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
-        if (r == 0)
-                r = q;
-
-        set_free_free(remove_symlinks_to);
-        free(config_path);
-
-        return r;
-}
-
-int unit_file_link(
-                UnitFileScope scope,
-                bool runtime,
-                const char *root_dir,
-                char **files,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
-
-        _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        char **i;
-        _cleanup_free_ char *config_path = NULL;
-        int r, q;
-
-        assert(scope >= 0);
-        assert(scope < _UNIT_FILE_SCOPE_MAX);
-
-        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;
-
-        STRV_FOREACH(i, files) {
-                _cleanup_free_ char *path = NULL;
-                char *fn;
-                struct stat st;
-
-                fn = basename(*i);
-
-                if (!path_is_absolute(*i) ||
-                    !unit_name_is_valid(fn, UNIT_NAME_ANY)) {
-                        if (r == 0)
-                                r = -EINVAL;
-                        continue;
-                }
-
-                if (lstat(*i, &st) < 0) {
-                        if (r == 0)
-                                r = -errno;
-                        continue;
-                }
-
-                if (!S_ISREG(st.st_mode)) {
-                        r = -ENOENT;
-                        continue;
-                }
-
-                q = in_search_path(*i, paths.unit_path);
-                if (q < 0)
-                        return q;
-
-                if (q > 0)
-                        continue;
-
-                path = path_make_absolute(fn, config_path);
-                if (!path)
-                        return -ENOMEM;
-
-                if (symlink(*i, path) >= 0) {
-                        unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-                        continue;
-                }
-
-                if (errno == EEXIST) {
-                        _cleanup_free_ char *dest = NULL;
-
-                        q = readlink_and_make_absolute(path, &dest);
-                        if (q < 0 && errno != ENOENT) {
-                                if (r == 0)
-                                        r = q;
-                                continue;
-                        }
-
-                        if (q >= 0 && path_equal(dest, *i))
-                                continue;
-
-                        if (force) {
-                                if (symlink_atomic(*i, path) >= 0) {
-                                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-                                        unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
-                                        continue;
-                                }
-                        }
-
-                        if (r == 0)
-                                r = -EEXIST;
-                } else {
-                        if (r == 0)
-                                r = -errno;
-                }
-        }
-
-        return r;
-}
-
-void unit_file_list_free(Hashmap *h) {
-        UnitFileList *i;
-
-        while ((i = hashmap_steal_first(h))) {
-                free(i->path);
-                free(i);
+        if (same_name_link_runtime) {
+                *state = UNIT_FILE_LINKED_RUNTIME;
+                return 1;
         }
 
-        hashmap_free(h);
-}
-
-int unit_file_changes_add(
-                UnitFileChange **changes,
-                unsigned *n_changes,
-                UnitFileChangeType type,
-                const char *path,
-                const char *source) {
-
-        UnitFileChange *c;
-        unsigned i;
-
-        assert(path);
-        assert(!changes == !n_changes);
-
-        if (!changes)
-                return 0;
-
-        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);
-
-        if (source) {
-                c[i].source = strdup(source);
-                if (!c[i].source) {
-                        free(c[i].path);
-                        return -ENOMEM;
-                }
-
-                path_kill_slashes(c[i].path);
-        } else
-                c[i].source = NULL;
-
-        *n_changes = i+1;
         return 0;
 }
 
-void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
-        unsigned i;
-
-        assert(changes || n_changes == 0);
+static void install_info_free(UnitFileInstallInfo *i) {
 
-        if (!changes)
+        if (!i)
                 return;
 
-        for (i = 0; i < n_changes; i++) {
-                free(changes[i].path);
-                free(changes[i].source);
-        }
-
-        free(changes);
-}
-
-static void install_info_free(UnitFileInstallInfo *i) {
-        assert(i);
-
         free(i->name);
         free(i->path);
         strv_free(i->aliases);
@@ -819,34 +703,45 @@ static void install_info_free(UnitFileInstallInfo *i) {
         strv_free(i->required_by);
         strv_free(i->also);
         free(i->default_instance);
+        free(i->symlink_target);
         free(i);
 }
 
-static void install_info_hashmap_free(OrderedHashmap *m) {
+static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) {
         UnitFileInstallInfo *i;
 
         if (!m)
-                return;
+                return NULL;
 
         while ((i = ordered_hashmap_steal_first(m)))
                 install_info_free(i);
 
-        ordered_hashmap_free(m);
+        return ordered_hashmap_free(m);
 }
 
 static void install_context_done(InstallContext *c) {
         assert(c);
 
-        install_info_hashmap_free(c->will_install);
-        install_info_hashmap_free(c->have_installed);
+        c->will_process = install_info_hashmap_free(c->will_process);
+        c->have_processed = install_info_hashmap_free(c->have_processed);
+}
+
+static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
+        UnitFileInstallInfo *i;
 
-        c->will_install = c->have_installed = NULL;
+        i = ordered_hashmap_get(c->have_processed, name);
+        if (i)
+                return i;
+
+        return ordered_hashmap_get(c->will_process, name);
 }
 
 static int install_info_add(
                 InstallContext *c,
                 const char *name,
-                const char *path) {
+                const char *path,
+                UnitFileInstallInfo **ret) {
+
         UnitFileInstallInfo *i = NULL;
         int r;
 
@@ -859,17 +754,21 @@ static int install_info_add(
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
-        if (ordered_hashmap_get(c->have_installed, name) ||
-            ordered_hashmap_get(c->will_install, name))
+        i = install_info_find(c, name);
+        if (i) {
+                if (ret)
+                        *ret = i;
                 return 0;
+        }
 
-        r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops);
+        r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
         if (r < 0)
                 return r;
 
         i = new0(UnitFileInstallInfo, 1);
         if (!i)
                 return -ENOMEM;
+        i->type = _UNIT_FILE_TYPE_INVALID;
 
         i->name = strdup(name);
         if (!i->name) {
@@ -885,30 +784,32 @@ static int install_info_add(
                 }
         }
 
-        r = ordered_hashmap_put(c->will_install, i->name, i);
+        r = ordered_hashmap_put(c->will_process, i->name, i);
         if (r < 0)
                 goto fail;
 
+        if (ret)
+                *ret = i;
+
         return 0;
 
 fail:
-        if (i)
-                install_info_free(i);
-
+        install_info_free(i);
         return r;
 }
 
 static int install_info_add_auto(
                 InstallContext *c,
-                const char *name_or_path) {
+                const char *name_or_path,
+                UnitFileInstallInfo **ret) {
 
         assert(c);
         assert(name_or_path);
 
         if (path_is_absolute(name_or_path))
-                return install_info_add(c, NULL, name_or_path);
+                return install_info_add(c, NULL, name_or_path, ret);
         else
-                return install_info_add(c, name_or_path, NULL);
+                return install_info_add(c, name_or_path, NULL, ret);
 }
 
 static int config_parse_also(
@@ -923,63 +824,33 @@ static int config_parse_also(
                 void *data,
                 void *userdata) {
 
-        size_t l;
-        const char *word, *state;
-        InstallContext *c = data;
         UnitFileInstallInfo *i = userdata;
+        InstallContext *c = data;
+        int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
 
-        FOREACH_WORD_QUOTED(word, l, rvalue, state) {
-                _cleanup_free_ char *n;
-                int r;
-
-                n = strndup(word, l);
-                if (!n)
-                        return -ENOMEM;
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
 
-                r = install_info_add(c, n, NULL);
+                r = extract_first_word(&rvalue, &word, NULL, 0);
                 if (r < 0)
                         return r;
+                if (r == 0)
+                        break;
 
-                r = strv_extend(&i->also, n);
+                r = install_info_add(c, word, NULL, NULL);
                 if (r < 0)
                         return r;
-        }
-        if (!isempty(state))
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
 
-        return 0;
-}
-
-static int config_parse_user(
-                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) {
-
-        UnitFileInstallInfo *i = data;
-        char *printed;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-
-        r = install_full_printf(i, rvalue, &printed);
-        if (r < 0)
-                return r;
+                r = strv_push(&i->also, word);
+                if (r < 0)
+                        return r;
 
-        free(i->user);
-        i->user = printed;
+                word = NULL;
+        }
 
         return 0;
 }
@@ -1024,9 +895,7 @@ static int unit_file_load(
                 UnitFileInstallInfo *info,
                 const char *path,
                 const char *root_dir,
-                bool allow_symlink,
-                bool load,
-                bool *also) {
+                SearchFlags flags) {
 
         const ConfigTableItem items[] = {
                 { "Install", "Alias",           config_parse_strv,             0, &info->aliases           },
@@ -1034,34 +903,57 @@ static int unit_file_load(
                 { "Install", "RequiredBy",      config_parse_strv,             0, &info->required_by       },
                 { "Install", "DefaultInstance", config_parse_default_instance, 0, info                     },
                 { "Install", "Also",            config_parse_also,             0, c                        },
-                { "Exec",    "User",            config_parse_user,             0, info                     },
                 {}
         };
 
         _cleanup_fclose_ FILE *f = NULL;
-        int fd, r;
+        _cleanup_close_ int fd = -1;
+        struct stat st;
+        int r;
 
         assert(c);
         assert(info);
         assert(path);
 
-        if (!isempty(root_dir))
-                path = strjoina(root_dir, "/", path);
+        path = prefix_roota(root_dir, path);
 
-        if (!load) {
-                r = access(path, F_OK) ? -errno : 0;
-                return r;
+        if (!(flags & SEARCH_LOAD)) {
+                r = lstat(path, &st);
+                if (r < 0)
+                        return -errno;
+
+                if (null_or_empty(&st))
+                        info->type = UNIT_FILE_TYPE_MASKED;
+                else if (S_ISREG(st.st_mode))
+                        info->type = UNIT_FILE_TYPE_REGULAR;
+                else if (S_ISLNK(st.st_mode))
+                        return -ELOOP;
+                else if (S_ISDIR(st.st_mode))
+                        return -EISDIR;
+                else
+                        return -ENOTTY;
+
+                return 0;
         }
 
-        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
+        fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
         if (fd < 0)
                 return -errno;
+        if (fstat(fd, &st) < 0)
+                return -errno;
+        if (null_or_empty(&st)) {
+                info->type = UNIT_FILE_MASKED;
+                return 0;
+        }
+        if (S_ISDIR(st.st_mode))
+                return -EISDIR;
+        if (!S_ISREG(st.st_mode))
+                return -ENOTTY;
 
         f = fdopen(fd, "re");
-        if (!f) {
-                safe_close(fd);
-                return -ENOMEM;
-        }
+        if (!f)
+                return -errno;
+        fd = -1;
 
         r = config_parse(NULL, path, f,
                          NULL,
@@ -1070,8 +962,7 @@ static int unit_file_load(
         if (r < 0)
                 return r;
 
-        if (also)
-                *also = !strv_isempty(info->also);
+        info->type = UNIT_FILE_TYPE_REGULAR;
 
         return
                 (int) strv_length(info->aliases) +
@@ -1079,14 +970,73 @@ static int unit_file_load(
                 (int) strv_length(info->required_by);
 }
 
+static int unit_file_load_or_readlink(
+                InstallContext *c,
+                UnitFileInstallInfo *info,
+                const char *path,
+                const char *root_dir,
+                SearchFlags flags) {
+
+        _cleanup_free_ char *np = NULL;
+        int r;
+
+        r = unit_file_load(c, info, path, root_dir, flags);
+        if (r != -ELOOP)
+                return r;
+
+        /* This is a symlink, let's read it. */
+
+        r = readlink_and_make_absolute_root(root_dir, path, &np);
+        if (r < 0)
+                return r;
+
+        if (path_equal(np, "/dev/null"))
+                info->type = UNIT_FILE_TYPE_MASKED;
+        else {
+                const char *bn;
+                UnitType a, b;
+
+                bn = basename(np);
+
+                if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
+
+                        if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
+                                return -EINVAL;
+
+                } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
+
+                        if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
+                                return -EINVAL;
+
+                } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
+
+                        if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
+                                return -EINVAL;
+                } else
+                        return -EINVAL;
+
+                /* Enforce that the symlink destination does not
+                 * change the unit file type. */
+
+                a = unit_name_to_type(info->name);
+                b = unit_name_to_type(bn);
+                if (a < 0 || b < 0 || a != b)
+                        return -EINVAL;
+
+                info->type = UNIT_FILE_TYPE_SYMLINK;
+                info->symlink_target = np;
+                np = NULL;
+        }
+
+        return 0;
+}
+
 static int unit_file_search(
                 InstallContext *c,
                 UnitFileInstallInfo *info,
                 const LookupPaths *paths,
                 const char *root_dir,
-                bool allow_symlink,
-                bool load,
-                bool *also) {
+                SearchFlags flags) {
 
         char **p;
         int r;
@@ -1095,8 +1045,12 @@ static int unit_file_search(
         assert(info);
         assert(paths);
 
+        /* Was this unit already loaded? */
+        if (info->type != _UNIT_FILE_TYPE_INVALID)
+                return 0;
+
         if (info->path)
-                return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also);
+                return unit_file_load_or_readlink(c, info, info->path, root_dir, flags);
 
         assert(info->name);
 
@@ -1107,14 +1061,15 @@ static int unit_file_search(
                 if (!path)
                         return -ENOMEM;
 
-                r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
-                if (r >= 0) {
+                r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                return r;
+                } else {
                         info->path = path;
                         path = NULL;
                         return r;
                 }
-                if (r != -ENOENT && r != -ELOOP)
-                        return r;
         }
 
         if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
@@ -1136,92 +1091,149 @@ static int unit_file_search(
                         if (!path)
                                 return -ENOMEM;
 
-                        r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
-                        if (r >= 0) {
+                        r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
+                        if (r < 0) {
+                                if (r != -ENOENT)
+                                        return r;
+                        } else {
                                 info->path = path;
                                 path = NULL;
                                 return r;
                         }
-                        if (r != -ENOENT && r != -ELOOP)
-                                return r;
                 }
         }
 
         return -ENOENT;
 }
 
-static int unit_file_can_install(
-                const LookupPaths *paths,
+static int install_info_follow(
+                InstallContext *c,
+                UnitFileInstallInfo *i,
                 const char *root_dir,
-                const char *name,
-                bool allow_symlink,
-                bool *also) {
+                SearchFlags flags) {
+
+        assert(c);
+        assert(i);
+
+        if (i->type != UNIT_FILE_TYPE_SYMLINK)
+                return -EINVAL;
+        if (!i->symlink_target)
+                return -EINVAL;
+
+        /* If the basename doesn't match, the caller should add a
+         * complete new entry for this. */
+
+        if (!streq(basename(i->symlink_target), i->name))
+                return -EXDEV;
+
+        free(i->path);
+        i->path = i->symlink_target;
+        i->symlink_target = NULL;
+        i->type = _UNIT_FILE_TYPE_INVALID;
+
+        return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
+}
+
+static int install_info_traverse(
+                UnitFileScope scope,
+                InstallContext *c,
+                const char *root_dir,
+                const LookupPaths *paths,
+                UnitFileInstallInfo *start,
+                SearchFlags flags,
+                UnitFileInstallInfo **ret) {
 
-        _cleanup_(install_context_done) InstallContext c = {};
         UnitFileInstallInfo *i;
+        unsigned k = 0;
         int r;
 
         assert(paths);
-        assert(name);
+        assert(start);
+        assert(c);
 
-        r = install_info_add_auto(&c, name);
+        r = unit_file_search(c, start, paths, root_dir, flags);
         if (r < 0)
                 return r;
 
-        assert_se(i = ordered_hashmap_first(c.will_install));
+        i = start;
+        while (i->type == UNIT_FILE_TYPE_SYMLINK) {
+                /* Follow the symlink */
 
-        r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also);
+                if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
+                        return -ELOOP;
 
-        if (r >= 0)
-                r =
-                        (int) strv_length(i->aliases) +
-                        (int) strv_length(i->wanted_by) +
-                        (int) strv_length(i->required_by);
+                if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path))
+                        return -ELOOP;
 
-        return r;
-}
+                r = install_info_follow(c, i, root_dir, flags);
+                if (r < 0) {
+                        _cleanup_free_ char *buffer = NULL;
+                        const char *bn;
 
-static int create_symlink(
-                const char *old_path,
-                const char *new_path,
-                bool force,
-                UnitFileChange **changes,
-                unsigned *n_changes) {
+                        if (r != -EXDEV)
+                                return r;
 
-        _cleanup_free_ char *dest = NULL;
-        int r;
+                        /* Target has a different name, create a new
+                         * install info object for that, and continue
+                         * with that. */
 
-        assert(old_path);
-        assert(new_path);
+                        bn = basename(i->symlink_target);
 
-        mkdir_parents_label(new_path, 0755);
+                        if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
+                            unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
 
-        if (symlink(old_path, new_path) >= 0) {
-                unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
-                return 0;
+                                _cleanup_free_ char *instance = NULL;
+
+                                r = unit_name_to_instance(i->name, &instance);
+                                if (r < 0)
+                                        return r;
+
+                                r = unit_name_replace_instance(bn, instance, &buffer);
+                                if (r < 0)
+                                        return r;
+
+                                bn = buffer;
+                        }
+
+                        r = install_info_add(c, bn, NULL, &i);
+                        if (r < 0)
+                                return r;
+
+                        r = unit_file_search(c, i, paths, root_dir, flags);
+                        if (r < 0)
+                                return r;
+                }
+
+                /* Try again, with the new target we found. */
         }
 
-        if (errno != EEXIST)
-                return -errno;
+        if (ret)
+                *ret = i;
 
-        r = readlink_and_make_absolute(new_path, &dest);
-        if (r < 0)
-                return r;
+        return 0;
+}
 
-        if (path_equal(dest, old_path))
-                return 0;
+static int install_info_discover(
+                UnitFileScope scope,
+                InstallContext *c,
+                const char *root_dir,
+                const LookupPaths *paths,
+                const char *name,
+                SearchFlags flags,
+                UnitFileInstallInfo **ret) {
+
+        UnitFileInstallInfo *i;
+        int r;
 
-        if (!force)
-                return -EEXIST;
+        assert(c);
+        assert(paths);
+        assert(name);
 
-        r = symlink_atomic(old_path, new_path);
+        r = install_info_add_auto(c, name, &i);
         if (r < 0)
                 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 install_info_traverse(scope, c, root_dir, paths, i, flags, ret);
 }
 
 static int install_info_symlink_alias(
@@ -1356,6 +1368,9 @@ static int install_info_apply(
         assert(paths);
         assert(config_path);
 
+        if (i->type != UNIT_FILE_TYPE_REGULAR)
+                return 0;
+
         r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
 
         q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
@@ -1374,53 +1389,59 @@ static int install_info_apply(
 }
 
 static int install_context_apply(
+                UnitFileScope scope,
                 InstallContext *c,
                 const LookupPaths *paths,
                 const char *config_path,
                 const char *root_dir,
                 bool force,
+                SearchFlags flags,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
         UnitFileInstallInfo *i;
-        int r, q;
+        int r;
 
         assert(c);
         assert(paths);
         assert(config_path);
 
-        if (!ordered_hashmap_isempty(c->will_install)) {
-                r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
-                if (r < 0)
-                        return r;
+        if (ordered_hashmap_isempty(c->will_process))
+                return 0;
 
-                r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
-                if (r < 0)
-                        return r;
-        }
+        r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
+        if (r < 0)
+                return r;
 
         r = 0;
-        while ((i = ordered_hashmap_first(c->will_install))) {
-                assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
+        while ((i = ordered_hashmap_first(c->will_process))) {
+                int q;
 
-                q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
-                if (q < 0) {
-                        if (r >= 0)
-                                r = q;
+                q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
+                if (q < 0)
+                        return q;
 
+                r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL);
+                if (r < 0)
                         return r;
-                } else if (r >= 0)
-                        r += q;
+
+                if (i->type != UNIT_FILE_TYPE_REGULAR)
+                        continue;
 
                 q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
-                if (r >= 0 && q < 0)
-                        r = q;
+                if (r >= 0) {
+                        if (q < 0)
+                                r = q;
+                        else
+                                r+= q;
+                }
         }
 
         return r;
 }
 
 static int install_context_mark_for_removal(
+                UnitFileScope scope,
                 InstallContext *c,
                 const LookupPaths *paths,
                 Set **remove_symlinks_to,
@@ -1428,7 +1449,7 @@ static int install_context_mark_for_removal(
                 const char *root_dir) {
 
         UnitFileInstallInfo *i;
-        int r, q;
+        int r;
 
         assert(c);
         assert(paths);
@@ -1436,87 +1457,182 @@ static int install_context_mark_for_removal(
 
         /* Marks all items for removal */
 
-        if (!ordered_hashmap_isempty(c->will_install)) {
-                r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops);
+        if (ordered_hashmap_isempty(c->will_process))
+                return 0;
+
+        r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
+        if (r < 0)
+                return r;
+
+        while ((i = ordered_hashmap_first(c->will_process))) {
+
+                r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
                 if (r < 0)
                         return r;
 
-                r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install));
+                r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
                 if (r < 0)
                         return r;
-        }
 
-        r = 0;
-        while ((i = ordered_hashmap_first(c->will_install))) {
-                assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
-
-                q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
-                if (q == -ENOENT) {
-                        /* do nothing */
-                } else if (q < 0) {
-                        if (r >= 0)
-                                r = q;
+                if (i->type != UNIT_FILE_TYPE_REGULAR)
+                        continue;
 
+                r = mark_symlink_for_removal(remove_symlinks_to, i->name);
+                if (r < 0)
                         return r;
-                } else if (r >= 0)
-                        r += q;
-
-                if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
-                        char *unit_file;
-
-                        if (i->path) {
-                                unit_file = basename(i->path);
-
-                                if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE))
-                                        /* unit file named as instance exists, thus all symlinks
-                                         * pointing to it will be removed */
-                                        q = mark_symlink_for_removal(remove_symlinks_to, i->name);
-                                else
-                                        /* does not exist, thus we will mark for removal symlinks
-                                         * to template unit file */
-                                        q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
-                        } else {
-                                /* If i->path is not set, it means that we didn't actually find
-                                 * the unit file. But we can still remove symlinks to the
-                                 * nonexistent template. */
-                                r = unit_name_template(i->name, &unit_file);
-                                if (r < 0)
-                                        return r;
+        }
 
-                                q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
-                                free(unit_file);
-                        }
-                } else
-                        q = mark_symlink_for_removal(remove_symlinks_to, i->name);
+        return 0;
+}
+
+int unit_file_mask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _cleanup_free_ char *prefix = NULL;
+        char **i;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &prefix);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, files) {
+                _cleanup_free_ char *path = NULL;
+                int q;
+
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
+                        if (r == 0)
+                                r = -EINVAL;
+                        continue;
+                }
 
-                if (r >= 0 && q < 0)
+                path = path_make_absolute(*i, prefix);
+                if (!path)
+                        return -ENOMEM;
+
+                q = create_symlink("/dev/null", path, force, changes, n_changes);
+                if (q < 0 && r >= 0)
                         r = q;
         }
 
         return r;
 }
 
-int unit_file_add_dependency(
+int unit_file_unmask(
+                UnitFileScope scope,
+                bool runtime,
+                const char *root_dir,
+                char **files,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        _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;
+        char **i;
+        int r, q;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
+
+        r = get_config_path(scope, runtime, root_dir, &config_path);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, files) {
+                _cleanup_free_ char *path = NULL;
+
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+                        return -EINVAL;
+
+                path = path_make_absolute(*i, config_path);
+                if (!path)
+                        return -ENOMEM;
+
+                r = null_or_empty_path(path);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        continue;
+
+                if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                        return -ENOMEM;
+
+                todo[n_todo++] = *i;
+        }
+
+        strv_uniq(todo);
+
+        r = 0;
+        STRV_FOREACH(i, todo) {
+                _cleanup_free_ char *path = NULL;
+
+                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;
+
+                        unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+                }
+        }
+
+        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        if (r >= 0)
+                r = q;
+
+        return r;
+}
+
+int unit_file_link(
                 UnitFileScope scope,
                 bool runtime,
                 const char *root_dir,
                 char **files,
-                char *target,
-                UnitDependency dep,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        _cleanup_(install_context_done) InstallContext c = {};
         _cleanup_free_ char *config_path = NULL;
+        _cleanup_free_ char **todo = NULL;
+        size_t n_todo = 0, n_allocated = 0;
         char **i;
-        int r;
-        UnitFileInstallInfo *info;
+        int r, q;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
+
         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
                 return r;
@@ -1526,55 +1642,135 @@ int unit_file_add_dependency(
                 return r;
 
         STRV_FOREACH(i, files) {
-                UnitFileState state;
+                _cleanup_free_ char *full = NULL;
+                struct stat st;
+                char *fn;
+
+                if (!path_is_absolute(*i))
+                        return -EINVAL;
 
-                state = unit_file_get_state(scope, root_dir, *i);
-                if (state < 0)
-                        return log_error_errno(state, "Failed to get unit file state for %s: %m", *i);
+                fn = basename(*i);
+                if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
+                        return -EINVAL;
 
-                if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
-                        log_error("Failed to enable unit: Unit %s is masked", *i);
-                        return -EOPNOTSUPP;
-                }
+                full = prefix_root(root_dir, *i);
+                if (!full)
+                        return -ENOMEM;
 
-                r = install_info_add_auto(&c, *i);
-                if (r < 0)
-                        return r;
+                if (lstat(full, &st) < 0)
+                        return -errno;
+                if (S_ISLNK(st.st_mode))
+                        return -ELOOP;
+                if (S_ISDIR(st.st_mode))
+                        return -EISDIR;
+                if (!S_ISREG(st.st_mode))
+                        return -ENOTTY;
+
+                q = in_search_path(*i, paths.unit_path);
+                if (q < 0)
+                        return q;
+                if (q > 0)
+                        continue;
+
+                if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+                        return -ENOMEM;
+
+                todo[n_todo++] = *i;
         }
 
-        if (!ordered_hashmap_isempty(c.will_install)) {
-                r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops);
-                if (r < 0)
-                        return r;
+        strv_uniq(todo);
 
-                r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install));
-                if (r < 0)
-                        return r;
+        r = 0;
+        STRV_FOREACH(i, todo) {
+                _cleanup_free_ char *path = NULL;
+
+                path = path_make_absolute(basename(*i), config_path);
+                if (!path)
+                        return -ENOMEM;
+
+                q = create_symlink(*i, path, force, changes, n_changes);
+                if (q < 0 && r >= 0)
+                        r = q;
         }
 
-        while ((info = ordered_hashmap_first(c.will_install))) {
-                assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0);
+        return r;
+}
+
+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) {
+
+        _cleanup_lookup_paths_free_ LookupPaths paths = {};
+        _cleanup_(install_context_done) InstallContext c = {};
+        _cleanup_free_ char *config_path = NULL;
+        UnitFileInstallInfo *i, *target_info;
+        char **f;
+        int r;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+        assert(target);
+
+        if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
+                return -EINVAL;
+
+        if (!unit_name_is_valid(target, UNIT_NAME_ANY))
+                return -EINVAL;
+
+        r = verify_root_dir(scope, &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;
+
+        r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
+        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 = unit_file_search(&c, info, &paths, root_dir, false, false, NULL);
+                r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
                 if (r < 0)
                         return r;
+                if (i->type == UNIT_FILE_TYPE_MASKED)
+                        return -ESHUTDOWN;
+
+                assert(i->type == UNIT_FILE_TYPE_REGULAR);
+
+                /* We didn't actually load anything from the unit
+                 * file, but instead just add in our new symlink to
+                 * create. */
 
                 if (dep == UNIT_WANTS)
-                        r = strv_extend(&info->wanted_by, target);
-                else if (dep == UNIT_REQUIRES)
-                        r = strv_extend(&info->required_by, target);
+                        l = &i->wanted_by;
                 else
-                        r = -EINVAL;
-
-                if (r < 0)
-                        return r;
+                        l = &i->required_by;
 
-                r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes);
-                if (r < 0)
-                        return r;
+                strv_free(*l);
+                *l = strv_new(target_info->name, NULL);
+                if (!*l)
+                        return -ENOMEM;
         }
 
-        return 0;
+        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
 }
 
 int unit_file_enable(
@@ -1588,13 +1784,18 @@ int unit_file_enable(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        char **i;
         _cleanup_free_ char *config_path = NULL;
+        UnitFileInstallInfo *i;
+        char **f;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
+
         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
                 return r;
@@ -1603,29 +1804,22 @@ int unit_file_enable(
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(i, files) {
-                UnitFileState state;
-
-                /* We only want to know if this unit is masked, so we ignore
-                 * errors from unit_file_get_state, deferring other checks.
-                 * This allows templated units to be enabled on the fly. */
-                state = unit_file_get_state(scope, root_dir, *i);
-                if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
-                        log_error("Failed to enable unit: Unit %s is masked", *i);
-                        return -EOPNOTSUPP;
-                }
-
-                r = install_info_add_auto(&c, *i);
+        STRV_FOREACH(f, files) {
+                r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i);
                 if (r < 0)
                         return r;
+                if (i->type == UNIT_FILE_TYPE_MASKED)
+                        return -ESHUTDOWN;
+
+                assert(i->type == UNIT_FILE_TYPE_REGULAR);
         }
 
         /* This will return the number of symlink rules that were
-        supposed to be created, not the ones actually created. This is
-        useful to determine whether the passed files had any
-        installation data at all. */
+           supposed to be created, not the ones actually created. This
+           is useful to determine whether the passed files had any
+           installation data at all. */
 
-        return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
+        return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
 }
 
 int unit_file_disable(
@@ -1638,14 +1832,18 @@ int unit_file_disable(
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
-        char **i;
         _cleanup_free_ char *config_path = NULL;
         _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-        int r, q;
+        char **i;
+        int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
 
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
+
         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
                 return r;
@@ -1655,18 +1853,19 @@ int unit_file_disable(
                 return r;
 
         STRV_FOREACH(i, files) {
-                r = install_info_add_auto(&c, *i);
+                if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+                        return -EINVAL;
+
+                r = install_info_add(&c, *i, NULL, NULL);
                 if (r < 0)
                         return r;
         }
 
-        r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
-
-        q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
-        if (r >= 0)
-                r = q;
+        r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir);
+        if (r < 0)
+                return r;
 
-        return r;
+        return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
 }
 
 int unit_file_reenable(
@@ -1677,21 +1876,30 @@ int unit_file_reenable(
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
+
+        char **n;
         int r;
+        size_t l, i;
 
-        r = unit_file_disable(scope, runtime, root_dir, files,
-                              changes, n_changes);
+        /* First, we invoke the disable command with only the basename... */
+        l = strv_length(files);
+        n = newa(char*, l+1);
+        for (i = 0; i < l; i++)
+                n[i] = basename(files[i]);
+        n[i] = NULL;
+
+        r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes);
         if (r < 0)
                 return r;
 
-        return unit_file_enable(scope, runtime, root_dir, files, force,
-                                changes, n_changes);
+        /* But the enable command with the full name */
+        return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes);
 }
 
 int unit_file_set_default(
                 UnitFileScope scope,
                 const char *root_dir,
-                const char *file,
+                const char *name,
                 bool force,
                 UnitFileChange **changes,
                 unsigned *n_changes) {
@@ -1699,42 +1907,40 @@ int unit_file_set_default(
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_(install_context_done) InstallContext c = {};
         _cleanup_free_ char *config_path = NULL;
-        char *path;
+        UnitFileInstallInfo *i;
+        const char *path;
         int r;
-        UnitFileInstallInfo *i = NULL;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
-        assert(file);
+        assert(name);
 
-        if (unit_name_to_type(file) != UNIT_TARGET)
+        if (unit_name_to_type(name) != UNIT_TARGET)
+                return -EINVAL;
+        if (streq(name, SPECIAL_DEFAULT_TARGET))
                 return -EINVAL;
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = verify_root_dir(scope, &root_dir);
         if (r < 0)
                 return r;
 
-        r = get_config_path(scope, false, root_dir, &config_path);
+        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
                 return r;
 
-        r = install_info_add_auto(&c, file);
+        r = get_config_path(scope, false, root_dir, &config_path);
         if (r < 0)
                 return r;
 
-        assert_se(i = ordered_hashmap_first(c.will_install));
-
-        r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL);
+        r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i);
         if (r < 0)
                 return r;
+        if (i->type == UNIT_FILE_TYPE_MASKED)
+                return -ESHUTDOWN;
 
         path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
 
-        r = create_symlink(i->path, path, force, changes, n_changes);
-        if (r < 0)
-                return r;
-
-        return 0;
+        return create_symlink(i->path, path, force, changes, n_changes);
 }
 
 int unit_file_get_default(
@@ -1743,126 +1949,101 @@ int unit_file_get_default(
                 char **name) {
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
-        char **p;
+        _cleanup_(install_context_done) InstallContext c = {};
+        UnitFileInstallInfo *i;
+        char *n;
         int r;
 
         assert(scope >= 0);
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        r = verify_root_dir(scope, &root_dir);
         if (r < 0)
                 return r;
 
-        STRV_FOREACH(p, paths.unit_path) {
-                _cleanup_free_ char *path = NULL, *tmp = NULL;
-                char *n;
-
-                path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET);
-                if (!path)
-                        return -ENOMEM;
-
-                r = readlink_malloc(path, &tmp);
-                if (r == -ENOENT)
-                        continue;
-                else if (r == -EINVAL)
-                        /* not a symlink */
-                        n = strdup(SPECIAL_DEFAULT_TARGET);
-                else if (r < 0)
-                        return r;
-                else
-                        n = strdup(basename(tmp));
+        r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+        if (r < 0)
+                return r;
 
-                if (!n)
-                        return -ENOMEM;
+        r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+        if (r < 0)
+                return r;
+        if (i->type == UNIT_FILE_TYPE_MASKED)
+                return -ESHUTDOWN;
 
-                *name = n;
-                return 0;
-        }
+        n = strdup(i->name);
+        if (!n)
+                return -ENOMEM;
 
-        return -ENOENT;
+        *name = n;
+        return 0;
 }
 
-UnitFileState unit_file_lookup_state(
+int unit_file_lookup_state(
                 UnitFileScope scope,
                 const char *root_dir,
                 const LookupPaths *paths,
-                const char *name) {
+                const char *name,
+                UnitFileState *ret) {
 
-        UnitFileState state = _UNIT_FILE_STATE_INVALID;
-        char **i;
-        _cleanup_free_ char *path = NULL;
-        int r = 0;
+        _cleanup_(install_context_done) InstallContext c = {};
+        UnitFileInstallInfo *i;
+        UnitFileState state;
+        int r;
 
         assert(paths);
+        assert(name);
 
         if (!unit_name_is_valid(name, UNIT_NAME_ANY))
                 return -EINVAL;
 
-        STRV_FOREACH(i, paths->unit_path) {
-                struct stat st;
-                char *partial;
-                bool also = false;
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
 
-                free(path);
-                path = path_join(root_dir, *i, name);
-                if (!path)
-                        return -ENOMEM;
+        r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+        if (r < 0)
+                return r;
 
-                if (root_dir)
-                        partial = path + strlen(root_dir);
-                else
-                        partial = path;
-
-                /*
-                 * Search for a unit file in our default paths, to
-                 * be sure, that there are no broken symlinks.
-                 */
-                if (lstat(path, &st) < 0) {
-                        r = -errno;
-                        if (errno != ENOENT)
-                                return r;
+        /* Shortcut things, if the caller just wants to know if this unit exists. */
+        if (!ret)
+                return 0;
 
-                        if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE))
-                                continue;
-                } else {
-                        if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
-                                return -ENOENT;
+        switch (i->type) {
 
-                        r = null_or_empty_path(path);
-                        if (r < 0 && r != -ENOENT)
-                                return r;
-                        else if (r > 0) {
-                                state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
-                                return state;
-                        }
-                }
+        case UNIT_FILE_TYPE_MASKED:
+                state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+                break;
 
-                r = find_symlinks_in_scope(scope, root_dir, name, &state);
+        case UNIT_FILE_TYPE_REGULAR:
+                r = find_symlinks_in_scope(scope, root_dir, i->name, &state);
                 if (r < 0)
                         return r;
-                else if (r > 0)
-                        return state;
-
-                r = unit_file_can_install(paths, root_dir, partial, true, &also);
-                if (r < 0 && errno != ENOENT)
-                        return r;
-                else if (r > 0)
-                        return UNIT_FILE_DISABLED;
-                else if (r == 0) {
-                        if (also)
-                                return UNIT_FILE_INDIRECT;
-                        return UNIT_FILE_STATIC;
+                if (r == 0) {
+                        if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
+                                state = UNIT_FILE_DISABLED;
+                        else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
+                                state = UNIT_FILE_INDIRECT;
+                        else
+                                state = UNIT_FILE_STATIC;
                 }
+
+                break;
+
+        default:
+                assert_not_reached("Unexpect unit file type.");
         }
 
-        return r < 0 ? r : state;
+        *ret = state;
+        return 0;
 }
 
-UnitFileState unit_file_get_state(
+int unit_file_get_state(
                 UnitFileScope scope,
                 const char *root_dir,
-                const char *name) {
+                const char *name,
+                UnitFileState *ret) {
 
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         int r;
@@ -1871,14 +2052,15 @@ UnitFileState unit_file_get_state(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(name);
 
-        if (root_dir && scope != UNIT_FILE_SYSTEM)
-                return -EINVAL;
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
 
         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
                 return r;
 
-        return unit_file_lookup_state(scope, root_dir, &paths, name);
+        return unit_file_lookup_state(scope, root_dir, &paths, name, ret);
 }
 
 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
@@ -1890,6 +2072,13 @@ 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;
+
         if (scope == UNIT_FILE_SYSTEM)
                 r = conf_files_list(&files, ".preset", root_dir,
                                     "/etc/systemd/system-preset",
@@ -1906,13 +2095,14 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
                                     "/usr/lib/systemd/user-preset",
                                     NULL);
         else
-                return 1;
+                return 1; /* Default is "enable" */
 
         if (r < 0)
                 return r;
 
         STRV_FOREACH(p, files) {
                 _cleanup_fclose_ FILE *f;
+                char line[LINE_MAX];
 
                 f = fopen(*p, "re");
                 if (!f) {
@@ -1922,39 +2112,38 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
                         return -errno;
                 }
 
-                for (;;) {
-                        char line[LINE_MAX], *l;
-
-                        if (!fgets(line, sizeof(line), f))
-                                break;
+                FOREACH_LINE(line, f, return -errno) {
+                        const char *parameter;
+                        char *l;
 
                         l = strstrip(line);
-                        if (!*l)
-                                continue;
 
-                        if (strchr(COMMENTS "\n", *l))
+                        if (isempty(l))
+                                continue;
+                        if (strchr(COMMENTS, *l))
                                 continue;
 
-                        if (first_word(l, "enable")) {
-                                l += 6;
-                                l += strspn(l, WHITESPACE);
-
-                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
+                        parameter = first_word(l, "enable");
+                        if (parameter) {
+                                if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
                                         log_debug("Preset file says enable %s.", name);
                                         return 1;
                                 }
 
-                        } else if (first_word(l, "disable")) {
-                                l += 7;
-                                l += strspn(l, WHITESPACE);
+                                continue;
+                        }
 
-                                if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
+                        parameter = first_word(l, "disable");
+                        if (parameter) {
+                                if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
                                         log_debug("Preset file says disable %s.", name);
                                         return 0;
                                 }
 
-                        } else
-                                log_debug("Couldn't parse line '%s'", l);
+                                continue;
+                        }
+
+                        log_debug("Couldn't parse line '%s'", l);
                 }
         }
 
@@ -1963,6 +2152,86 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
         return 1;
 }
 
+static int execute_preset(
+                UnitFileScope scope,
+                InstallContext *plus,
+                InstallContext *minus,
+                const LookupPaths *paths,
+                const char *config_path,
+                const char *root_dir,
+                char **files,
+                UnitFilePresetMode mode,
+                bool force,
+                UnitFileChange **changes,
+                unsigned *n_changes) {
+
+        int r;
+
+        assert(plus);
+        assert(minus);
+        assert(paths);
+        assert(config_path);
+
+        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);
+                if (r < 0)
+                        return r;
+
+                r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+        } else
+                r = 0;
+
+        if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
+                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);
+                if (r >= 0) {
+                        if (q < 0)
+                                r = q;
+                        else
+                                r+= q;
+                }
+        }
+
+        return r;
+}
+
+static int preset_prepare_one(
+                UnitFileScope scope,
+                InstallContext *plus,
+                InstallContext *minus,
+                LookupPaths *paths,
+                const char *root_dir,
+                UnitFilePresetMode mode,
+                const char *name) {
+
+        UnitFileInstallInfo *i;
+        int r;
+
+        if (install_info_find(plus, name) ||
+            install_info_find(minus, name))
+                return 0;
+
+        r = unit_file_query_preset(scope, 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);
+                if (r < 0)
+                        return r;
+
+                if (i->type == UNIT_FILE_TYPE_MASKED)
+                        return -ESHUTDOWN;
+        } else
+                r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+
+        return r;
+}
+
 int unit_file_preset(
                 UnitFileScope scope,
                 bool runtime,
@@ -1977,12 +2246,16 @@ int unit_file_preset(
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_free_ char *config_path = NULL;
         char **i;
-        int r, q;
+        int r;
 
         assert(scope >= 0);
         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);
         if (r < 0)
                 return r;
@@ -1992,44 +2265,15 @@ int unit_file_preset(
                 return r;
 
         STRV_FOREACH(i, files) {
-
                 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
                         return -EINVAL;
 
-                r = unit_file_query_preset(scope, root_dir, *i);
-                if (r < 0)
-                        return r;
-
-                if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
-                        r = install_info_add_auto(&plus, *i);
-                else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
-                        r = install_info_add_auto(&minus, *i);
-                else
-                        r = 0;
+                r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i);
                 if (r < 0)
                         return r;
         }
 
-        r = 0;
-
-        if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
-                _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-
-                r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
-
-                q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
-                if (r == 0)
-                        r = q;
-        }
-
-        if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
-                /* Returns number of symlinks that where supposed to be installed. */
-                q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
-                if (r == 0)
-                        r = q;
-        }
-
-        return r;
+        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes);
 }
 
 int unit_file_preset_all(
@@ -2045,12 +2289,16 @@ int unit_file_preset_all(
         _cleanup_lookup_paths_free_ LookupPaths paths = {};
         _cleanup_free_ char *config_path = NULL;
         char **i;
-        int r, q;
+        int r;
 
         assert(scope >= 0);
         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);
         if (r < 0)
                 return r;
@@ -2062,6 +2310,7 @@ int unit_file_preset_all(
         STRV_FOREACH(i, paths.unit_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)
@@ -2075,62 +2324,23 @@ int unit_file_preset_all(
                         return -errno;
                 }
 
-                for (;;) {
-                        struct dirent *de;
-
-                        errno = 0;
-                        de = readdir(d);
-                        if (!de && errno != 0)
-                                return -errno;
-
-                        if (!de)
-                                break;
-
-                        if (hidden_file(de->d_name))
-                                continue;
+                FOREACH_DIRENT(de, d, return -errno) {
 
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
 
                         dirent_ensure_type(d, de);
 
-                        if (de->d_type != DT_REG)
+                        if (!IN_SET(de->d_type, DT_LNK, DT_REG))
                                 continue;
 
-                        r = unit_file_query_preset(scope, root_dir, de->d_name);
-                        if (r < 0)
-                                return r;
-
-                        if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY)
-                                r = install_info_add_auto(&plus, de->d_name);
-                        else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY)
-                                r = install_info_add_auto(&minus, de->d_name);
-                        else
-                                r = 0;
+                        r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name);
                         if (r < 0)
                                 return r;
                 }
         }
 
-        r = 0;
-
-        if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
-                _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
-
-                r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
-
-                q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL);
-                if (r == 0)
-                        r = q;
-        }
-
-        if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
-                q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
-                if (r == 0)
-                        r = q;
-        }
-
-        return r;
+        return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes);
 }
 
 static void unit_file_list_free_one(UnitFileList *f) {
@@ -2141,6 +2351,15 @@ static void unit_file_list_free_one(UnitFileList *f) {
         free(f);
 }
 
+Hashmap* unit_file_list_free(Hashmap *h) {
+        UnitFileList *i;
+
+        while ((i = hashmap_steal_first(h)))
+                unit_file_list_free_one(i);
+
+        return hashmap_free(h);
+}
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
 
 int unit_file_get_list(
@@ -2156,14 +2375,9 @@ int unit_file_get_list(
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(h);
 
-        if (root_dir && scope != UNIT_FILE_SYSTEM)
-                return -EINVAL;
-
-        if (root_dir) {
-                r = access(root_dir, F_OK);
-                if (r < 0)
-                        return -errno;
-        }
+        r = verify_root_dir(scope, &root_dir);
+        if (r < 0)
+                return r;
 
         r = lookup_paths_init_from_scope(&paths, scope, root_dir);
         if (r < 0)
@@ -2172,6 +2386,7 @@ int unit_file_get_list(
         STRV_FOREACH(i, paths.unit_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)
@@ -2185,22 +2400,8 @@ int unit_file_get_list(
                         return -errno;
                 }
 
-                for (;;) {
+                FOREACH_DIRENT(de, d, return -errno) {
                         _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
-                        struct dirent *de;
-                        _cleanup_free_ char *path = NULL;
-                        bool also = false;
-
-                        errno = 0;
-                        de = readdir(d);
-                        if (!de && errno != 0)
-                                return -errno;
-
-                        if (!de)
-                                break;
-
-                        if (hidden_file(de->d_name))
-                                continue;
 
                         if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
                                 continue;
@@ -2221,44 +2422,14 @@ int unit_file_get_list(
                         if (!f->path)
                                 return -ENOMEM;
 
-                        r = null_or_empty_path(f->path);
-                        if (r < 0 && r != -ENOENT)
-                                return r;
-                        else if (r > 0) {
-                                f->state =
-                                        path_startswith(*i, "/run") ?
-                                        UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
-                                goto found;
-                        }
-
-                        r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
+                        r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state);
                         if (r < 0)
-                                return r;
-                        else if (r > 0) {
-                                f->state = UNIT_FILE_ENABLED;
-                                goto found;
-                        }
-
-                        path = path_make_absolute(de->d_name, *i);
-                        if (!path)
-                                return -ENOMEM;
+                                f->state = UNIT_FILE_BAD;
 
-                        r = unit_file_can_install(&paths, root_dir, path, true, &also);
-                        if (r == -EINVAL ||  /* Invalid setting? */
-                            r == -EBADMSG || /* Invalid format? */
-                            r == -ENOENT     /* Included file not found? */)
-                                f->state = UNIT_FILE_INVALID;
-                        else if (r < 0)
-                                return r;
-                        else if (r > 0)
-                                f->state = UNIT_FILE_DISABLED;
-                        else
-                                f->state = also ? UNIT_FILE_INDIRECT : UNIT_FILE_STATIC;
-
-                found:
                         r = hashmap_put(h, basename(f->path), f);
                         if (r < 0)
                                 return r;
+
                         f = NULL; /* prevent cleanup */
                 }
         }
@@ -2276,7 +2447,7 @@ 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_INVALID] = "invalid",
+        [UNIT_FILE_BAD] = "bad",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
index a9d77dd91b5244761bc489739891dcaaaaffce40..45a417df92af892c28c6d81bfaaf8dd97e5f716b 100644 (file)
@@ -25,13 +25,15 @@ typedef enum UnitFileScope UnitFileScope;
 typedef enum UnitFileState UnitFileState;
 typedef enum UnitFilePresetMode UnitFilePresetMode;
 typedef enum UnitFileChangeType UnitFileChangeType;
+typedef enum UnitFileType UnitFileType;
 typedef struct UnitFileChange UnitFileChange;
 typedef struct UnitFileList UnitFileList;
 typedef struct UnitFileInstallInfo UnitFileInstallInfo;
 
 #include "hashmap.h"
-#include "unit-name.h"
 #include "path-lookup.h"
+#include "strv.h"
+#include "unit-name.h"
 
 enum UnitFileScope {
         UNIT_FILE_SYSTEM,
@@ -51,7 +53,7 @@ enum UnitFileState {
         UNIT_FILE_STATIC,
         UNIT_FILE_DISABLED,
         UNIT_FILE_INDIRECT,
-        UNIT_FILE_INVALID,
+        UNIT_FILE_BAD,
         _UNIT_FILE_STATE_MAX,
         _UNIT_FILE_STATE_INVALID = -1
 };
@@ -82,10 +84,17 @@ struct UnitFileList {
         UnitFileState state;
 };
 
+enum UnitFileType {
+        UNIT_FILE_TYPE_REGULAR,
+        UNIT_FILE_TYPE_SYMLINK,
+        UNIT_FILE_TYPE_MASKED,
+        _UNIT_FILE_TYPE_MAX,
+        _UNIT_FILE_TYPE_INVALID = -1,
+};
+
 struct UnitFileInstallInfo {
         char *name;
         char *path;
-        char *user;
 
         char **aliases;
         char **wanted_by;
@@ -93,8 +102,26 @@ struct UnitFileInstallInfo {
         char **also;
 
         char *default_instance;
+
+        UnitFileType type;
+
+        char *symlink_target;
 };
 
+static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(UnitFileInstallInfo *i) {
+        assert(i);
+
+        return !strv_isempty(i->aliases) ||
+               !strv_isempty(i->wanted_by) ||
+               !strv_isempty(i->required_by);
+}
+
+static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
+        assert(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);
@@ -105,21 +132,14 @@ int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char
 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, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
-
-UnitFileState unit_file_lookup_state(
-                UnitFileScope scope,
-                const char *root_dir,
-                const LookupPaths *paths,
-                const char *name);
-UnitFileState unit_file_get_state(
-                UnitFileScope scope,
-                const char *root_dir,
-                const char *filename);
+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);
+int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
 
 int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
+Hashmap* unit_file_list_free(Hashmap *h);
 
-void 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);
 
index dbc07aa7ad93b2896e8b78771e857ff3b32ab295..0313b0946f38f455dbf90352797ca4c9c76bc3e5 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <time.h>
 #include <errno.h>
-#include <sys/socket.h>
-#include <string.h>
 #include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
 
-#include "logs-show.h"
-#include "log.h"
-#include "util.h"
-#include "utf8.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
 #include "hashmap.h"
+#include "hostname-util.h"
+#include "io-util.h"
 #include "journal-internal.h"
-#include "formats-util.h"
+#include "log.h"
+#include "logs-show.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "terminal-util.h"
-#include "hostname-util.h"
+#include "utf8.h"
+#include "util.h"
 
-/* up to three lines (each up to 100 characters),
-   or 300 characters, whichever is less */
+/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
 #define PRINT_LINE_THRESHOLD 3
 #define PRINT_CHAR_THRESHOLD 300
 
index 9c1e4d5e13e261424d0a65f4275184645e3fd896..2c1da0a40d51ccc0cef05709633b009afb98244e 100644 (file)
 #include <linux/fs.h>
 #include <sys/statfs.h>
 
+#include "alloc-util.h"
 #include "btrfs-util.h"
+#include "chattr-util.h"
 #include "copy.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "machine-image.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "rm-rf.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
-
-#include "machine-image.h"
+#include "xattr-util.h"
 
 static const char image_search_path[] =
         "/var/lib/machines\0"
@@ -176,11 +183,10 @@ static int image_make(
                                 return r;
                         if (r) {
                                 BtrfsSubvolInfo info;
-                                BtrfsQuotaInfo quota;
 
                                 /* It's a btrfs subvolume */
 
-                                r = btrfs_subvol_get_info_fd(fd, &info);
+                                r = btrfs_subvol_get_info_fd(fd, 0, &info);
                                 if (r < 0)
                                         return r;
 
@@ -195,13 +201,17 @@ static int image_make(
                                 if (r < 0)
                                         return r;
 
-                                r = btrfs_subvol_get_quota_fd(fd, &quota);
-                                if (r >= 0) {
-                                        (*ret)->usage = quota.referenced;
-                                        (*ret)->usage_exclusive = quota.exclusive;
+                                if (btrfs_quota_scan_ongoing(fd) == 0) {
+                                        BtrfsQuotaInfo quota;
 
-                                        (*ret)->limit = quota.referenced_max;
-                                        (*ret)->limit_exclusive = quota.exclusive_max;
+                                        r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
+                                        if (r >= 0) {
+                                                (*ret)->usage = quota.referenced;
+                                                (*ret)->usage_exclusive = quota.exclusive;
+
+                                                (*ret)->limit = quota.referenced_max;
+                                                (*ret)->limit_exclusive = quota.exclusive_max;
+                                        }
                                 }
 
                                 return 1;
@@ -397,7 +407,7 @@ int image_remove(Image *i) {
         switch (i->type) {
 
         case IMAGE_SUBVOLUME:
-                r = btrfs_subvol_remove(i->path, true);
+                r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
                 if (r < 0)
                         return r;
                 break;
@@ -587,7 +597,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
         case IMAGE_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);
+                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);
+
+                /* 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);
+
                 break;
 
         case IMAGE_RAW:
@@ -629,6 +644,10 @@ int image_read_only(Image *i, bool b) {
         switch (i->type) {
 
         case IMAGE_SUBVOLUME:
+
+                /* Note that we set the flag only on the top-level
+                 * subvolume of the image. */
+
                 r = btrfs_subvol_set_read_only(i->path, b);
                 if (r < 0)
                         return r;
@@ -729,7 +748,14 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
         if (i->type != IMAGE_SUBVOLUME)
                 return -EOPNOTSUPP;
 
-        return btrfs_quota_limit(i->path, referenced_max);
+        /* We set the quota both for the subvolume as well as for the
+         * subtree. The latter is mostly for historical reasons, since
+         * we didn't use to have a concept of subtree quota, and hence
+         * only modified the subvolume quota. */
+
+        (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
+        (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+        return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
 }
 
 int image_name_lock(const char *name, int operation, LockFile *ret) {
index 8af78f47d5e3775de87065a6a3cb7e86dbd1ea08..4172a63fd056ddd507fa3fa85515648c0575bcb6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <sys/mount.h>
 #include <sys/prctl.h>
-#include <sys/vfs.h>
 #include <sys/statvfs.h>
-#include <sys/mount.h>
+#include <sys/vfs.h>
 
-#include "util.h"
-#include "process-util.h"
+#include "alloc-util.h"
+#include "btrfs-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "lockfile-util.h"
+#include "machine-pool.h"
 #include "mkdir.h"
-#include "btrfs-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
 #include "path-util.h"
+#include "process-util.h"
 #include "signal-util.h"
-#include "machine-pool.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
 
 #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
 #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
@@ -170,7 +178,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
         };
         _cleanup_close_ int fd = -1, control = -1, loop = -1;
         _cleanup_free_ char* loopdev = NULL;
-        char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
+        char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL;
         bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
         char buf[FORMAT_BYTES_MAX];
         int r, nr = -1;
@@ -194,14 +202,35 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
 
                 r = btrfs_quota_enable("/var/lib/machines", true);
                 if (r < 0)
-                        log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+                        log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
+
+                r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
+
+                return 1;
+        }
 
+        if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0) {
+                log_debug("/var/lib/machines is already a mount point, not creating loopback file for it.");
                 return 0;
         }
 
-        if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
-            dir_is_empty("/var/lib/machines") == 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
+        r = dir_is_populated("/var/lib/machines");
+        if (r < 0 && r != -ENOENT)
+                return r;
+        if (r > 0) {
+                log_debug("/var/log/machines is already populated, not creating loopback file for it.");
+                return 0;
+        }
+
+        r = mkfs_exists("btrfs");
+        if (r == -ENOENT) {
+                log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines.");
+                return 0;
+        }
+        if (r < 0)
+                return r;
 
         fd = setup_machine_raw(size, error);
         if (fd < 0)
@@ -266,6 +295,10 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
         if (r < 0)
                 log_warning_errno(r, "Failed to enable quota, ignoring: %m");
 
+        r = btrfs_subvol_auto_qgroup(mntdir, 0, true);
+        if (r < 0)
+                log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m");
+
         if (chmod(mntdir, 0700) < 0) {
                 r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
                 goto fail;
@@ -286,7 +319,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
         (void) rmdir(mntdir);
         (void) rmdir(tmpdir);
 
-        return 0;
+        return 1;
 
 fail:
         if (mntdir_mounted)
@@ -345,7 +378,7 @@ int grow_machine_directory(void) {
         if (b.f_bavail > b.f_blocks / 3)
                 return 0;
 
-        /* Calculate how much we are willing to add at maximum */
+        /* Calculate how much we are willing to add at most */
         max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN;
 
         /* Calculate the old size */
@@ -370,9 +403,11 @@ int grow_machine_directory(void) {
         if (r <= 0)
                 return r;
 
-        r = btrfs_quota_limit("/var/lib/machines", new_size);
-        if (r < 0)
-                return r;
+        /* Also bump the quota, of both the subvolume leaf qgroup, as
+         * well as of any subtree quota group by the same id but a
+         * higher level, if it exists. */
+        (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
+        (void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
 
         log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
         return 1;
index d8f0fb404db354640be51faaa7c45b7aacffb0a7..d149bc1722d5ded57abe0ba202c82b2ab9adb6a0 100644 (file)
 
 #include <fcntl.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <string.h>
 #include <sys/prctl.h>
+#include <unistd.h>
 
+#include "copy.h"
+#include "fd-util.h"
+#include "locale-util.h"
+#include "macro.h"
 #include "pager.h"
-#include "util.h"
 #include "process-util.h"
-#include "macro.h"
-#include "terminal-util.h"
 #include "signal-util.h"
-#include "copy.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
 
 static pid_t pager_pid = 0;
 
index 34eec959ef910191120915394ea31b91fb5c2250..d71f379e76732b4a74d208b3ccfe15a7c8baf38e 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#include "alloc-util.h"
 #include "util.h"
 #include "strv.h"
 #include "path-util.h"
-#include "path-lookup.h"
 #include "install.h"
+#include "string-util.h"
+#include "path-lookup.h"
 
 int user_config_home(char **config_home) {
         const char *e;
@@ -210,7 +212,7 @@ static char** user_dirs(
                 if (strv_extend(&res, generator_late) < 0)
                         return NULL;
 
-        if (!path_strv_make_absolute_cwd(res))
+        if (path_strv_make_absolute_cwd(res) < 0)
                 return NULL;
 
         tmp = res;
@@ -244,6 +246,7 @@ int lookup_paths_init(
 
         const char *e;
         bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
+        int r;
 
         assert(p);
 
@@ -259,9 +262,9 @@ int lookup_paths_init(
                 /* FIXME: empty components in other places should be
                  * rejected. */
 
-                p->unit_path = path_split_and_make_absolute(e);
-                if (!p->unit_path)
-                        return -ENOMEM;
+                r = path_split_and_make_absolute(e, &p->unit_path);
+                if (r < 0)
+                        return r;
         } else
                 p->unit_path = NULL;
 
@@ -269,7 +272,6 @@ int lookup_paths_init(
                 /* Let's figure something out. */
 
                 _cleanup_strv_free_ char **unit_path;
-                int r;
 
                 /* For the user units we include share/ in the search
                  * path in order to comply with the XDG basedir spec.
@@ -342,9 +344,9 @@ int lookup_paths_init(
 
                 e = getenv("SYSTEMD_SYSVINIT_PATH");
                 if (e) {
-                        p->sysvinit_path = path_split_and_make_absolute(e);
-                        if (!p->sysvinit_path)
-                                return -ENOMEM;
+                        r = path_split_and_make_absolute(e, &p->sysvinit_path);
+                        if (r < 0)
+                                return r;
                 } else
                         p->sysvinit_path = NULL;
 
@@ -360,9 +362,9 @@ int lookup_paths_init(
 
                 e = getenv("SYSTEMD_SYSVRCND_PATH");
                 if (e) {
-                        p->sysvrcnd_path = path_split_and_make_absolute(e);
-                        if (!p->sysvrcnd_path)
-                                return -ENOMEM;
+                        r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
+                        if (r < 0)
+                                return r;
                 } else
                         p->sysvrcnd_path = NULL;
 
@@ -417,9 +419,8 @@ void lookup_paths_free(LookupPaths *p) {
         p->unit_path = strv_free(p->unit_path);
 
 #ifdef HAVE_SYSV_COMPAT
-        strv_free(p->sysvinit_path);
-        strv_free(p->sysvrcnd_path);
-        p->sysvinit_path = p->sysvrcnd_path = NULL;
+        p->sysvinit_path = strv_free(p->sysvinit_path);
+        p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
 #endif
 }
 
index 7749f205408b43691366c534dcc00cb953c36562..63e81f489490ed3af4bb8902ed8a754799815c31 100644 (file)
 #include <limits.h>
 #include <termios.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "ptyfwd.h"
+#include "util.h"
 
 struct PTYForward {
         sd_event *event;
@@ -411,6 +413,7 @@ PTYForward *pty_forward_free(PTYForward *f) {
                 sd_event_source_unref(f->stdin_event_source);
                 sd_event_source_unref(f->stdout_event_source);
                 sd_event_source_unref(f->master_event_source);
+                sd_event_source_unref(f->sigwinch_event_source);
                 sd_event_unref(f->event);
 
                 if (f->saved_stdout)
index d73a74912e385385c8ad808cb61a0835a380d9f8..c518cf83ec4084a6885c5e3fe07336d0efcd5e08 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <seccomp.h>
 
+#include "string-util.h"
 #include "util.h"
 #include "seccomp-util.h"
 
index 3dedbd1f6269db89a72569a466b9ce7a4296300d..39b836d0535403c0c598ee8998dd6ecf5627d1c5 100644 (file)
 
 #include <stdio.h>
 
+#include "alloc-util.h"
 #include "conf-parser.h"
-#include "sleep-config.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
+#include "parse-util.h"
+#include "sleep-config.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
@@ -49,7 +54,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
         };
 
         config_parse_many(PKGSYSCONFDIR "/sleep.conf",
-                          CONF_DIRS_NULSTR("systemd/sleep.conf"),
+                          CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
                           "Sleep\0", config_item_table_lookup, items,
                           false, NULL);
 
index 4db249e1cac8fd298fe072c15116d2925581f061..ec6e5a8312ea47cd78b4727afc5170a56b373b5a 100644 (file)
 #include <errno.h>
 #include <poll.h>
 
+#include "fd-util.h"
+#include "io-util.h"
 #include "log.h"
-#include "util.h"
 #include "process-util.h"
 #include "spawn-polkit-agent.h"
+#include "stdio-util.h"
+#include "util.h"
 
 #ifdef ENABLE_POLKIT
 static pid_t agent_pid = 0;
@@ -76,8 +79,9 @@ void polkit_agent_close(void) {
                 return;
 
         /* Inform agent that we are done */
-        kill(agent_pid, SIGTERM);
-        kill(agent_pid, SIGCONT);
+        (void) kill(agent_pid, SIGTERM);
+        (void) kill(agent_pid, SIGCONT);
+
         (void) wait_for_terminate(agent_pid, NULL);
         agent_pid = 0;
 }
index 85bd477f2dedc174dcbd7defc6f5bbfec70319a2..c5c4a4d7d7fad41bde406909cf40c86660aa1344 100644 (file)
 #include <string.h>
 #include <sys/utsname.h>
 
-#include "macro.h"
-#include "util.h"
+#include "alloc-util.h"
 #include "hostname-util.h"
+#include "macro.h"
 #include "specifier.h"
+#include "string-util.h"
+#include "util.h"
 
 /*
  * Generic infrastructure for replacing %x style specifiers in
index b12189cd10c7a195f98de5e0eaea9d4599f119fe..fc885f6cb8140f2a79e81f7b16354916215477d7 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/stat.h>
-#include <stdbool.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
 #include <string.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <unistd.h>
-#include <fcntl.h>
 
-#include "util.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
 #include "base-filesystem.h"
+#include "fd-util.h"
 #include "missing.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
 #include "switch-root.h"
+#include "user-util.h"
+#include "util.h"
 
 int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,  unsigned long mountflags) {
 
index b2cab948efb22c97033e6b540db9321f479be700..21cb82ea1cc45bc1800802987b0e4f09dd70b1ed 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "fileio.h"
 #include "log.h"
+#include "string-util.h"
 #include "util.h"
 #include "sysctl-util.h"
 
index 4794ff45bbbaf0033f9f4fb974945476a47f8fa1..079dd8752cceead399f81c0e8195ea8312a1848f 100644 (file)
@@ -19,8 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "uid-range.h"
+#include "user-util.h"
+#include "util.h"
 
 static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
         assert(range);
index 63f1e4ca6fdb02775e23691fe70de1d896ab0cdb..13b32a0509b5b6ee33cddc1faae131e87022e993 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <utmpx.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
 #include <string.h>
 #include <sys/utsname.h>
-#include <fcntl.h>
 #include <unistd.h>
-#include <poll.h>
+#include <utmpx.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hostname-util.h"
 #include "macro.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
-#include "hostname-util.h"
+#include "user-util.h"
 #include "utmp-wtmp.h"
 
 int utmp_get_runlevel(int *runlevel, int *previous) {
index 9d39beb3404deee679733c33f1d14ea43da890bc..d58f9873d507f82e1f71f04a84d0084530ae2d6f 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "watchdog.h"
 #include "log.h"
+#include "fd-util.h"
 
 static int watchdog_fd = -1;
 static usec_t watchdog_timeout = USEC_INFINITY;
index 1ba66eb9981078111bab166271f195749b7701c8..95de369817382fbd556b23027dfc0226ad5810fc 100644 (file)
 #include "sd-messages.h"
 
 #include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
 #include "sleep-config.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
index 73c04fdfc089932fa8d74cf4186c0a0fc245d32d..ba82adadb425601f039ed910dd5c3fd0e55723c7 100644 (file)
 #include "sd-event.h"
 #include "sd-resolve.h"
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "log.h"
 #include "path-util.h"
 #include "set.h"
 #include "socket-util.h"
+#include "string-util.h"
 #include "util.h"
 
 #define BUFFER_SIZE (256 * 1024)
index ee34209a30ff99c46915a532e21714302a8d1e9e..25b5ff52eab6a3adff91a52db656c874761edc0a 100644 (file)
 #include <string.h>
 
 #include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "hashmap.h"
 #include "log.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "sysctl-util.h"
 #include "util.h"
 
 static char **arg_prefixes = NULL;
 
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysctl.d");
 
 static int apply_all(Hashmap *sysctl_options) {
         char *property, *value;
@@ -85,8 +88,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
                         if (feof(f))
                                 break;
 
-                        log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
-                        return -errno;
+                        return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
                 }
 
                 p = strstrip(l);
index 00045150f61b30c333c1c13da2e563911357b861..6c2f53774dede2d608497225d3a6d81de10ba961 100644 (file)
@@ -22,7 +22,9 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include "fs-util.h"
 #include "log.h"
+#include "string-util.h"
 #include "util.h"
 
 /*
index 420a246be15ffcc278861d6930180e9d73e326ff..51b82d57dbf7b44f2e9ec8725deeba82c9496be7 100644 (file)
@@ -37,6 +37,7 @@
 #include "sd-daemon.h"
 #include "sd-login.h"
 
+#include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-message.h"
 #include "efivars.h"
 #include "env-util.h"
 #include "exit-status.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
 #include "hostname-util.h"
 #include "initreq.h"
 #include "install.h"
+#include "io-util.h"
 #include "list.h"
+#include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
 #include "macro.h"
 #include "mkdir.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "rlimit-util.h"
 #include "set.h"
 #include "signal-util.h"
 #include "socket-util.h"
 #include "spawn-ask-password-agent.h"
 #include "spawn-polkit-agent.h"
 #include "special.h"
+#include "stat-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
+#include "user-util.h"
 #include "util.h"
 #include "utmp-wtmp.h"
 #include "verbs.h"
+#include "virt.h"
 
 static char **arg_types = NULL;
 static char **arg_states = NULL;
@@ -107,7 +118,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
 static char **arg_wall = NULL;
 static const char *arg_kill_who = NULL;
 static int arg_signal = SIGTERM;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
 static usec_t arg_when = 0;
 static enum action {
         _ACTION_INVALID,
@@ -285,6 +296,10 @@ static bool install_client_side(void) {
         if (arg_scope == UNIT_FILE_GLOBAL)
                 return true;
 
+        /* Unsupported environment variable, mostly for debugging purposes */
+        if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
+                return true;
+
         return false;
 }
 
@@ -1320,7 +1335,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
                            UNIT_FILE_MASKED,
                            UNIT_FILE_MASKED_RUNTIME,
                            UNIT_FILE_DISABLED,
-                           UNIT_FILE_INVALID)) {
+                           UNIT_FILE_BAD)) {
                         on  = ansi_highlight_red();
                         off = ansi_normal();
                 } else if (u->state == UNIT_FILE_ENABLED) {
@@ -1488,16 +1503,12 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
 
         static const char *dependencies[_DEPENDENCY_MAX] = {
                 [DEPENDENCY_FORWARD] = "Requires\0"
-                                       "RequiresOverridable\0"
                                        "Requisite\0"
-                                       "RequisiteOverridable\0"
                                        "Wants\0"
                                        "ConsistsOf\0"
                                        "BindsTo\0",
                 [DEPENDENCY_REVERSE] = "RequiredBy\0"
-                                       "RequiredByOverridable\0"
                                        "RequisiteOf\0"
-                                       "RequisiteOfOverridable\0"
                                        "WantedBy\0"
                                        "PartOf\0"
                                        "BoundBy\0",
@@ -2171,7 +2182,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
                 return bus_log_parse_error(r);
 
         output_jobs_list(jobs, c, skipped);
-        return r;
+        return 0;
 }
 
 static int cancel_job(int argc, char *argv[], void *userdata) {
@@ -3475,7 +3486,8 @@ static void print_status_info(
 
                                 dir = mfree(dir);
 
-                                if (path_get_parent(*dropin, &dir) < 0) {
+                                dir = dirname_malloc(*dropin);
+                                if (!dir) {
                                         log_oom();
                                         return;
                                 }
@@ -4889,102 +4901,6 @@ static int set_property(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
-static int snapshot(int argc, char *argv[], void *userdata) {
-        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
-        _cleanup_free_ char *n = NULL, *id = NULL;
-        const char *path;
-        sd_bus *bus;
-        int r;
-
-        polkit_agent_open_if_enabled();
-
-        if (argc > 1) {
-                r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to generate unit name: %m");
-        } else {
-                n = strdup("");
-                if (!n)
-                        return log_oom();
-        }
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "CreateSnapshot",
-                        &error,
-                        &reply,
-                        "sb", n, false);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r));
-
-        r = sd_bus_message_read(reply, "o", &path);
-        if (r < 0)
-                return bus_log_parse_error(r);
-
-        r = sd_bus_get_property_string(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        path,
-                        "org.freedesktop.systemd1.Unit",
-                        "Id",
-                        &error,
-                        &id);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r));
-
-        if (!arg_quiet)
-                puts(id);
-
-        return 0;
-}
-
-static int delete_snapshot(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **names = NULL;
-        sd_bus *bus;
-        char **name;
-        int r;
-
-        polkit_agent_open_if_enabled();
-
-        r = acquire_bus(BUS_MANAGER, &bus);
-        if (r < 0)
-                return r;
-
-        r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names);
-        if (r < 0)
-                return log_error_errno(r, "Failed to expand names: %m");
-
-        STRV_FOREACH(name, names) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-                int q;
-
-                q = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "RemoveSnapshot",
-                                &error,
-                                NULL,
-                                "s", *name);
-                if (q < 0) {
-                        log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
-                        if (r == 0)
-                                r = q;
-                }
-        }
-
-        return r;
-}
-
 static int daemon_reload(int argc, char *argv[], void *userdata) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         const char *method;
@@ -5305,6 +5221,9 @@ static int enable_sysv_units(const char *verb, char **args) {
         if (arg_scope != UNIT_FILE_SYSTEM)
                 return 0;
 
+        if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
+                return 0;
+
         if (!STR_IN_SET(verb,
                         "enable",
                         "disable",
@@ -5514,10 +5433,10 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
                 else
                         assert_not_reached("Unknown verb");
 
-                if (r < 0) {
-                        log_error_errno(r, "Operation failed: %m");
-                        goto finish;
-                }
+                if (r == -ESHUTDOWN)
+                        return log_error_errno(r, "Unit file is masked.");
+                if (r < 0)
+                        return log_error_errno(r, "Operation failed: %m");
 
                 if (!arg_quiet)
                         dump_unit_file_changes(changes, n_changes);
@@ -5634,7 +5553,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
 
                 r = acquire_bus(BUS_MANAGER, &bus);
                 if (r < 0)
-                        return r;
+                        goto finish;
 
                 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
                 for (i = 0; i < n_changes; i++)
@@ -5680,7 +5599,8 @@ 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");
 
@@ -5817,8 +5737,8 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
                 STRV_FOREACH(name, names) {
                         UnitFileState state;
 
-                        state = unit_file_get_state(arg_scope, arg_root, *name);
-                        if (state < 0)
+                        r = unit_file_get_state(arg_scope, arg_root, *name, &state);
+                        if (r < 0)
                                 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
 
                         if (IN_SET(state,
@@ -6362,9 +6282,6 @@ static void systemctl_help(void) {
                "Job Commands:\n"
                "  list-jobs [PATTERN...]          List jobs\n"
                "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
-               "Snapshot Commands:\n"
-               "  snapshot [NAME]                 Create a snapshot\n"
-               "  delete NAME...                  Remove one or more snapshots\n\n"
                "Environment Commands:\n"
                "  show-environment                Dump environment\n"
                "  set-environment NAME=VALUE...   Set one or more environment variables\n"
@@ -6506,11 +6423,6 @@ static void help_states(void) {
         for (i = 0; i < _SLICE_STATE_MAX; i++)
                 puts(slice_state_to_string(i));
 
-        if (!arg_no_legend)
-                puts("\nAvailable snapshot unit substates:");
-        for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
-                puts(snapshot_state_to_string(i));
-
         if (!arg_no_legend)
                 puts("\nAvailable socket unit substates:");
         for (i = 0; i < _SOCKET_STATE_MAX; i++)
@@ -6612,7 +6524,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 {}
         };
 
-        int c;
+        const char *p;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
@@ -6632,15 +6545,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case 't': {
-                        const char *word, *state;
-                        size_t size;
+                        if (isempty(optarg))
+                                return log_error_errno(r, "--type requires arguments.");
 
-                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                _cleanup_free_ char *type;
+                        p = optarg;
+                        for(;;) {
+                                _cleanup_free_ char *type = NULL;
 
-                                type = strndup(word, size);
-                                if (!type)
-                                        return -ENOMEM;
+                                r = extract_first_word(&p, &type, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse type: %s", optarg);
+
+                                if (r == 0)
+                                        break;
 
                                 if (streq(type, "help")) {
                                         help_types();
@@ -6681,18 +6598,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 if (!arg_properties)
                                         return log_oom();
                         } else {
-                                const char *word, *state;
-                                size_t size;
+                                p = optarg;
+                                for(;;) {
+                                        _cleanup_free_ char *prop = NULL;
 
-                                FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
-                                        char *prop;
+                                        r = extract_first_word(&p, &prop, ",", 0);
+                                        if (r < 0)
+                                                return log_error_errno(r, "Failed to parse property: %s", optarg);
 
-                                        prop = strndup(word, size);
-                                        if (!prop)
-                                                return log_oom();
+                                        if (r == 0)
+                                                break;
 
-                                        if (strv_consume(&arg_properties, prop) < 0)
+                                        if (strv_push(&arg_properties, prop) < 0)
                                                 return log_oom();
+
+                                        prop = NULL;
                                 }
                         }
 
@@ -6769,7 +6689,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case 'l':
@@ -6856,15 +6778,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_STATE: {
-                        const char *word, *state;
-                        size_t size;
+                        if (isempty(optarg))
+                                return log_error_errno(r, "--signal requires arguments.");
 
-                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
+                        p = optarg;
+                        for(;;) {
                                 _cleanup_free_ char *s = NULL;
 
-                                s = strndup(word, size);
-                                if (!s)
-                                        return log_oom();
+                                r = extract_first_word(&p, &s, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse signal: %s", optarg);
+
+                                if (r == 0)
+                                        break;
 
                                 if (streq(s, "help")) {
                                         help_states();
@@ -7399,14 +7325,14 @@ static int talk_initctl(void) {
 static int systemctl_main(int argc, char *argv[]) {
 
         static const Verb verbs[] = {
-                { "list-units",            VERB_ANY, 1,        VERB_DEFAULT, list_units        },
-                { "list-unit-files",       VERB_ANY, 1,        0,            list_unit_files   },
-                { "list-sockets",          VERB_ANY, 1,        0,            list_sockets      },
-                { "list-timers",           VERB_ANY, 1,        0,            list_timers       },
-                { "list-jobs",             VERB_ANY, 1,        0,            list_jobs         },
-                { "list-machines",         VERB_ANY, 1,        0,            list_machines     },
+                { "list-units",            VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units        },
+                { "list-unit-files",       VERB_ANY, VERB_ANY, 0,            list_unit_files   },
+                { "list-sockets",          VERB_ANY, VERB_ANY, 0,            list_sockets      },
+                { "list-timers",           VERB_ANY, VERB_ANY, 0,            list_timers       },
+                { "list-jobs",             VERB_ANY, VERB_ANY, 0,            list_jobs         },
+                { "list-machines",         VERB_ANY, VERB_ANY, 0,            list_machines     },
                 { "clear-jobs",            VERB_ANY, 1,        0,            daemon_reload     },
-                { "cancel",                2,        VERB_ANY, 0,            cancel_job        },
+                { "cancel",                VERB_ANY, VERB_ANY, 0,            cancel_job        },
                 { "start",                 2,        VERB_ANY, 0,            start_unit        },
                 { "stop",                  2,        VERB_ANY, 0,            start_unit        },
                 { "condstop",              2,        VERB_ANY, 0,            start_unit        }, /* For compatibility with ALTLinux */
@@ -7427,8 +7353,6 @@ static int systemctl_main(int argc, char *argv[]) {
                 { "cat",                   2,        VERB_ANY, 0,            cat               },
                 { "status",                VERB_ANY, VERB_ANY, 0,            show              },
                 { "help",                  VERB_ANY, VERB_ANY, 0,            show              },
-                { "snapshot",              VERB_ANY, 2,        0,            snapshot          },
-                { "delete",                2,        VERB_ANY, 0,            delete_snapshot   },
                 { "daemon-reload",         VERB_ANY, 1,        0,            daemon_reload     },
                 { "daemon-reexec",         VERB_ANY, 1,        0,            daemon_reload     },
                 { "show-environment",      VERB_ANY, 1,        0,            show_environment  },
@@ -7778,8 +7702,11 @@ finish:
         strv_free(arg_properties);
 
         strv_free(arg_wall);
+        free(arg_root);
 
         release_busses();
 
+        /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
+
         return r < 0 ? EXIT_FAILURE : r;
 }
index 38cb2a1102800d58dcf458cd91b97a90b833b428..fc117258213499350c0ebcce6d3888c980e3ef17 100644 (file)
@@ -24,7 +24,7 @@
 ***/
 
 #include <sys/types.h>
-#include <stdint.h>
+#include <inttypes.h>
 
 #include "_sd-common.h"
 
index 4291fb7ebcb6b82ef1bc52ab0a12b15faf673b93..c0146158f3798fa1909652993bfb57d3466232d7 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <netinet/in.h>
+#include <inttypes.h>
 #include <net/ethernet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
 
 #include "sd-event.h"
 #include "sd-dhcp-lease.h"
 
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
 enum {
         SD_DHCP_CLIENT_EVENT_STOP               = 0,
         SD_DHCP_CLIENT_EVENT_IP_ACQUIRE         = 1,
@@ -72,4 +78,6 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri
 int sd_dhcp_client_detach_event(sd_dhcp_client *client);
 sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
 
+_SD_END_DECLARATIONS;
+
 #endif
index ed5bceecdd8b9c7ccab681e83907d724bdbe17f4..38222594e7bd90d18eede4e6d3e7588e5bd6b079 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <netinet/in.h>
+#include <inttypes.h>
 #include <net/ethernet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_dhcp_lease sd_dhcp_lease;
 struct sd_dhcp_route;
@@ -52,4 +58,6 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s
 int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
 int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
 
+_SD_END_DECLARATIONS;
+
 #endif
index 4b0c7a18526804e7c9f622abb7f7699f66ebc0c1..55bceb1ea59a8d57ee957f89fa1c92fe2b8a383e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
+#include <inttypes.h>
 #include <netinet/in.h>
 
 #include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
 
 typedef struct sd_dhcp_server sd_dhcp_server;
 
@@ -39,7 +42,7 @@ int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int pri
 int sd_dhcp_server_detach_event(sd_dhcp_server *client);
 sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
 
-bool sd_dhcp_server_is_running(sd_dhcp_server *server);
+int sd_dhcp_server_is_running(sd_dhcp_server *server);
 
 int sd_dhcp_server_start(sd_dhcp_server *server);
 int sd_dhcp_server_stop(sd_dhcp_server *server);
@@ -55,4 +58,6 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
 
 int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
 
+_SD_END_DECLARATIONS;
+
 #endif
index 90c35ef3f6aef593d11020dcabfdd9d5ebfa1036..9f0e92806e7171f6705154f4a072f96921141b84 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <inttypes.h>
 #include <net/ethernet.h>
+#include <sys/types.h>
 
 #include "sd-event.h"
-
 #include "sd-dhcp6-lease.h"
 
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
 enum {
         SD_DHCP6_CLIENT_EVENT_STOP                      = 0,
         SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE             = 10,
@@ -48,10 +53,8 @@ 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_information_request(sd_dhcp6_client *client,
-                                            bool enabled);
-int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
-                                            bool *enabled);
+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,
                                        uint16_t option);
 
@@ -59,6 +62,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
 
 int sd_dhcp6_client_stop(sd_dhcp6_client *client);
 int sd_dhcp6_client_start(sd_dhcp6_client *client);
+int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
 int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
                                  int priority);
 int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
@@ -67,4 +71,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
 sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
 int sd_dhcp6_client_new(sd_dhcp6_client **ret);
 
+_SD_END_DECLARATIONS;
+
 #endif
index dc3df3bbf7b803ae30fa1a427972ac882bd3dccb..3fc0ee4bed3719617634d6e4eabe2166ff2ffeb8 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <inttypes.h>
 #include <netinet/in.h>
 
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
 typedef struct sd_dhcp6_lease sd_dhcp6_lease;
 
 void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
@@ -42,4 +47,6 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
 sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
 sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
 
+_SD_END_DECLARATIONS;
+
 #endif
index 3c44b981d68030700161c74ba13748d59bae25fa..49269a073ae1ffa27115b95e3c4a7e3215be89a0 100644 (file)
@@ -39,9 +39,11 @@ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char
 int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias);
 int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value);
 
-/* the inverse condition avoids ambiguity of danling 'else' after the macro */
+/* the inverse condition avoids ambiguity of dangling 'else' after the macro */
 #define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value)            \
         if (sd_hwdb_seek(hwdb, modalias) < 0) { }                       \
         else while (sd_hwdb_enumerate(hwdb, &(key), &(value)) > 0)
 
+_SD_END_DECLARATIONS;
+
 #endif
diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h
deleted file mode 100644 (file)
index cb6c24a..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdicmp6ndfoo
-#define foosdicmp6ndfoo
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Intel Corporation. All rights reserved.
-
-  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 <net/ethernet.h>
-
-#include "sd-event.h"
-
-enum {
-        SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE              = 0,
-        SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT           = 1,
-        SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER             = 2,
-        SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED           = 3,
-        SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED    = 4,
-};
-
-typedef struct sd_icmp6_nd sd_icmp6_nd;
-
-typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event,
-                                      void *userdata);
-
-int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb,
-                             void *userdata);
-int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index);
-int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr);
-
-int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority);
-int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd);
-sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd);
-
-sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd);
-sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd);
-int sd_icmp6_nd_new(sd_icmp6_nd **ret);
-
-int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
-                        struct in6_addr *addr);
-
-int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu);
-int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
-                        uint8_t *prefixlen);
-int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr,
-                                uint8_t *prefixlen);
-
-int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
-int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
-
-#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-
-#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \
-        be16toh((address).s6_addr16[0]),        \
-        be16toh((address).s6_addr16[1]),        \
-        be16toh((address).s6_addr16[2]),        \
-        be16toh((address).s6_addr16[3]),        \
-        be16toh((address).s6_addr16[4]),        \
-        be16toh((address).s6_addr16[5]),        \
-        be16toh((address).s6_addr16[6]),        \
-        be16toh((address).s6_addr16[7])
-
-#endif
index adcb2c7b920144f2d7abe51bd3a5577fa9f8652e..6337d614525046d624736e0c4e2ae5421d75bc8a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
 #include <netinet/in.h>
 #include <net/ethernet.h>
 
 #include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
 
 enum {
         SD_IPV4ACD_EVENT_STOP           = 0,
@@ -45,11 +47,13 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
 int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
 int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
 int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
-bool sd_ipv4acd_is_running(sd_ipv4acd *ll);
+int sd_ipv4acd_is_running(sd_ipv4acd *ll);
 int sd_ipv4acd_start(sd_ipv4acd *ll);
 int sd_ipv4acd_stop(sd_ipv4acd *ll);
 sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
 sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
 int sd_ipv4acd_new (sd_ipv4acd **ret);
 
+_SD_END_DECLARATIONS;
+
 #endif
index 677505f0c6a06d38cba36f4c930725c2d8bc1b83..2949f1dfb284de3ce7ba61ac10f11d2cb7a1cdf1 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdbool.h>
 #include <netinet/in.h>
 #include <net/ethernet.h>
 
 #include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
 
 enum {
         SD_IPV4LL_EVENT_STOP            = 0,
@@ -43,12 +45,15 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
 int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
 int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
 int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
 int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
+int sd_ipv4ll_is_running(sd_ipv4ll *ll);
 int sd_ipv4ll_start(sd_ipv4ll *ll);
 int sd_ipv4ll_stop(sd_ipv4ll *ll);
 sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
 sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
 int sd_ipv4ll_new (sd_ipv4ll **ret);
 
+_SD_END_DECLARATIONS;
+
 #endif
index 30d9dedf2c5c22d5088ee50885e116136807a15d..31651ce132f2af0c7dcb77b70ed0a62eea119551 100644 (file)
@@ -1,5 +1,8 @@
 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
+#ifndef foosdlldphfoo
+#define foosdlldphfoo
+
 /***
   This file is part of systemd.
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#pragma once
+#include <net/ethernet.h>
+#include <inttypes.h>
 
 #include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
 
 enum {
         SD_LLDP_EVENT_UPDATE_INFO       = 0,
@@ -72,3 +79,7 @@ sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
 int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
 
 int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
new file mode 100644 (file)
index 0000000..80e2432
--- /dev/null
@@ -0,0 +1,83 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdndiscfoo
+#define foosdndiscfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+  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 <inttypes.h>
+#include <net/ethernet.h>
+
+#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+enum {
+        SD_NDISC_EVENT_STOP     = 0,
+        SD_NDISC_EVENT_TIMEOUT  = 1,
+};
+
+typedef struct sd_ndisc sd_ndisc;
+
+typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata);
+typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
+                                                 unsigned lifetime, void *userdata);
+typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen,
+                                                     unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata);
+typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata);
+
+int sd_ndisc_set_callback(sd_ndisc *nd,
+                          sd_ndisc_router_callback_t rcb,
+                          sd_ndisc_prefix_onlink_callback_t plcb,
+                          sd_ndisc_prefix_autonomous_callback_t pacb,
+                          sd_ndisc_callback_t cb,
+                          void *userdata);
+int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
+int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
+
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
+int sd_ndisc_detach_event(sd_ndisc *nd);
+sd_event *sd_ndisc_get_event(sd_ndisc *nd);
+
+sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
+sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
+int sd_ndisc_new(sd_ndisc **ret);
+
+int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu);
+
+int sd_ndisc_stop(sd_ndisc *nd);
+int sd_ndisc_router_discovery_start(sd_ndisc *nd);
+
+#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+
+#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \
+        be16toh((address).s6_addr16[0]),        \
+        be16toh((address).s6_addr16[1]),        \
+        be16toh((address).s6_addr16[2]),        \
+        be16toh((address).s6_addr16[3]),        \
+        be16toh((address).s6_addr16[4]),        \
+        be16toh((address).s6_addr16[5]),        \
+        be16toh((address).s6_addr16[6]),        \
+        be16toh((address).s6_addr16[7])
+
+_SD_END_DECLARATIONS;
+
+#endif
index e09b8c8e2d51d1aa65e76958f37b827f2801c9fc..2960deda0a4a8b107644b057ac241a129aab0a1a 100644 (file)
@@ -136,7 +136,13 @@ int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type);
 int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
 int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
 int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
+int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags);
+int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags);
 int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
 int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
 int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
 
index e238c0ce2039ccd1a98ec0a821f919d6ce28b550..32803036332fd83f5b844f3a04f81182cd081203 100644 (file)
 
 #include <inttypes.h>
 
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
 enum {
         /* Temporary files */
         SD_PATH_TEMPORARY = 0x0ULL,
@@ -84,4 +88,6 @@ enum {
 int sd_path_home(uint64_t type, const char *suffix, char **path);
 int sd_path_search(uint64_t type, const char *suffix, char ***paths);
 
+_SD_END_DECLARATIONS;
+
 #endif
diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h
deleted file mode 100644 (file)
index 90878ff..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdpppoefoo
-#define foosdpppoefoo
-
-/***
-  This file is part of systemd.
-
-  Copyright (C) 2014 Tom Gundersen
-
-  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 <stdbool.h>
-#include <net/ethernet.h>
-
-#include "sd-event.h"
-
-#include "sparse-endian.h"
-
-enum {
-        SD_PPPOE_EVENT_RUNNING          = 0,
-        SD_PPPOE_EVENT_STOPPED          = 1,
-};
-
-typedef struct sd_pppoe sd_pppoe;
-typedef void (*sd_pppoe_cb_t)(sd_pppoe *ppp, int event, void *userdata);
-
-int sd_pppoe_detach_event(sd_pppoe *ppp);
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority);
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel);
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata);
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex);
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname);
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name);
-int sd_pppoe_start(sd_pppoe *ppp);
-int sd_pppoe_stop(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp);
-int sd_pppoe_new (sd_pppoe **ret);
-
-#endif
index 80c5852e455dde8fb8bb280f0487a4af31f9621a..82c4b39efe1ab3434b5143f9955737f075456772 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/types.h>
-#include <sys/socket.h>
+#include <inttypes.h>
 #include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
 
-#include "_sd-common.h"
 #include "sd-event.h"
+#include "_sd-common.h"
 
 _SD_BEGIN_DECLARATIONS;
 
index ba09727080ac8cd0e873c67888af6c378dff4e6c..675f94906b2dd89eae7e22ae82ada54ff972fe00 100644 (file)
 #include <shadow.h>
 #include <utmp.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
 #include "copy.h"
+#include "def.h"
+#include "fd-util.h"
 #include "fileio-label.h"
 #include "formats-util.h"
 #include "hashmap.h"
 #include "path-util.h"
 #include "selinux-util.h"
+#include "smack-util.h"
 #include "specifier.h"
+#include "string-util.h"
 #include "strv.h"
 #include "uid-range.h"
+#include "user-util.h"
 #include "utf8.h"
 #include "util.h"
-#include "smack-util.h"
 
 typedef enum ItemType {
         ADD_USER = 'u',
@@ -67,7 +72,7 @@ typedef struct Item {
 
 static char *arg_root = NULL;
 
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d");
 
 static Hashmap *users = NULL, *groups = NULL;
 static Hashmap *todo_uids = NULL, *todo_gids = NULL;
@@ -938,7 +943,7 @@ static int add_user(Item *i) {
                 }
         }
 
-        /* Otherwise try to reuse the group ID */
+        /* Otherwise, try to reuse the group ID */
         if (!i->uid_set && i->gid_set) {
                 r = uid_is_ok((uid_t) i->gid, i->name);
                 if (r < 0)
@@ -1762,7 +1767,7 @@ static int parse_argv(int argc, char *argv[]) {
                 {}
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
@@ -1779,12 +1784,9 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case ARG_ROOT:
-                        free(arg_root);
-                        arg_root = path_make_absolute_cwd(optarg);
-                        if (!arg_root)
-                                return log_oom();
-
-                        path_kill_slashes(arg_root);
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case '?':
@@ -1859,7 +1861,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        lock = take_password_lock(arg_root);
+        lock = take_etc_passwd_lock(arg_root);
         if (lock < 0) {
                 log_error_errno(lock, "Failed to take lock: %m");
                 goto finish;
index 964750076add59afc06b3ace8d310726b03105f8..50755485070021a4b5bc0392ffc4b61d2f2a7c02 100644 (file)
 #include <stdio.h>
 #include <unistd.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "hexdecoct.h"
+#include "install.h"
+#include "log.h"
 #include "mkdir.h"
-#include "strv.h"
-#include "path-util.h"
 #include "path-lookup.h"
-#include "log.h"
-#include "unit-name.h"
-#include "special.h"
-#include "hashmap.h"
+#include "path-util.h"
 #include "set.h"
-#include "install.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "util.h"
 
 typedef enum RunlevelType {
         RUNLEVEL_UP,
@@ -80,9 +87,13 @@ typedef struct SysvStub {
         char **conflicts;
         bool has_lsb;
         bool reload;
+        bool loaded;
 } SysvStub;
 
 static void free_sysvstub(SysvStub *s) {
+        if (!s)
+                return;
+
         free(s->name);
         free(s->path);
         free(s->description);
@@ -107,19 +118,14 @@ static void free_sysvstub_hashmapp(Hashmap **h) {
 }
 
 static int add_symlink(const char *service, const char *where) {
-        _cleanup_free_ char *from = NULL, *to = NULL;
+        const char *from, *to;
         int r;
 
         assert(service);
         assert(where);
 
-        from = strjoin(arg_dest, "/", service, NULL);
-        if (!from)
-                return log_oom();
-
-        to = strjoin(arg_dest, "/", where, ".wants/", service, NULL);
-        if (!to)
-                return log_oom();
+        from = strjoina(arg_dest, "/", service);
+        to = strjoina(arg_dest, "/", where, ".wants/", service);
 
         mkdir_parents_label(to, 0755);
 
@@ -127,6 +133,7 @@ static int add_symlink(const char *service, const char *where) {
         if (r < 0) {
                 if (errno == EEXIST)
                         return 0;
+
                 return -errno;
         }
 
@@ -134,20 +141,19 @@ static int add_symlink(const char *service, const char *where) {
 }
 
 static int add_alias(const char *service, const char *alias) {
-        _cleanup_free_ char *link = NULL;
+        const char *link;
         int r;
 
         assert(service);
         assert(alias);
 
-        link = strjoin(arg_dest, "/", alias, NULL);
-        if (!link)
-                return log_oom();
+        link = strjoina(arg_dest, "/", alias);
 
         r = symlink(service, link);
         if (r < 0) {
                 if (errno == EEXIST)
                         return 0;
+
                 return -errno;
         }
 
@@ -155,26 +161,32 @@ static int add_alias(const char *service, const char *alias) {
 }
 
 static int generate_unit_file(SysvStub *s) {
-        char **p;
+        _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        _cleanup_free_ char *unit = NULL,
-                *before = NULL, *after = NULL,
-                *wants = NULL, *conflicts = NULL;
+        const char *unit;
+        char **p;
         int r;
 
+        assert(s);
+
+        if (!s->loaded)
+                return 0;
+
+        unit = strjoina(arg_dest, "/", s->name);
+
         before = strv_join(s->before, " ");
         after = strv_join(s->after, " ");
         wants = strv_join(s->wants, " ");
         conflicts = strv_join(s->conflicts, " ");
-        unit = strjoin(arg_dest, "/", s->name, NULL);
-        if (!before || !after || !wants || !conflicts || !unit)
+
+        if (!before || !after || !wants || !conflicts)
                 return log_oom();
 
         /* We might already have a symlink with the same name from a Provides:,
          * or from backup files like /etc/init.d/foo.bak. Real scripts always win,
          * so remove an existing link */
         if (is_symlink(unit) > 0) {
-                log_warning("Overwriting existing symlink %s with real service", unit);
+                log_warning("Overwriting existing symlink %s with real service.", unit);
                 (void) unlink(unit);
         }
 
@@ -186,9 +198,11 @@ static int generate_unit_file(SysvStub *s) {
                 "# Automatically generated by systemd-sysv-generator\n\n"
                 "[Unit]\n"
                 "Documentation=man:systemd-sysv-generator(8)\n"
-                "SourcePath=%s\n"
-                "Description=%s\n",
-                s->path, s->description);
+                "SourcePath=%s\n",
+                s->path);
+
+        if (s->description)
+                fprintf(f, "Description=%s\n", s->description);
 
         if (!isempty(before))
                 fprintf(f, "Before=%s\n", before);
@@ -221,13 +235,17 @@ static int generate_unit_file(SysvStub *s) {
         if (s->reload)
                 fprintf(f, "ExecReload=%s reload\n", s->path);
 
+        r = fflush_and_check(f);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write unit %s: %m", unit);
+
         STRV_FOREACH(p, s->wanted_by) {
                 r = add_symlink(s->name, *p);
                 if (r < 0)
-                        log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p);
+                        log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
         }
 
-        return 0;
+        return 1;
 }
 
 static bool usage_contains_reload(const char *line) {
@@ -257,7 +275,7 @@ static char *sysv_translate_name(const char *name) {
         return res;
 }
 
-static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
+static int sysv_translate_facility(const char *name, const char *filename, char **ret) {
 
         /* We silently ignore the $ prefix here. According to the LSB
          * spec it simply indicates whether something is a
@@ -276,31 +294,45 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 "time",                 SPECIAL_TIME_SYNC_TARGET,
         };
 
-        char *filename_no_sh, *e, *r;
+        char *filename_no_sh, *e, *m;
         const char *n;
         unsigned i;
+        int r;
 
         assert(name);
-        assert(_r);
+        assert(filename);
+        assert(ret);
 
         n = *name == '$' ? name + 1 : name;
 
         for (i = 0; i < ELEMENTSOF(table); i += 2) {
-
                 if (!streq(table[i], n))
                         continue;
 
                 if (!table[i+1])
                         return 0;
 
-                r = strdup(table[i+1]);
-                if (!r)
+                m = strdup(table[i+1]);
+                if (!m)
                         return log_oom();
 
-                goto finish;
+                *ret = m;
+                return 1;
+        }
+
+        /* If we don't know this name, fallback heuristics to figure
+         * out whether something is a target or a service alias. */
+
+        /* Facilities starting with $ are most likely targets */
+        if (*name == '$')  {
+                r = unit_name_build(n, NULL, ".target", ret);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to build name: %m");
+
+                return r;
         }
 
-        /* strip ".sh" suffix from file name for comparison */
+        /* Strip ".sh" suffix from file name for comparison */
         filename_no_sh = strdupa(filename);
         e = endswith(filename_no_sh, ".sh");
         if (e) {
@@ -308,103 +340,103 @@ static int sysv_translate_facility(const char *name, const char *filename, char
                 filename = filename_no_sh;
         }
 
-        /* If we don't know this name, fallback heuristics to figure
-         * out whether something is a target or a service alias. */
-
-        if (*name == '$') {
-                int k;
-
-                /* Facilities starting with $ are most likely targets */
-                k = unit_name_build(n, NULL, ".target", &r);
-                if (k < 0)
-                        return k;
-
-        } else if (streq_ptr(n, filename))
-                /* Names equaling the file name of the services are redundant */
+        /* Names equaling the file name of the services are redundant */
+        if (streq_ptr(n, filename))
                 return 0;
-        else
-                /* Everything else we assume to be normal service names */
-                r = sysv_translate_name(n);
-        if (!r)
-                return -ENOMEM;
 
-finish:
-        *_r = r;
+        /* Everything else we assume to be normal service names */
+        m = sysv_translate_name(n);
+        if (!m)
+                return log_oom();
 
+        *ret = m;
         return 1;
 }
 
 static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) {
-        const char *word, *state_;
-        size_t z;
         int r;
 
-        FOREACH_WORD_QUOTED(word, z, text, state_) {
-                _cleanup_free_ char *n = NULL, *m = NULL;
-                UnitType t;
+        assert(s);
+        assert(full_text);
+        assert(text);
 
-                n = strndup(word, z);
-                if (!n)
-                        return log_oom();
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *m = NULL;
 
-                r = sysv_translate_facility(n, basename(s->path), &m);
+                r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
                 if (r < 0)
-                        return r;
+                        return log_error_errno(r, "Failed to parse word from provides string: %m");
                 if (r == 0)
+                        break;
+
+                r = sysv_translate_facility(word, basename(s->path), &m);
+                if (r <= 0) /* continue on error */
                         continue;
 
-                t = unit_name_to_type(m);
-                if (t == UNIT_SERVICE) {
+                switch (unit_name_to_type(m)) {
+
+                case UNIT_SERVICE:
                         log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
                         r = add_alias(s->name, m);
                         if (r < 0)
                                 log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m);
-                } else if (t == UNIT_TARGET) {
+                        break;
+
+                case UNIT_TARGET:
+
                         /* NB: SysV targets which are provided by a
                          * service are pulled in by the services, as
                          * an indication that the generic service is
                          * now available. This is strictly one-way.
                          * The targets do NOT pull in SysV services! */
+
                         r = strv_extend(&s->before, m);
                         if (r < 0)
                                 return log_oom();
+
                         r = strv_extend(&s->wants, m);
                         if (r < 0)
                                 return log_oom();
+
                         if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) {
                                 r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
                                 if (r < 0)
                                         return log_oom();
                         }
-                } else if (t == _UNIT_TYPE_INVALID)
+
+                        break;
+
+                case _UNIT_TYPE_INVALID:
                         log_warning("Unit name '%s' is invalid", m);
-                else
+                        break;
+
+                default:
                         log_warning("Unknown unit type for unit '%s'", m);
+                }
         }
-        if (!isempty(state_))
-                log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line);
+
         return 0;
 }
 
 static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) {
-        const char *word, *state_;
-        size_t z;
         int r;
 
-        FOREACH_WORD_QUOTED(word, z, text, state_) {
-                _cleanup_free_ char *n = NULL, *m = NULL;
-                bool is_before;
+        assert(s);
+        assert(full_text);
+        assert(text);
 
-                n = strndup(word, z);
-                if (!n)
-                        return log_oom();
+        for (;;) {
+                _cleanup_free_ char *word = NULL, *m = NULL;
+                bool is_before;
 
-                r = sysv_translate_facility(n, basename(s->path), &m);
-                if (r < 0) {
-                        log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n);
-                        continue;
-                }
+                r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse word from provides string: %m");
                 if (r == 0)
+                        break;
+
+                r = sysv_translate_facility(word, basename(s->path), &m);
+                if (r <= 0) /* continue on error */
                         continue;
 
                 is_before = startswith_no_case(full_text, "X-Start-Before:");
@@ -414,15 +446,14 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text
                         r = strv_extend(&s->after, m);
                         if (r < 0)
                                 return log_oom();
+
                         r = strv_extend(&s->wants, m);
                 } else
                         r = strv_extend(is_before ? &s->before : &s->after, m);
-
                 if (r < 0)
                         return log_oom();
         }
-        if (!isempty(state_))
-                log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text);
+
         return 0;
 }
 
@@ -440,24 +471,22 @@ static int load_sysv(SysvStub *s) {
         _cleanup_free_ char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL;
         char *description;
         bool supports_reload = false;
+        char l[LINE_MAX];
 
         assert(s);
 
         f = fopen(s->path, "re");
-        if (!f)
-                return errno == ENOENT ? 0 : -errno;
-
-        log_debug("Loading SysV script %s", s->path);
+        if (!f) {
+                if (errno == ENOENT)
+                        return 0;
 
-        while (!feof(f)) {
-                char l[LINE_MAX], *t;
+                return log_error_errno(errno, "Failed to open %s: %m", s->path);
+        }
 
-                if (!fgets(l, sizeof(l), f)) {
-                        if (feof(f))
-                                break;
+        log_debug("Loading SysV script %s", s->path);
 
-                        return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
-                }
+        FOREACH_LINE(l, f, goto fail) {
+                char *t;
 
                 line++;
 
@@ -500,29 +529,25 @@ static int load_sysv(SysvStub *s) {
 
                         if (startswith_no_case(t, "description:")) {
 
-                                size_t k = strlen(t);
-                                char *d;
+                                size_t k;
                                 const char *j;
 
-                                if (t[k-1] == '\\') {
+                                k = strlen(t);
+                                if (k > 0 && t[k-1] == '\\') {
                                         state = DESCRIPTION;
                                         t[k-1] = 0;
                                 }
 
                                 j = strstrip(t+12);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(chkconfig_description);
-                                chkconfig_description = d;
+                                r = free_and_strdup(&chkconfig_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (startswith_no_case(t, "pidfile:")) {
-
-                                char *fn;
+                                const char *fn;
 
                                 state = NORMAL;
 
@@ -532,12 +557,9 @@ static int load_sysv(SysvStub *s) {
                                         continue;
                                 }
 
-                                fn = strdup(fn);
-                                if (!fn)
-                                        return -ENOMEM;
-
-                                free(s->pid_file);
-                                s->pid_file = fn;
+                                r = free_and_strdup(&s->pid_file, fn);
+                                if (r < 0)
+                                        return log_oom();
                         }
 
                 } else if (state == DESCRIPTION) {
@@ -545,25 +567,25 @@ static int load_sysv(SysvStub *s) {
                         /* Try to parse Red Hat style description
                          * continuation */
 
-                        size_t k = strlen(t);
+                        size_t k;
                         char *j;
 
-                        if (t[k-1] == '\\')
+                        k = strlen(t);
+                        if (k > 0 && t[k-1] == '\\')
                                 t[k-1] = 0;
                         else
                                 state = NORMAL;
 
                         j = strstrip(t);
-                        if (j && *j) {
+                        if (!isempty(j)) {
                                 char *d = NULL;
 
                                 if (chkconfig_description)
                                         d = strjoin(chkconfig_description, " ", j, NULL);
                                 else
                                         d = strdup(j);
-
                                 if (!d)
-                                        return -ENOMEM;
+                                        return log_oom();
 
                                 free(chkconfig_description);
                                 chkconfig_description = d;
@@ -577,6 +599,7 @@ static int load_sysv(SysvStub *s) {
                                 r = handle_provides(s, line, t, t + 9);
                                 if (r < 0)
                                         return r;
+
                         } else if (startswith_no_case(t, "Required-Start:") ||
                                    startswith_no_case(t, "Should-Start:") ||
                                    startswith_no_case(t, "X-Start-Before:") ||
@@ -588,55 +611,47 @@ static int load_sysv(SysvStub *s) {
                                 if (r < 0)
                                         return r;
 
-
                         } else if (startswith_no_case(t, "Description:")) {
-                                char *d, *j;
+                                const char *j;
 
                                 state = LSB_DESCRIPTION;
 
                                 j = strstrip(t+12);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(long_description);
-                                long_description = d;
+                                r = free_and_strdup(&long_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (startswith_no_case(t, "Short-Description:")) {
-                                char *d, *j;
+                                const char *j;
 
                                 state = LSB;
 
                                 j = strstrip(t+18);
-                                if (j && *j) {
-                                        d = strdup(j);
-                                        if (!d)
-                                                return -ENOMEM;
-                                } else
-                                        d = NULL;
+                                if (isempty(j))
+                                        j = NULL;
 
-                                free(short_description);
-                                short_description = d;
+                                r = free_and_strdup(&short_description, j);
+                                if (r < 0)
+                                        return log_oom();
 
                         } else if (state == LSB_DESCRIPTION) {
 
                                 if (startswith(l, "#\t") || startswith(l, "#  ")) {
-                                        char *j;
+                                        const char *j;
 
                                         j = strstrip(t);
-                                        if (j && *j) {
+                                        if (!isempty(j)) {
                                                 char *d = NULL;
 
                                                 if (long_description)
                                                         d = strjoin(long_description, " ", t, NULL);
                                                 else
                                                         d = strdup(j);
-
                                                 if (!d)
-                                                        return -ENOMEM;
+                                                        return log_oom();
 
                                                 free(long_description);
                                                 long_description = d;
@@ -667,12 +682,16 @@ static int load_sysv(SysvStub *s) {
 
                 d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description);
                 if (!d)
-                        return -ENOMEM;
+                        return log_oom();
 
                 s->description = d;
         }
 
+        s->loaded = true;
         return 0;
+
+fail:
+        return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
 }
 
 static int fix_order(SysvStub *s, Hashmap *all_services) {
@@ -682,6 +701,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
 
         assert(s);
 
+        if (!s->loaded)
+                return 0;
+
         if (s->sysv_start_priority < 0)
                 return 0;
 
@@ -689,6 +711,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
                 if (s == other)
                         continue;
 
+                if (!other->loaded)
+                        continue;
+
                 if (other->sysv_start_priority < 0)
                         continue;
 
@@ -701,13 +726,12 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
                         r = strv_extend(&s->after, other->name);
                         if (r < 0)
                                 return log_oom();
-                }
-                else if (other->sysv_start_priority > s->sysv_start_priority) {
+
+                else if (other->sysv_start_priority > s->sysv_start_priority) {
                         r = strv_extend(&s->before, other->name);
                         if (r < 0)
                                 return log_oom();
-                }
-                else
+                } else
                         continue;
 
                 /* FIXME: Maybe we should compare the name here lexicographically? */
@@ -718,6 +742,10 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
 
 static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
         char **path;
+        int r;
+
+        assert(lp);
+        assert(all_services);
 
         STRV_FOREACH(path, lp->sysvinit_path) {
                 _cleanup_closedir_ DIR *d = NULL;
@@ -726,21 +754,17 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                 d = opendir(*path);
                 if (!d) {
                         if (errno != ENOENT)
-                                log_warning_errno(errno, "opendir(%s) failed: %m", *path);
+                                log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path);
                         continue;
                 }
 
-                while ((de = readdir(d))) {
+                FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) {
                         _cleanup_free_ char *fpath = NULL, *name = NULL;
                         _cleanup_(free_sysvstubp) SysvStub *service = NULL;
                         struct stat st;
-                        int r;
-
-                        if (hidden_file(de->d_name))
-                                continue;
 
                         if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
-                                log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
+                                log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name);
                                 continue;
                         }
 
@@ -757,15 +781,19 @@ 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) {
+                                log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
+                                continue;
+                        } else if (r >= 0) {
+                                log_debug("Native unit for %s already exists, skipping.", name);
+                                continue;
+                        }
+
                         fpath = strjoin(*path, "/", de->d_name, NULL);
                         if (!fpath)
                                 return log_oom();
 
-                        if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) {
-                                log_debug("Native unit for %s already exists, skipping", name);
-                                continue;
-                        }
-
                         service = new0(SysvStub, 1);
                         if (!service)
                                 return log_oom();
@@ -773,12 +801,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
                         service->sysv_start_priority = -1;
                         service->name = name;
                         service->path = fpath;
+                        name = fpath = NULL;
 
                         r = hashmap_put(all_services, service->name, service);
                         if (r < 0)
                                 return log_oom();
 
-                        name = fpath = NULL;
                         service = NULL;
                 }
         }
@@ -787,43 +815,41 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
 }
 
 static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
-        char **p;
-        unsigned i;
-        _cleanup_closedir_ DIR *d = NULL;
-        _cleanup_free_ char *path = NULL, *fpath = NULL;
-        SysvStub *service;
-        Iterator j;
         Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
         _cleanup_set_free_ Set *shutdown_services = NULL;
-        int r = 0;
+        SysvStub *service;
+        unsigned i;
+        Iterator j;
+        char **p;
+        int r;
+
+        assert(lp);
 
-        STRV_FOREACH(p, lp->sysvrcnd_path)
+        STRV_FOREACH(p, lp->sysvrcnd_path) {
                 for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
+
+                        _cleanup_closedir_ DIR *d = NULL;
+                        _cleanup_free_ char *path = NULL;
                         struct dirent *de;
 
-                        free(path);
                         path = strjoin(*p, "/", rcnd_table[i].path, NULL);
-                        if (!path)
-                                return -ENOMEM;
-
-                        safe_closedir(d);
+                        if (!path) {
+                                r = log_oom();
+                                goto finish;
+                        }
 
                         d = opendir(path);
                         if (!d) {
                                 if (errno != ENOENT)
-                                        log_warning_errno(errno, "opendir(%s) failed: %m", path);
+                                        log_warning_errno(errno, "Opening %s failed, ignoring: %m", path);
 
                                 continue;
                         }
 
-                        while ((de = readdir(d))) {
-                                _cleanup_free_ char *name = NULL;
-
+                        FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path)) {
+                                _cleanup_free_ char *name = NULL, *fpath = NULL;
                                 int a, b;
 
-                                if (hidden_file(de->d_name))
-                                        continue;
-
                                 if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
                                         continue;
 
@@ -836,10 +862,9 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
                                 if (a < 0 || b < 0)
                                         continue;
 
-                                free(fpath);
                                 fpath = strjoin(*p, "/", de->d_name, NULL);
                                 if (!fpath) {
-                                        r = -ENOMEM;
+                                        r = log_oom();
                                         goto finish;
                                 }
 
@@ -851,64 +876,77 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
 
                                 service = hashmap_get(all_services, name);
                                 if (!service){
-                                        log_debug("Ignoring %s symlink in %s, not generating %s.",
-                                                  de->d_name, rcnd_table[i].path, name);
+                                        log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name);
                                         continue;
                                 }
 
                                 if (de->d_name[0] == 'S')  {
 
-                                        if (rcnd_table[i].type == RUNLEVEL_UP) {
-                                                service->sysv_start_priority =
-                                                        MAX(a*10 + b, service->sysv_start_priority);
-                                        }
+                                        if (rcnd_table[i].type == RUNLEVEL_UP)
+                                                service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
 
                                         r = set_ensure_allocated(&runlevel_services[i], NULL);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                         r = set_put(runlevel_services[i], service);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                 } else if (de->d_name[0] == 'K' &&
                                            (rcnd_table[i].type == RUNLEVEL_DOWN)) {
 
                                         r = set_ensure_allocated(&shutdown_services, NULL);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
 
                                         r = set_put(shutdown_services, service);
-                                        if (r < 0)
+                                        if (r < 0) {
+                                                log_oom();
                                                 goto finish;
+                                        }
                                 }
                         }
                 }
+        }
 
 
         for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
                 SET_FOREACH(service, runlevel_services[i], j) {
                         r = strv_extend(&service->before, rcnd_table[i].target);
-                        if (r < 0)
-                                return log_oom();
+                        if (r < 0) {
+                                log_oom();
+                                goto finish;
+                        }
                         r = strv_extend(&service->wanted_by, rcnd_table[i].target);
-                        if (r < 0)
-                                return log_oom();
+                        if (r < 0) {
+                                log_oom();
+                                goto finish;
+                        }
                 }
 
         SET_FOREACH(service, shutdown_services, j) {
                 r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET);
-                if (r < 0)
-                        return log_oom();
+                if (r < 0) {
+                        log_oom();
+                        goto finish;
+                }
                 r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET);
-                if (r < 0)
-                        return log_oom();
+                if (r < 0) {
+                        log_oom();
+                        goto finish;
+                }
         }
 
         r = 0;
 
 finish:
-
         for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
                 set_free(runlevel_services[i]);
 
@@ -916,11 +954,11 @@ finish:
 }
 
 int main(int argc, char *argv[]) {
-        int r, q;
-        _cleanup_lookup_paths_free_ LookupPaths lp = {};
         _cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
+        _cleanup_lookup_paths_free_ LookupPaths lp = {};
         SysvStub *service;
         Iterator j;
+        int r;
 
         if (argc > 1 && argc != 4) {
                 log_error("This program takes three or no arguments.");
@@ -938,43 +976,34 @@ int main(int argc, char *argv[]) {
 
         r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
         if (r < 0) {
-                log_error("Failed to find lookup paths.");
-                return EXIT_FAILURE;
+                log_error_errno(r, "Failed to find lookup paths: %m");
+                goto finish;
         }
 
         all_services = hashmap_new(&string_hash_ops);
         if (!all_services) {
-                log_oom();
-                return EXIT_FAILURE;
+                r = log_oom();
+                goto finish;
         }
 
         r = enumerate_sysv(&lp, all_services);
-        if (r < 0) {
-                log_error("Failed to generate units for all init scripts.");
-                return EXIT_FAILURE;
-        }
+        if (r < 0)
+                goto finish;
 
         r = set_dependencies_from_rcnd(&lp, all_services);
-        if (r < 0) {
-                log_error("Failed to read runlevels from rcnd links.");
-                return EXIT_FAILURE;
-        }
+        if (r < 0)
+                goto finish;
 
-        HASHMAP_FOREACH(service, all_services, j) {
-                q = load_sysv(service);
-                if (q < 0)
-                        continue;
-        }
+        HASHMAP_FOREACH(service, all_services, j)
+                (void) load_sysv(service);
 
         HASHMAP_FOREACH(service, all_services, j) {
-                q = fix_order(service, all_services);
-                if (q < 0)
-                        continue;
-
-                q = generate_unit_file(service);
-                if (q < 0)
-                        continue;
+                (void) fix_order(service, all_services);
+                (void) generate_unit_file(service);
         }
 
-        return EXIT_SUCCESS;
+        r = 0;
+
+finish:
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index d69104f54009d573e97df12dfa5e48f01c31e2c1..aeaa0929b16648b7abc1e5e8044cd8581890e8ba 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/socket.h>
 #include <string.h>
+#include <sys/socket.h>
 
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
 
 static const struct af_name* lookup_af(register const char *str, register unsigned int len);
 
+#include "af-from-name.h"
 #include "af-list.h"
 #include "af-to-name.h"
-#include "af-from-name.h"
 
 int main(int argc, const char *argv[]) {
 
@@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) {
         assert_se(af_from_name("huddlduddl") == AF_UNSPEC);
 
         return 0;
-}
\ No newline at end of file
+}
index d7c8eaa4a9e55461994b9bb0f8f07d145d55e922..f3989ad201ac42b132cbd68c9ed894a54d83249c 100644 (file)
 #include <string.h>
 
 #include "macro.h"
+#include "string-util.h"
 #include "util.h"
 
 static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len);
 
+#include "arphrd-from-name.h"
 #include "arphrd-list.h"
 #include "arphrd-to-name.h"
-#include "arphrd-from-name.h"
 
 int main(int argc, const char *argv[]) {
 
@@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) {
         assert_se(arphrd_from_name("huddlduddl") == 0);
 
         return 0;
-}
\ No newline at end of file
+}
index abd36d693cd949108d57e0494d417f80cf1b3350..ada6d67c424b5605e476a1385269c5558571d48d 100644 (file)
@@ -20,8 +20,9 @@
 #include <unistd.h>
 
 #include "async.h"
-#include "util.h"
+#include "fileio.h"
 #include "macro.h"
+#include "util.h"
 
 static bool test_async = false;
 
index e4771c9dd73749dfb4d513d766186ed810fb5b69..33356f8387ad4bcc8968f12f8db8e87713e0a2d1 100644 (file)
 
 #include <fcntl.h>
 
-#include "log.h"
+#include "btrfs-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "log.h"
+#include "parse-util.h"
+#include "string-util.h"
 #include "util.h"
-#include "btrfs-util.h"
 
 int main(int argc, char *argv[]) {
+        BtrfsQuotaInfo quota;
         int r, fd;
 
         fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
         if (fd < 0)
                 log_error_errno(errno, "Failed to open root directory: %m");
         else {
-                BtrfsSubvolInfo info;
-                BtrfsQuotaInfo quota;
                 char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX];
+                BtrfsSubvolInfo info;
 
-                r = btrfs_subvol_get_info_fd(fd, &info);
+                r = btrfs_subvol_get_info_fd(fd, 0, &info);
                 if (r < 0)
                         log_error_errno(r, "Failed to get subvolume info: %m");
                 else {
@@ -45,7 +48,7 @@ int main(int argc, char *argv[]) {
                         log_info("read-only (search): %s", yes_no(info.read_only));
                 }
 
-                r = btrfs_subvol_get_quota_fd(fd, &quota);
+                r = btrfs_qgroup_get_quota_fd(fd, 0, &quota);
                 if (r < 0)
                         log_error_errno(r, "Failed to get quota info: %m");
                 else {
@@ -80,15 +83,15 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to make snapshot: %m");
 
-        r = btrfs_subvol_remove("/xxxtest", false);
+        r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA);
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
-        r = btrfs_subvol_remove("/xxxtest2", false);
+        r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA);
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
-        r = btrfs_subvol_remove("/xxxtest3", false);
+        r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA);
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
@@ -96,7 +99,7 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to make snapshot: %m");
 
-        r = btrfs_subvol_remove("/etc2", false);
+        r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA);
         if (r < 0)
                 log_error_errno(r, "Failed to remove subvolume: %m");
 
@@ -137,13 +140,61 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 log_error_errno(r, "Failed to snapshot subvolume: %m");
 
-        r = btrfs_subvol_remove("/xxxrectest", true);
+        r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
         if (r < 0)
                 log_error_errno(r, "Failed to recursively remove subvolume: %m");
 
-        r = btrfs_subvol_remove("/xxxrectest2", true);
+        r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
         if (r < 0)
                 log_error_errno(r, "Failed to recursively remove subvolume: %m");
 
+        r = btrfs_subvol_make("/xxxquotatest");
+        if (r < 0)
+                log_error_errno(r, "Failed to make subvolume: %m");
+
+        r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true);
+        if (r < 0)
+                log_error_errno(r, "Failed to set up auto qgroup: %m");
+
+        r = btrfs_subvol_make("/xxxquotatest/beneath");
+        if (r < 0)
+                log_error_errno(r, "Failed to make subvolume: %m");
+
+        r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false);
+        if (r < 0)
+                log_error_errno(r, "Failed to set up auto qgroup: %m");
+
+        r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024);
+        if (r < 0)
+                log_error_errno(r, "Failed to set up quota limit: %m");
+
+        r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024);
+        if (r < 0)
+                log_error_errno(r, "Failed to set up quota limit: %m");
+
+        r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
+        if (r < 0)
+                log_error_errno(r, "Failed to setup snapshot: %m");
+
+        r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, &quota);
+        if (r < 0)
+                log_error_errno(r, "Failed to query quota: %m");
+
+        assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
+
+        r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, &quota);
+        if (r < 0)
+                log_error_errno(r, "Failed to query quota: %m");
+
+        assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
+
+        r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
+        if (r < 0)
+                log_error_errno(r, "Failed remove subvolume: %m");
+
+        r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
+        if (r < 0)
+                log_error_errno(r, "Failed remove subvolume: %m");
+
         return 0;
 }
index 87e1da1258a703444a0988e48d3c875d91e7ac0f..70819b0371c0043458a3e7c7d31c016a3fb9d10d 100644 (file)
@@ -21,7 +21,9 @@
 
 #include <string.h>
 
+#include "alloc-util.h"
 #include "calendarspec.h"
+#include "string-util.h"
 #include "util.h"
 
 static void test_one(const char *input, const char *output) {
@@ -50,6 +52,44 @@ static void test_one(const char *input, const char *output) {
         assert_se(streq(q, p));
 }
 
+static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) {
+        CalendarSpec *c;
+        usec_t u;
+        char *old_tz;
+        char buf[FORMAT_TIMESTAMP_MAX];
+        int r;
+
+        old_tz = getenv("TZ");
+        if (old_tz)
+                old_tz = strdupa(old_tz);
+
+        if (new_tz)
+                assert_se(setenv("TZ", new_tz, 1) >= 0);
+        else
+                assert_se(unsetenv("TZ") >= 0);
+        tzset();
+
+        assert_se(calendar_spec_from_string(input, &c) >= 0);
+
+        printf("\"%s\"\n", input);
+
+        u = after;
+        r = calendar_spec_next_usec(c, after, &u);
+        printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
+        if (expect != (usec_t)-1)
+                assert_se(r >= 0 && u == expect);
+        else
+                assert(r == -ENOENT);
+
+        calendar_spec_free(c);
+
+        if (old_tz)
+                assert_se(setenv("TZ", old_tz, 1) >= 0);
+        else
+                assert_se(unsetenv("TZ") >= 0);
+        tzset();
+}
+
 int main(int argc, char* argv[]) {
         CalendarSpec *c;
 
@@ -82,6 +122,15 @@ int main(int argc, char* argv[]) {
         test_one("semi-annually", "*-01,07-01 00:00:00");
         test_one("annually", "*-01-01 00:00:00");
         test_one("*:2/3", "*-*-* *:02/3:00");
+        test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+
+        test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
+        test_next("2016-03-27 03:17:00", "EET", 12345, -1);
+        test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
 
         assert_se(calendar_spec_from_string("test", &c) < 0);
         assert_se(calendar_spec_from_string("", &c) < 0);
index 43a2d35b80346c8d65f8bf598711a97ec1fa5a12..4418bafda6e6aa95e70454e4683408fa561f6e85 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
-#include "fileio.h"
-#include "cap-list.h"
-#include "capability.h"
 #include <sys/prctl.h>
 
+#include "alloc-util.h"
+#include "cap-list.h"
+#include "capability-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "util.h"
+
 /* verify the capability parser */
 static void test_cap_list(void) {
         int i;
index f47452ce72502eb620c719d18b8f1b660c485e66..fc8d3ffe0d2bb4200874928cb75ff6c52015f670 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/wait.h>
-#include <sys/capability.h>
-#include <sys/socket.h>
 #include <netinet/in.h>
 #include <pwd.h>
+#include <sys/capability.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
-#include "capability.h"
-#include "util.h"
+#include "capability-util.h"
+#include "fd-util.h"
 #include "macro.h"
+#include "util.h"
 
 static uid_t test_uid = -1;
 static gid_t test_gid = -1;
-// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage
+
+/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
 static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE;
 
 static void fork_test(void (*test_func)(void)) {
index 4ecf09a29e0df0712da8f438001dbcae1c68b3aa..a48b324e2603070a7f74375c67d53fd352da1f83 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
-#include "util.h"
+#include "alloc-util.h"
 #include "cgroup-util.h"
-#include "test-helper.h"
+#include "dirent-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "parse-util.h"
 #include "process-util.h"
+#include "string-util.h"
+#include "test-helper.h"
+#include "user-util.h"
+#include "util.h"
 
 static void check_p_d_u(const char *path, int code, const char *result) {
         _cleanup_free_ char *unit = NULL;
index 37b1c3554aa1116839a6df77e914278ee7b7a694..c20a29ba1f83ff7d671d5a0e8379891b2ef99949 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "cgroup-util.h"
 #include "path-util.h"
+#include "string-util.h"
 #include "util.h"
 
 int main(int argc, char*argv[]) {
index b788c9532d97e4a1a84f7a9d6daf5e9adee3ea13..f224c6cdd8c11ab3cd19b39bb822748dbbe0f44e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "apparmor-util.h"
+#include "architecture.h"
+#include "audit-util.h"
 #include "condition.h"
-#include "macro.h"
-#include "util.h"
+#include "hostname-util.h"
+#include "ima-util.h"
 #include "log.h"
-#include "architecture.h"
-#include "sd-id128.h"
+#include "macro.h"
 #include "selinux-util.h"
-#include "audit.h"
-#include "ima-util.h"
-#include "apparmor-util.h"
 #include "smack-util.h"
-#include "hostname-util.h"
+#include "util.h"
 
 static void test_condition_test_path(void) {
         Condition *condition;
index 01ece022c12667d7e4b6f658a0f38fba1495f1bb..86ac513d4f51f7026ef2dad958bd1a419ea4e346 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <stdarg.h>
+#include <stdio.h>
 
+#include "alloc-util.h"
 #include "conf-files.h"
+#include "fs-util.h"
 #include "macro.h"
+#include "parse-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
-#include "rm-rf.h"
 
 static void setup_test_dir(char *tmp_dir, const char *files, ...) {
         va_list ap;
@@ -36,7 +41,7 @@ static void setup_test_dir(char *tmp_dir, const char *files, ...) {
         va_start(ap, files);
         while (files != NULL) {
                 _cleanup_free_ char *path = strappend(tmp_dir, files);
-                assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0) == 0);
+                assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID) == 0);
                 files = va_arg(ap, const char *);
         }
         va_end(ap);
index 463906d3046ea1c779fa1c19bd4f1ea87249f714..b3a4c403394fedfdf1e3e6e7f6456aa1dd6e67e1 100644 (file)
 ***/
 
 #include "conf-parser.h"
+#include "log.h"
 #include "macro.h"
-#include "util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "log.h"
+#include "util.h"
 
 static void test_config_parse_path_one(const char *rvalue, const char *expected) {
         char *path = NULL;
index a03a68bd43778353cdd52580b4813f9a536dfee3..ad57cb0202f5cd4ae5d1cc0642708330368a96f2 100644 (file)
 
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "copy.h"
-#include "path-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
+#include "macro.h"
 #include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
 #include "strv.h"
-#include "macro.h"
 #include "util.h"
-#include "rm-rf.h"
 
 static void test_copy_file(void) {
         _cleanup_free_ char *buf = NULL;
index 00b569080ccaa04809882b70af82e7e93197c6de..c6d8bf82eaa8e0fc8b546e5605b1b693d2c0f8f1 100644 (file)
 
 #include <string.h>
 
+#include "alloc-util.h"
+#include "string-util.h"
 #include "util.h"
 
-static void test_one(const char *p) {
+static void test_should_pass(const char *p) {
         usec_t t, q;
         char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
 
         assert_se(parse_timestamp(p, &t) >= 0);
-        format_timestamp(buf, sizeof(buf), t);
+        format_timestamp_us(buf, sizeof(buf), t);
         log_info("%s", buf);
 
         /* Chop off timezone */
@@ -42,23 +44,57 @@ static void test_one(const char *p) {
         assert_se(parse_timestamp(buf, &q) >= 0);
 }
 
+static void test_should_parse(const char *p) {
+        usec_t t;
+
+        assert_se(parse_timestamp(p, &t) >= 0);
+}
+
+static void test_should_fail(const char *p) {
+        usec_t t;
+
+        assert_se(parse_timestamp(p, &t) < 0);
+}
+
+static void test_one(const char *p) {
+        _cleanup_free_ char *with_utc;
+
+        log_info("Test: %s", p);
+        with_utc = strjoin(p, " UTC", NULL);
+        test_should_pass(p);
+        test_should_pass(with_utc);
+}
+
+static void test_one_noutc(const char *p) {
+        _cleanup_free_ char *with_utc;
+
+        log_info("Test: %s", p);
+        with_utc = strjoin(p, " UTC", NULL);
+        test_should_pass(p);
+        test_should_fail(with_utc);
+}
+
 int main(int argc, char *argv[]) {
         test_one("17:41");
         test_one("18:42:44");
+        test_one("18:42:44.0");
+        test_one("18:42:44.999999999999");
         test_one("12-10-02 12:13:14");
         test_one("12-10-2 12:13:14");
         test_one("12-10-03 12:13");
         test_one("2012-12-30 18:42");
         test_one("2012-10-02");
         test_one("Tue 2012-10-02");
-        test_one("now");
+        test_one_noutc("now");
         test_one("yesterday");
         test_one("today");
         test_one("tomorrow");
-        test_one("+2d");
-        test_one("+2y 4d");
-        test_one("5months ago");
-        test_one("@1395716396");
+        test_one_noutc("+2d");
+        test_one_noutc("+2y 4d");
+        test_one_noutc("5months ago");
+        test_one_noutc("@1395716396");
+        test_should_parse("today UTC");
+        test_should_fail("today UTC UTC");
 
         return 0;
 }
index 59ba4be0875f7b98587d77ef01273b9aae877822..646b168cc0e3a10c2489fd0963039aa3321865a0 100644 (file)
@@ -21,7 +21,9 @@
 
 #include <sys/types.h>
 
+#include "alloc-util.h"
 #include "device-nodes.h"
+#include "string-util.h"
 #include "util.h"
 
 /* helpers for test_encode_devnode_name */
index 2193eb6f7df500f0ae8e32117069d528074b17eb..d5778748a05036722f3a8bb1a0197880d310adc4 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
  ***/
 
-#include "macro.h"
+#include "alloc-util.h"
 #include "dns-domain.h"
+#include "macro.h"
+#include "string-util.h"
 
 static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
         char buffer[buffer_sz];
index 27df9089c38da9ac5cf209c27400bda451ef9701..c597d5aecd25e215930fdc4511f1df79a10f513c 100644 (file)
 
 #include <stdio.h>
 
-#include "util.h"
-#include "terminal-util.h"
+#include "alloc-util.h"
 #include "def.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
 
 static void test_one(const char *p) {
         _cleanup_free_ char *t;
index 6596069ade5102dcbcc115c5f6534e9b9b610727..954ed0d9e076b3c248851b26a100a90b28935447 100644 (file)
@@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test1: (Trivial)\n");
-        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &err, &j);
+        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
         if (sd_bus_error_is_set(&err))
                 log_error("error: %s: %s", err.name, err.message);
         assert_se(r == 0);
@@ -65,15 +65,15 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test2: (Cyclic Order, Unfixable)\n");
-        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test4: (Identical transaction)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load3:\n");
@@ -81,21 +81,21 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test5: (Colliding transaction, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
 
         printf("Test6: (Colliding transaction, replace)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test7: (Unmergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
 
         printf("Test8: (Mergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test9: (Unmergeable job type, replace)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load4:\n");
@@ -103,7 +103,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         manager_free(m);
index 110223f3b85d63920f8be4471d6d71df376fb37b..c1315bbf9ff8c3120779d2697d02942044d69a71 100644 (file)
 
 #include <string.h>
 
-#include "util.h"
-#include "strv.h"
 #include "env-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 static void test_strv_env_delete(void) {
         _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
index fa6336f1fbf69b7ac5a99a8090cb9eb7d16f6eb9..03ec0fcfc75456db6cc760996aa8a0a79bbf6884 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <grp.h>
+#include <pwd.h>
 #include <stdio.h>
+#include <sys/types.h>
 
-#include "unit.h"
-#include "manager.h"
-#include "util.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "macro.h"
+#include "manager.h"
 #include "mkdir.h"
+#include "path-util.h"
 #include "rm-rf.h"
+#include "unit.h"
+#include "util.h"
 
 typedef void (*test_function_t)(Manager *m);
 
@@ -123,11 +129,17 @@ static void test_exec_systemcallerrornumber(Manager *m) {
 }
 
 static void test_exec_user(Manager *m) {
-        test(m, "exec-user.service", 0, CLD_EXITED);
+        if (getpwnam("nobody"))
+                test(m, "exec-user.service", 0, CLD_EXITED);
+        else
+                log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m");
 }
 
 static void test_exec_group(Manager *m) {
-        test(m, "exec-group.service", 0, CLD_EXITED);
+        if (getgrnam("nobody"))
+                test(m, "exec-group.service", 0, CLD_EXITED);
+        else
+                log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m");
 }
 
 static void test_exec_environment(Manager *m) {
@@ -136,6 +148,50 @@ static void test_exec_environment(Manager *m) {
         test(m, "exec-environment-empty.service", 0, CLD_EXITED);
 }
 
+static void test_exec_environmentfile(Manager *m) {
+        static const char e[] =
+                "VAR1='word1 word2'\n"
+                "VAR2=word3 \n"
+                "# comment1\n"
+                "\n"
+                "; comment2\n"
+                " ; # comment3\n"
+                "line without an equal\n"
+                "VAR3='$word 5 6'\n";
+        int r;
+
+        r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
+        assert_se(r == 0);
+
+        test(m, "exec-environmentfile.service", 0, CLD_EXITED);
+
+        unlink("/tmp/test-exec_environmentfile.conf");
+}
+
+static void test_exec_passenvironment(Manager *m) {
+        /* test-execute runs under MANAGER_USER which, by default, forwards all
+         * variables present in the environment, but only those that are
+         * present _at the time it is created_!
+         *
+         * So these PassEnvironment checks are still expected to work, since we
+         * are ensuring the variables are not present at manager creation (they
+         * are unset explicitly in main) and are only set here.
+         *
+         * This is still a good approximation of how a test for MANAGER_SYSTEM
+         * would work.
+         */
+        assert_se(setenv("VAR1", "word1 word2", 1) == 0);
+        assert_se(setenv("VAR2", "word3", 1) == 0);
+        assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
+        test(m, "exec-passenvironment.service", 0, CLD_EXITED);
+        test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
+        test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
+        assert_se(unsetenv("VAR1") == 0);
+        assert_se(unsetenv("VAR2") == 0);
+        assert_se(unsetenv("VAR3") == 0);
+        test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
+}
+
 static void test_exec_umask(Manager *m) {
         test(m, "exec-umask-default.service", 0, CLD_EXITED);
         test(m, "exec-umask-0177.service", 0, CLD_EXITED);
@@ -144,7 +200,51 @@ static void test_exec_umask(Manager *m) {
 static void test_exec_runtimedirectory(Manager *m) {
         test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
         test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
-        test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+        if (getgrnam("nobody"))
+                test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+        else
+                log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m");
+}
+
+static void test_exec_capabilityboundingset(Manager *m) {
+        int r;
+
+        /* We use capsh to test if the capabilities are
+         * properly set, so be sure that it exists */
+        r = find_binary("capsh", NULL);
+        if (r < 0) {
+                log_error_errno(r, "Skipping test_exec_capabilityboundingset, could not find capsh binary: %m");
+                return;
+        }
+
+        test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
+        test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
+        test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
+        test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
+}
+
+static void test_exec_privatenetwork(Manager *m) {
+        int r;
+
+        r = find_binary("ip", NULL);
+        if (r < 0) {
+                log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m");
+                return;
+        }
+
+        test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
+}
+
+static void test_exec_oomscoreadjust(Manager *m) {
+        test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+        test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+}
+
+static void test_exec_ioschedulingclass(Manager *m) {
+        test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
+        test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
+        test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+        test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
 }
 
 int main(int argc, char *argv[]) {
@@ -154,13 +254,19 @@ int main(int argc, char *argv[]) {
                 test_exec_ignoresigpipe,
                 test_exec_privatetmp,
                 test_exec_privatedevices,
+                test_exec_privatenetwork,
                 test_exec_systemcallfilter,
                 test_exec_systemcallerrornumber,
                 test_exec_user,
                 test_exec_group,
                 test_exec_environment,
+                test_exec_environmentfile,
+                test_exec_passenvironment,
                 test_exec_umask,
                 test_exec_runtimedirectory,
+                test_exec_capabilityboundingset,
+                test_exec_oomscoreadjust,
+                test_exec_ioschedulingclass,
                 NULL,
         };
         test_function_t *test = NULL;
@@ -177,7 +283,17 @@ int main(int argc, char *argv[]) {
         }
 
         assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
-        assert_se(set_unit_path(TEST_DIR) >= 0);
+        assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0);
+
+        /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test
+         * cases, otherwise (and if they are present in the environment),
+         * `manager_default_environment` will copy them into the default
+         * environment which is passed to each created job, which will make the
+         * tests that expect those not to be present to fail.
+         */
+        assert_se(unsetenv("VAR1") == 0);
+        assert_se(unsetenv("VAR2") == 0);
+        assert_se(unsetenv("VAR3") == 0);
 
         r = manager_new(MANAGER_USER, true, &m);
         if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
new file mode 100644 (file)
index 0000000..65d3a0a
--- /dev/null
@@ -0,0 +1,558 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2013 Thomas H.P. Andersen
+
+  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 <string.h>
+
+#include "extract-word.h"
+#include "log.h"
+#include "string-util.h"
+
+static void test_extract_first_word(void) {
+        const char *p, *original;
+        char *t;
+
+        p = original = "foobar waldo";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(p == original + 7);
+
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"foobar\" \'waldo\'";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "\"foobar\""));
+        free(t);
+        assert_se(p == original + 9);
+
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "\'waldo\'"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"foobar\" \'waldo\'";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(p == original + 9);
+
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"";
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+        assert_se(streq(t, "\""));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+        assert_se(p == original + 1);
+
+        p = original = "\'";
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+        assert_se(streq(t, "\'"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\'";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+        assert_se(p == original + 1);
+
+        p = original = "\'fooo";
+        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+        assert_se(streq(t, "\'fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\'fooo";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\'fooo";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"fooo";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "yay\'foo\'bar";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "yay\'foo\'bar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "yay\'foo\'bar";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+        assert_se(streq(t, "yayfoobar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "   foobar   ";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = " foo\\ba\\x6ar ";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
+        assert_se(streq(t, "foo\ba\x6ar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = " foo\\ba\\x6ar ";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "foobax6ar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "    f\\u00f6o \"pi\\U0001F4A9le\"   ";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
+        assert_se(streq(t, "föo"));
+        free(t);
+        assert_se(p == original + 13);
+
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0);
+        assert_se(streq(t, "pi\360\237\222\251le"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "fooo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "fooo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "foo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "foo::bar";
+        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+        assert_se(streq(t, "foo"));
+        free(t);
+        assert_se(p == original + 5);
+
+        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+        assert_se(streq(t, "bar"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word(&p, &t, ":", 0) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "foo\\:bar::waldo";
+        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+        assert_se(streq(t, "foo:bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word(&p, &t, ":", 0) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "foo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "foo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "fooo bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+        assert_se(streq(t, "fooo bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "fooo\\ bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "\\w+@\\K[\\d.]+";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
+        assert_se(p == original + 1);
+
+        p = original = "\\w+@\\K[\\d.]+";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "\\w+@\\K[\\d.]+"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\\w+\\b";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+        assert_se(streq(t, "\\w+\b"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "-N ''";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+        assert_se(streq(t, "-N"));
+        free(t);
+        assert_se(p == original + 3);
+
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = ":foo\\:bar::waldo:";
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(t);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == original + 1);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, "foo:bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(t);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == original + 11);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(p == original + 17);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+        assert_se(streq(t, ""));
+        free(t);
+        assert_se(p == NULL);
+
+        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
+        assert_se(!t);
+        assert_se(!p);
+
+        p = "foo\\xbar";
+        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+        assert_se(streq(t, "fooxbar"));
+        free(t);
+        assert_se(p == NULL);
+
+        p = "foo\\xbar";
+        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) > 0);
+        assert_se(streq(t, "foo\\xbar"));
+        free(t);
+        assert_se(p == NULL);
+}
+
+static void test_extract_first_word_and_warn(void) {
+        const char *p, *original;
+        char *t;
+
+        p = original = "foobar waldo";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(p == original + 7);
+
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"foobar\" \'waldo\'";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foobar"));
+        free(t);
+        assert_se(p == original + 9);
+
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "waldo"));
+        free(t);
+        assert_se(isempty(p));
+
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
+        assert_se(!t);
+        assert_se(isempty(p));
+
+        p = original = "\"";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+        assert_se(p == original + 1);
+
+        p = original = "\'";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+        assert_se(p == original + 1);
+
+        p = original = "\'fooo";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\'fooo";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = " foo\\ba\\x6ar ";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foo\ba\x6ar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = " foo\\ba\\x6ar ";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foobax6ar"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "    f\\u00f6o \"pi\\U0001F4A9le\"   ";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "föo"));
+        free(t);
+        assert_se(p == original + 13);
+
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "pi\360\237\222\251le"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo\\"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
+        assert_se(p == original + 5);
+
+        p = original = "\"foo\\";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "foo"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "fooo\\ bar quux";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "fooo\\ bar"));
+        free(t);
+        assert_se(p == original + 10);
+
+        p = original = "\\w+@\\K[\\d.]+";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "\\w+@\\K[\\d.]+"));
+        free(t);
+        assert_se(isempty(p));
+
+        p = original = "\\w+\\b";
+        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+        assert_se(streq(t, "\\w+\b"));
+        free(t);
+        assert_se(isempty(p));
+}
+
+static void test_extract_many_words(void) {
+        const char *p, *original;
+        char *a, *b, *c;
+
+        p = original = "foobar waldi piep";
+        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, "foobar"));
+        assert_se(streq_ptr(b, "waldi"));
+        assert_se(streq_ptr(c, "piep"));
+        free(a);
+        free(b);
+        free(c);
+
+        p = original = "'foobar' wa\"ld\"i   ";
+        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, "'foobar'"));
+        assert_se(streq_ptr(b, "wa\"ld\"i"));
+        assert_se(streq_ptr(c, NULL));
+        free(a);
+        free(b);
+
+        p = original = "'foobar' wa\"ld\"i   ";
+        assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, "foobar"));
+        assert_se(streq_ptr(b, "waldi"));
+        assert_se(streq_ptr(c, NULL));
+        free(a);
+        free(b);
+
+        p = original = "";
+        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, NULL));
+        assert_se(streq_ptr(b, NULL));
+        assert_se(streq_ptr(c, NULL));
+
+        p = original = "  ";
+        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, NULL));
+        assert_se(streq_ptr(b, NULL));
+        assert_se(streq_ptr(c, NULL));
+
+        p = original = "foobar";
+        assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
+        assert_se(p == original);
+
+        p = original = "foobar waldi";
+        assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+        assert_se(p == original+7);
+        assert_se(streq_ptr(a, "foobar"));
+        free(a);
+
+        p = original = "     foobar    ";
+        assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+        assert_se(isempty(p));
+        assert_se(streq_ptr(a, "foobar"));
+        free(a);
+}
+
+int main(int argc, char *argv[]) {
+        log_parse_environment();
+        log_open();
+
+        test_extract_first_word();
+        test_extract_first_word_and_warn();
+        test_extract_many_words();
+
+        return 0;
+}
index 242c5d9dc29aa943aff619f6bef468806c815534..282aab12460b3156cf212b7ac1426b77add7b3d0 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
+#include "fd-util.h"
 #include "fdset.h"
-#include "util.h"
+#include "fileio.h"
 #include "macro.h"
+#include "util.h"
 
 static void test_fdset_new_fill(void) {
         int fd = -1;
index ad547822e7d83080d42d6d19d285ec282d6de46c..bde3c7c3cfc78d7a500f14882b5b1dc2ab2d935f 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 
-#include "util.h"
-#include "process-util.h"
+#include "alloc-util.h"
+#include "ctype.h"
+#include "def.h"
+#include "env-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
 #include "strv.h"
-#include "env-util.h"
-#include "def.h"
-#include "ctype.h"
+#include "util.h"
 
 static void test_parse_env_file(void) {
         char    t[] = "/tmp/test-fileio-in-XXXXXX",
@@ -359,6 +363,26 @@ static void test_write_string_file_no_create(void) {
         unlink(fn);
 }
 
+static void test_write_string_file_verify(void) {
+        _cleanup_free_ char *buf = NULL, *buf2 = NULL;
+        int r;
+
+        assert_se(read_one_line_file("/proc/cmdline", &buf) >= 0);
+        assert_se((buf2 = strjoin(buf, "\n", NULL)));
+
+        r = write_string_file("/proc/cmdline", buf, 0);
+        assert_se(r == -EACCES || r == -EIO);
+        r = write_string_file("/proc/cmdline", buf2, 0);
+        assert_se(r == -EACCES || r == -EIO);
+
+        assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
+        assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
+
+        r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
+        assert_se(r == -EACCES || r == -EIO);
+        assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
+}
+
 static void test_load_env_file_pairs(void) {
         char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
         int fd;
@@ -415,6 +439,7 @@ int main(int argc, char *argv[]) {
         test_write_string_stream();
         test_write_string_file();
         test_write_string_file_no_create();
+        test_write_string_file_verify();
         test_load_env_file_pairs();
 
         return 0;
index 50e5dee0a71c62070c6563a0924b8fc006a4872f..27816ac7796a5c6f54f0bc1cb24b8f942ef446bd 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "fstab-util.h"
-#include "util.h"
 #include "log.h"
+#include "string-util.h"
+#include "util.h"
 
 /*
 int fstab_filter_options(const char *opts, const char *names,
index c691f577c6034e7179bb01a7138361b20a1ee08c..6bf33306a94ba48361034a89bb9542d3493e8b90 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
+#include "hashmap.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
-#include "hashmap.h"
 
 void test_hashmap_funcs(void);
 
index 6f5ef2615e30ad6a78b3b01616fde2e469bcd644..590175433c3c0e7ea4bd30f6456723c71cab3a48 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "alloc-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
+#include "string-util.h"
+#include "util.h"
 
 static void test_hostname_is_valid(void) {
         assert_se(hostname_is_valid("foobar", false));
index a6a0cd77a1dce3475818f05c3d8d8a5b73f69d74..32cf3f80ca6e73ae54cc98521623503b57a56c7e 100644 (file)
 
 #include <string.h>
 
-#include "systemd/sd-id128.h"
+#include "sd-daemon.h"
+#include "sd-id128.h"
 
-#include "util.h"
+#include "alloc-util.h"
 #include "macro.h"
-#include "sd-daemon.h"
+#include "string-util.h"
+#include "util.h"
 
 #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10)
 #define STR_WALDI "0102030405060708090a0b0c0d0e0f10"
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
new file mode 100644 (file)
index 0000000..08fde94
--- /dev/null
@@ -0,0 +1,665 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 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 "fileio.h"
+#include "install.h"
+#include "mkdir.h"
+#include "rm-rf.h"
+#include "string-util.h"
+
+static void test_basic_mask_and_enable(const char *root) {
+        const char *p;
+        UnitFileState state;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+
+        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);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/a.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        p = strjoina(root, "/usr/lib/systemd/system/b.service");
+        assert_se(symlink("a.service", p) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        p = strjoina(root, "/usr/lib/systemd/system/c.service");
+        assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        p = strjoina(root, "/usr/lib/systemd/system/d.service");
+        assert_se(symlink("c.service", p) >= 0);
+
+        /* This one is interesting, as d follows a relative, then an absolute symlink */
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/dev/null"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
+        assert_se(streq(changes[0].path, p));
+
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED);
+        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);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        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(n_changes == 0);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        /* Disabling a disabled unit must suceed but be a NOP */
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 0);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        /* Let's enable this indirectly via a symlink */
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+
+        /* Let's try to reenable */
+
+        assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 2);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
+        assert_se(streq(changes[0].path, p));
+        assert_se(changes[1].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service"));
+        assert_se(streq(changes[1].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+}
+
+static void test_linked_units(const char *root) {
+        const char *p, *q;
+        UnitFileState state;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0, i;
+
+        /*
+         * We'll test three cases here:
+         *
+         * a) a unit file in /opt, that we use "systemctl link" and
+         * "systemctl enable" on to make it available to the system
+         *
+         * b) a unit file in /opt, that is statically linked into
+         * /usr/lib/systemd/system, that "enable" should work on
+         * correctly.
+         *
+         * c) a unit file in /opt, that is linked into
+         * /etc/systemd/system, and where "enable" should result in
+         * -ELOOP, since using information from /etc to generate
+         * information in /etc should not be allowed.
+         */
+
+        p = strjoina(root, "/opt/linked.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/opt/linked2.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/opt/linked3.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/linked2.service");
+        assert_se(symlink("/opt/linked2.service", p) >= 0);
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service");
+        assert_se(symlink("/opt/linked3.service", p) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED);
+
+        /* First, let's link the unit into the search path */
+        assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/opt/linked.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED);
+
+        /* Let's unlink it from the search path again */
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
+
+        /* Now, let's not just link it, but also enable it */
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 2);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
+        q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+        for (i = 0 ; i < n_changes; i++) {
+                assert_se(changes[i].type == UNIT_FILE_SYMLINK);
+                assert_se(streq(changes[i].source, "/opt/linked.service"));
+
+                if (p && streq(changes[i].path, p))
+                        p = NULL;
+                else if (q && streq(changes[i].path, q))
+                        q = NULL;
+                else
+                        assert_not_reached("wut?");
+        }
+        assert(!p && !q);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+
+        /* And let's unlink it again */
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 2);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
+        q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
+        for (i = 0; i < n_changes; i++) {
+                assert_se(changes[i].type == UNIT_FILE_UNLINK);
+
+                if (p && streq(changes[i].path, p))
+                        p = NULL;
+                else if (q && streq(changes[i].path, q))
+                        q = NULL;
+                else
+                        assert_not_reached("wut?");
+        }
+        assert(!p && !q);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 2);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service");
+        q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service");
+        for (i = 0 ; i < n_changes; i++) {
+                assert_se(changes[i].type == UNIT_FILE_SYMLINK);
+                assert_se(streq(changes[i].source, "/opt/linked2.service"));
+
+                if (p && streq(changes[i].path, p))
+                        p = NULL;
+                else if (q && streq(changes[i].path, q))
+                        q = NULL;
+                else
+                        assert_not_reached("wut?");
+        }
+        assert(!p && !q);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+}
+
+static void test_default(const char *root) {
+        _cleanup_free_ char *def = NULL;
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        const char *p;
+
+        p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target");
+        assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/test-default.target");
+        assert_se(symlink("test-default-real.target", p) >= 0);
+
+        assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
+
+        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT);
+        assert_se(n_changes == 0);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
+
+        assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0);
+        assert_se(streq_ptr(def, "test-default-real.target"));
+}
+
+static void test_add_dependency(const char *root) {
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        const char *p;
+
+        p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
+        assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target");
+        assert_se(symlink("real-add-dependency-test-target.target", p) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
+        assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service");
+        assert_se(symlink("real-add-dependency-test-service.service", p) >= 0);
+
+        assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+}
+
+static void test_template_enable(const char *root) {
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        UnitFileState state;
+        const char *p;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/template@.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "DefaultInstance=def\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service");
+        assert_se(symlink("template@.service", p) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.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;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.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;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+}
+
+static void test_indirect(const char *root) {
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0;
+        UnitFileState state;
+        const char *p;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/indirecta.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/indirectb.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/indirectc.service");
+        assert_se(symlink("indirecta.service", p) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+
+        assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
+
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+}
+
+static void test_preset_and_list(const char *root) {
+        UnitFileChange *changes = NULL;
+        unsigned n_changes = 0, i;
+        const char *p, *q;
+        UnitFileState state;
+        bool got_yes = false, got_no = false;
+        Iterator j;
+        UnitFileList *fl;
+        Hashmap *h;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT);
+
+        p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
+        assert_se(write_string_file(p,
+                                    "[Install]\n"
+                                    "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
+        assert_se(write_string_file(p,
+                                    "enable *-yes.*\n"
+                                    "disable *\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+        assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service"));
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
+        assert_se(n_changes == 1);
+        assert_se(changes[0].type == UNIT_FILE_UNLINK);
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
+        assert_se(streq(changes[0].path, p));
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+        assert_se(n_changes == 0);
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+        assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+
+        assert_se(n_changes > 0);
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
+
+        for (i = 0; i < n_changes; i++) {
+
+                if (changes[i].type == UNIT_FILE_SYMLINK) {
+                        assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service"));
+                        assert_se(streq(changes[i].path, p));
+                } else
+                        assert_se(changes[i].type == UNIT_FILE_UNLINK);
+        }
+
+        unit_file_changes_free(changes, n_changes);
+        changes = NULL; n_changes = 0;
+
+        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+        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);
+
+        p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
+        q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
+
+        HASHMAP_FOREACH(fl, h, j) {
+                assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0);
+                assert_se(fl->state == state);
+
+                if (streq(fl->path, p)) {
+                        got_yes = true;
+                        assert_se(fl->state == UNIT_FILE_ENABLED);
+                } else if (streq(fl->path, q)) {
+                        got_no = true;
+                        assert_se(fl->state == UNIT_FILE_DISABLED);
+                } else
+                        assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT));
+        }
+
+        unit_file_list_free(h);
+
+        assert_se(got_yes && got_no);
+}
+
+int main(int argc, char *argv[]) {
+        char root[] = "/tmp/rootXXXXXX";
+        const char *p;
+
+        assert_se(mkdtemp(root));
+
+        p = strjoina(root, "/usr/lib/systemd/system/");
+        assert_se(mkdir_p(p, 0755) >= 0);
+
+        p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/");
+        assert_se(mkdir_p(p, 0755) >= 0);
+
+        p = strjoina(root, "/run/systemd/system/");
+        assert_se(mkdir_p(p, 0755) >= 0);
+
+        p = strjoina(root, "/opt/");
+        assert_se(mkdir_p(p, 0755) >= 0);
+
+        p = strjoina(root, "/usr/lib/systemd/system-preset/");
+        assert_se(mkdir_p(p, 0755) >= 0);
+
+        test_basic_mask_and_enable(root);
+        test_linked_units(root);
+        test_default(root);
+        test_add_dependency(root);
+        test_template_enable(root);
+        test_indirect(root);
+        test_preset_and_list(root);
+
+        assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+
+        return 0;
+}
index 5ee52e64cb5ac0a271429d7523c6cc12e96c9b3a..359b2623476614683a2bddcf96d40018bf193e78 100644 (file)
@@ -46,17 +46,19 @@ int main(int argc, char* argv[]) {
         const char *const files2[] = { "/home/lennart/test.service", NULL };
         UnitFileChange *changes = NULL;
         unsigned n_changes = 0;
+        UnitFileState state = 0;
 
         h = hashmap_new(&string_hash_ops);
         r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
         assert_se(r == 0);
 
         HASHMAP_FOREACH(p, h, i) {
-                UnitFileState s;
+                UnitFileState s = _UNIT_FILE_STATE_INVALID;
 
-                s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path));
+                r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s);
 
-                assert_se(p->state == s);
+                assert_se((r < 0 && p->state == UNIT_FILE_BAD) ||
+                          (p->state == s));
 
                 fprintf(stderr, "%s (%s)\n",
                         p->path,
@@ -78,7 +80,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_ENABLED);
 
         log_error("disable");
 
@@ -91,7 +95,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_DISABLED);
 
         log_error("mask");
         changes = NULL;
@@ -106,7 +112,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_MASKED);
 
         log_error("unmask");
         changes = NULL;
@@ -121,7 +129,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_DISABLED);
 
         log_error("mask");
         changes = NULL;
@@ -133,7 +143,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_MASKED);
 
         log_error("disable");
         changes = NULL;
@@ -148,7 +160,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_MASKED);
 
         log_error("umask");
         changes = NULL;
@@ -160,7 +174,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_DISABLED);
 
         log_error("enable files2");
         changes = NULL;
@@ -172,19 +188,22 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_ENABLED);
 
         log_error("disable files2");
         changes = NULL;
         n_changes = 0;
 
-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
         assert_se(r >= 0);
 
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r < 0);
 
         log_error("link files2");
         changes = NULL;
@@ -196,19 +215,22 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_LINKED);
 
         log_error("disable files2");
         changes = NULL;
         n_changes = 0;
 
-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
         assert_se(r >= 0);
 
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r < 0);
 
         log_error("link files2");
         changes = NULL;
@@ -220,7 +242,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_LINKED);
 
         log_error("reenable files2");
         changes = NULL;
@@ -232,19 +256,22 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_ENABLED);
 
         log_error("disable files2");
         changes = NULL;
         n_changes = 0;
 
-        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes);
+        r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes);
         assert_se(r >= 0);
 
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
+        assert_se(r < 0);
         log_error("preset files");
         changes = NULL;
         n_changes = 0;
@@ -255,7 +282,9 @@ int main(int argc, char* argv[]) {
         dump_changes(changes, n_changes);
         unit_file_changes_free(changes, n_changes);
 
-        assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED);
+        r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state);
+        assert_se(r >= 0);
+        assert_se(state == UNIT_FILE_ENABLED);
 
         return 0;
 }
index 4944bf6ad930e2b6e15790d501a3fed92c93d2c6..5841cb3fb1d25ab4fc11e4213fa622c7bae30d41 100644 (file)
@@ -19,8 +19,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
 #include "clean-ipc.h"
+#include "user-util.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         uid_t uid;
index 1058c583c36a88b5ab9b4ed1d526da21cf727335..3995224eea888790fde0186820b92378abad803d 100644 (file)
 
 #include <math.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "json.h"
+#include "string-util.h"
+#include "util.h"
 
 static void test_one(const char *data, ...) {
         void *state = NULL;
index 34c49b969a8cf8f21167d0234661e5a976702f0e..350eaf734dd1d040829707aea5aafd06e0c452c6 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <unistd.h>
 #include <getopt.h>
+#include <stdio.h>
 #include <sys/epoll.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
+#include "string-util.h"
 #include "udev-util.h"
 #include "util.h"
 
index 7d7e08dc5d1480a0b0e7b6cb8f0d1be3f9486e83..5a12e959d4350b090403aba7654571b2b93e967a 100644 (file)
 
 #include <sys/socket.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "namespace.h"
-#include "util.h"
 #include "process-util.h"
+#include "string-util.h"
+#include "util.h"
 
 static void test_tmpdir(const char *id, const char *A, const char *B) {
         _cleanup_free_ char *a, *b;
index 2879d7450f085434972d0ff8a0a574a7dcfa7209..a1e8774063ce6e73f35342a2eae2c2d414923195 100644 (file)
 ***/
 
 #include <arpa/inet.h>
-#include <net/if.h>
+#include <libkmod.h>
 #include <linux/ip.h>
+#include <net/if.h>
 #include <linux/if_tunnel.h>
-#include <libkmod.h>
 
-#include "util.h"
-#include "macro.h"
 #include "sd-netlink.h"
 
+#include "macro.h"
+#include "util.h"
+
 static int load_module(const char *mod_name) {
         struct kmod_ctx *ctx;
         struct kmod_list *list = NULL, *l;
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
new file mode 100644 (file)
index 0000000..f0d5d71
--- /dev/null
@@ -0,0 +1,495 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+  Copyright 2013 Thomas H.P. Andersen
+
+  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 <locale.h>
+#include <math.h>
+
+#include "log.h"
+#include "parse-util.h"
+
+static void test_parse_boolean(void) {
+        assert_se(parse_boolean("1") == 1);
+        assert_se(parse_boolean("y") == 1);
+        assert_se(parse_boolean("Y") == 1);
+        assert_se(parse_boolean("yes") == 1);
+        assert_se(parse_boolean("YES") == 1);
+        assert_se(parse_boolean("true") == 1);
+        assert_se(parse_boolean("TRUE") == 1);
+        assert_se(parse_boolean("on") == 1);
+        assert_se(parse_boolean("ON") == 1);
+
+        assert_se(parse_boolean("0") == 0);
+        assert_se(parse_boolean("n") == 0);
+        assert_se(parse_boolean("N") == 0);
+        assert_se(parse_boolean("no") == 0);
+        assert_se(parse_boolean("NO") == 0);
+        assert_se(parse_boolean("false") == 0);
+        assert_se(parse_boolean("FALSE") == 0);
+        assert_se(parse_boolean("off") == 0);
+        assert_se(parse_boolean("OFF") == 0);
+
+        assert_se(parse_boolean("garbage") < 0);
+        assert_se(parse_boolean("") < 0);
+        assert_se(parse_boolean("full") < 0);
+}
+
+static void test_parse_pid(void) {
+        int r;
+        pid_t pid;
+
+        r = parse_pid("100", &pid);
+        assert_se(r == 0);
+        assert_se(pid == 100);
+
+        r = parse_pid("0x7FFFFFFF", &pid);
+        assert_se(r == 0);
+        assert_se(pid == 2147483647);
+
+        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+        r = parse_pid("0", &pid);
+        assert_se(r == -ERANGE);
+        assert_se(pid == 65);
+
+        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+        r = parse_pid("-100", &pid);
+        assert_se(r == -ERANGE);
+        assert_se(pid == 65);
+
+        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+        r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
+        assert_se(r == -ERANGE);
+        assert_se(pid == 65);
+
+        r = parse_pid("junk", &pid);
+        assert_se(r == -EINVAL);
+}
+
+static void test_parse_mode(void) {
+        mode_t m;
+
+        assert_se(parse_mode("-1", &m) < 0);
+        assert_se(parse_mode("", &m) < 0);
+        assert_se(parse_mode("888", &m) < 0);
+        assert_se(parse_mode("77777", &m) < 0);
+
+        assert_se(parse_mode("544", &m) >= 0 && m == 0544);
+        assert_se(parse_mode("777", &m) >= 0 && m == 0777);
+        assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
+        assert_se(parse_mode("0", &m) >= 0 && m == 0);
+}
+
+static void test_parse_size(void) {
+        uint64_t bytes;
+
+        assert_se(parse_size("111", 1024, &bytes) == 0);
+        assert_se(bytes == 111);
+
+        assert_se(parse_size("111.4", 1024, &bytes) == 0);
+        assert_se(bytes == 111);
+
+        assert_se(parse_size(" 112 B", 1024, &bytes) == 0);
+        assert_se(bytes == 112);
+
+        assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0);
+        assert_se(bytes == 112);
+
+        assert_se(parse_size("3.5 K", 1024, &bytes) == 0);
+        assert_se(bytes == 3*1024 + 512);
+
+        assert_se(parse_size("3. K", 1024, &bytes) == 0);
+        assert_se(bytes == 3*1024);
+
+        assert_se(parse_size("3.0 K", 1024, &bytes) == 0);
+        assert_se(bytes == 3*1024);
+
+        assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0);
+        assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512);
+
+        assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("3.5G3B", 1024, &bytes) == 0);
+        assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3);
+
+        assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0);
+        assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4);
+
+        assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("4T3G3B", 1024, &bytes) == 0);
+        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+        assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0);
+        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+        assert_se(parse_size("12P", 1024, &bytes) == 0);
+        assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("3E 2P", 1024, &bytes) == 0);
+        assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
+
+        assert_se(parse_size("12X", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL);
+
+        assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE);
+        assert_se(parse_size("-1", 1024, &bytes) == -ERANGE);
+        assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE);
+
+        assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE);
+
+        assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
+}
+
+static void test_parse_range(void) {
+        unsigned lower, upper;
+
+        /* Successful cases */
+        assert_se(parse_range("111", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 111);
+
+        assert_se(parse_range("111-123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("123-111", &lower, &upper) == 0);
+        assert_se(lower == 123);
+        assert_se(upper == 111);
+
+        assert_se(parse_range("123-123", &lower, &upper) == 0);
+        assert_se(lower == 123);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("0", &lower, &upper) == 0);
+        assert_se(lower == 0);
+        assert_se(upper == 0);
+
+        assert_se(parse_range("0-15", &lower, &upper) == 0);
+        assert_se(lower == 0);
+        assert_se(upper == 15);
+
+        assert_se(parse_range("15-0", &lower, &upper) == 0);
+        assert_se(lower == 15);
+        assert_se(upper == 0);
+
+        assert_se(parse_range("128-65535", &lower, &upper) == 0);
+        assert_se(lower == 128);
+        assert_se(upper == 65535);
+
+        assert_se(parse_range("1024-4294967295", &lower, &upper) == 0);
+        assert_se(lower == 1024);
+        assert_se(upper == 4294967295);
+
+        /* Leading whitespace is acceptable */
+        assert_se(parse_range(" 111", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 111);
+
+        assert_se(parse_range(" 111-123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("111- 123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range("\t111-\t123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0);
+        assert_se(lower == 111);
+        assert_se(upper == 123);
+
+        /* Error cases, make sure they fail as expected */
+        lower = upper = 9999;
+        assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Empty string */
+        lower = upper = 9999;
+        assert_se(parse_range("", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */
+        assert_se(parse_range("111--123", &lower, &upper) == -ERANGE);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Error on trailing dash */
+        assert_se(parse_range("111-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111--", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111- ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Whitespace is not a separator */
+        assert_se(parse_range("111 123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Trailing whitespace is invalid (from safe_atou) */
+        assert_se(parse_range("111 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+
+        /* Out of the "unsigned" range, this is 1<<64 */
+        assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE);
+        assert_se(lower == 9999);
+        assert_se(upper == 9999);
+}
+
+static void test_safe_atolli(void) {
+        int r;
+        long long l;
+
+        r = safe_atolli("12345", &l);
+        assert_se(r == 0);
+        assert_se(l == 12345);
+
+        r = safe_atolli("  12345", &l);
+        assert_se(r == 0);
+        assert_se(l == 12345);
+
+        r = safe_atolli("-12345", &l);
+        assert_se(r == 0);
+        assert_se(l == -12345);
+
+        r = safe_atolli("  -12345", &l);
+        assert_se(r == 0);
+        assert_se(l == -12345);
+
+        r = safe_atolli("12345678901234567890", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atolli("-12345678901234567890", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atolli("junk", &l);
+        assert_se(r == -EINVAL);
+}
+
+static void test_safe_atou16(void) {
+        int r;
+        uint16_t l;
+
+        r = safe_atou16("12345", &l);
+        assert_se(r == 0);
+        assert_se(l == 12345);
+
+        r = safe_atou16("  12345", &l);
+        assert_se(r == 0);
+        assert_se(l == 12345);
+
+        r = safe_atou16("123456", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atou16("-1", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atou16("  -1", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atou16("junk", &l);
+        assert_se(r == -EINVAL);
+}
+
+static void test_safe_atoi16(void) {
+        int r;
+        int16_t l;
+
+        r = safe_atoi16("-12345", &l);
+        assert_se(r == 0);
+        assert_se(l == -12345);
+
+        r = safe_atoi16("  -12345", &l);
+        assert_se(r == 0);
+        assert_se(l == -12345);
+
+        r = safe_atoi16("32767", &l);
+        assert_se(r == 0);
+        assert_se(l == 32767);
+
+        r = safe_atoi16("  32767", &l);
+        assert_se(r == 0);
+        assert_se(l == 32767);
+
+        r = safe_atoi16("36536", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atoi16("-32769", &l);
+        assert_se(r == -ERANGE);
+
+        r = safe_atoi16("junk", &l);
+        assert_se(r == -EINVAL);
+}
+
+static void test_safe_atod(void) {
+        int r;
+        double d;
+        char *e;
+
+        r = safe_atod("junk", &d);
+        assert_se(r == -EINVAL);
+
+        r = safe_atod("0.2244", &d);
+        assert_se(r == 0);
+        assert_se(fabs(d - 0.2244) < 0.000001);
+
+        r = safe_atod("0,5", &d);
+        assert_se(r == -EINVAL);
+
+        errno = 0;
+        strtod("0,5", &e);
+        assert_se(*e == ',');
+
+        /* Check if this really is locale independent */
+        if (setlocale(LC_NUMERIC, "de_DE.utf8")) {
+
+                r = safe_atod("0.2244", &d);
+                assert_se(r == 0);
+                assert_se(fabs(d - 0.2244) < 0.000001);
+
+                r = safe_atod("0,5", &d);
+                assert_se(r == -EINVAL);
+
+                errno = 0;
+                assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001);
+        }
+
+        /* And check again, reset */
+        assert_se(setlocale(LC_NUMERIC, "C"));
+
+        r = safe_atod("0.2244", &d);
+        assert_se(r == 0);
+        assert_se(fabs(d - 0.2244) < 0.000001);
+
+        r = safe_atod("0,5", &d);
+        assert_se(r == -EINVAL);
+
+        errno = 0;
+        strtod("0,5", &e);
+        assert_se(*e == ',');
+}
+
+int main(int argc, char *argv[]) {
+        log_parse_environment();
+        log_open();
+
+        test_parse_boolean();
+        test_parse_pid();
+        test_parse_mode();
+        test_parse_size();
+        test_parse_range();
+        test_safe_atolli();
+        test_safe_atou16();
+        test_safe_atoi16();
+        test_safe_atod();
+
+        return 0;
+}
index aa4bac6cdd93575a338afefcc9532654a6f57e2a..65cb894ff7df5a8bbf2e1b620f85c9260bb6de2d 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <stdlib.h>
 #include <sys/stat.h>
 
-#include "path-lookup.h"
 #include "log.h"
-#include "strv.h"
+#include "path-lookup.h"
 #include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
 
 static void test_paths(ManagerRunningAs running_as, bool personal) {
         char template[] = "/tmp/test-path-lookup.XXXXXXX";
 
-        _cleanup_lookup_paths_free_ LookupPaths lp = {};
-        char *exists, *not;
+        _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
+        _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
+        char *exists, *not, *systemd_unit_path;
 
         assert_se(mkdtemp(template));
         exists = strjoina(template, "/exists");
         assert_se(mkdir(exists, 0755) == 0);
         not = strjoina(template, "/not");
 
-        assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0);
+        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(!strv_isempty(lp.unit_path));
-        assert_se(strv_contains(lp.unit_path, exists));
-        assert_se(strv_contains(lp.unit_path, not));
+        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(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
index fce4e81a09cd88e021fb583409d1e91b597787df..3f0f0264abf01e4537c2c53900e784ba7f8fd258 100644 (file)
 ***/
 
 #include <stdio.h>
-#include <unistd.h>
 #include <sys/mount.h>
+#include <unistd.h>
 
-#include "path-util.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "macro.h"
-#include "strv.h"
+#include "mount-util.h"
+#include "path-util.h"
 #include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 #define test_path_compare(a, b, result) {                 \
                 assert_se(path_compare(a, b) == result);  \
@@ -75,20 +79,6 @@ static void test_path(void) {
         assert_se(streq(basename("/aa///file..."), "file..."));
         assert_se(streq(basename("file.../"), ""));
 
-#define test_parent(x, y) {                                \
-                _cleanup_free_ char *z = NULL;             \
-                int r = path_get_parent(x, &z);            \
-                printf("expected: %s\n", y ? y : "error"); \
-                printf("actual: %s\n", r<0 ? "error" : z); \
-                assert_se((y==NULL) ^ (r==0));             \
-                assert_se(y==NULL || path_equal(z, y));    \
-        }
-
-        test_parent("./aa/bb/../file.da.", "./aa/bb/..");
-        test_parent("/aa///.file", "/aa///");
-        test_parent("/aa///file...", "/aa///");
-        test_parent("file.../", NULL);
-
         fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
         assert_se(fd >= 0);
         assert_se(fd_is_mount_point(fd, "/", 0) > 0);
@@ -104,32 +94,28 @@ static void test_path(void) {
         }
 }
 
-static void test_find_binary(const char *self, bool local) {
+static void test_find_binary(const char *self) {
         char *p;
 
-        assert_se(find_binary("/bin/sh", local, &p) == 0);
+        assert_se(find_binary("/bin/sh", &p) == 0);
         puts(p);
-        assert_se(streq(p, "/bin/sh"));
+        assert_se(path_equal(p, "/bin/sh"));
         free(p);
 
-        assert_se(find_binary(self, local, &p) == 0);
+        assert_se(find_binary(self, &p) == 0);
         puts(p);
         assert_se(endswith(p, "/test-path-util"));
         assert_se(path_is_absolute(p));
         free(p);
 
-        assert_se(find_binary("sh", local, &p) == 0);
+        assert_se(find_binary("sh", &p) == 0);
         puts(p);
         assert_se(endswith(p, "/sh"));
         assert_se(path_is_absolute(p));
         free(p);
 
-        assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT);
-
-        assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) ==
-                  (local ? -ENOENT : 0));
-        if (!local)
-                free(p);
+        assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
+        assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
 }
 
 static void test_prefixes(void) {
@@ -210,9 +196,10 @@ static void test_fsck_exists(void) {
         unsetenv("PATH");
 
         /* fsck.minix is provided by util-linux and will probably exist. */
-        assert_se(fsck_exists("minix") == 0);
+        assert_se(fsck_exists("minix") == 1);
 
-        assert_se(fsck_exists("AbCdE") == -ENOENT);
+        assert_se(fsck_exists("AbCdE") == 0);
+        assert_se(fsck_exists("/../bin/") == 0);
 }
 
 static void test_make_relative(void) {
@@ -450,8 +437,7 @@ static void test_path_is_mount_point(void) {
 
 int main(int argc, char **argv) {
         test_path();
-        test_find_binary(argv[0], true);
-        test_find_binary(argv[0], false);
+        test_find_binary(argv[0]);
         test_prefixes();
         test_path_join();
         test_fsck_exists();
index 676c9f17932ab94a6812792455917c4d0ba68b5c..8302bdd28302a0f0e4525fe933d73f15e5a1afeb 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <stdbool.h>
+#include <stdio.h>
 
-#include "unit.h"
-#include "manager.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "macro.h"
-#include "strv.h"
+#include "manager.h"
 #include "mkdir.h"
 #include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit.h"
+#include "util.h"
 
 typedef void (*test_function_t)(Manager *m);
 
@@ -254,7 +258,7 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        assert_se(set_unit_path(TEST_DIR) >= 0);
+        assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
 
         for (test = tests; test && *test; test++) {
                 int r;
index 1e2e42cbca1713440533d8faf51393895db5bbfb..07273ffe7921422eb60796a5ead7cfc2092959cc 100644 (file)
 
 #include <stdlib.h>
 
-#include "util.h"
-#include "set.h"
+#include "alloc-util.h"
 #include "prioq.h"
+#include "set.h"
 #include "siphash24.h"
+#include "util.h"
 
 #define SET_SIZE 1024*4
 
index eb0f443a4385fc37fabf093da22fed128c6463bf..48be5a3a87e5afd65f96339e2919c55be0a306de 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "process-util.h"
+#include "alloc-util.h"
 #include "log.h"
-#include "util.h"
 #include "macro.h"
-#include "virt.h"
+#include "process-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "util.h"
+#include "virt.h"
 
 static void test_get_process_comm(void) {
         struct stat st;
@@ -53,7 +55,7 @@ static void test_get_process_comm(void) {
         assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
         log_info("pid1 cmdline truncated: '%s'", d);
 
-        assert_se(get_parent_of_pid(1, &e) >= 0);
+        assert_se(get_process_ppid(1, &e) >= 0);
         log_info("pid1 ppid: "PID_FMT, e);
         assert_se(e == 0);
 
index b1d42d77fd95add611f5899d3c9f28404ca0e651..2de2091561d0b7e5a1258539f31b994851b48c55 100644 (file)
 
 #include <string.h>
 
-#include "util.h"
 #include "macro.h"
 #include "replace-var.h"
+#include "string-util.h"
+#include "util.h"
 
 static char *lookup(const char *variable, void *userdata) {
         return strjoin("<<<", variable, ">>>", NULL);
index f5bae65bef26703f677fd105f98c491ecb8dfd3a..b3ccc7509d55f11482e108e8397ca78ba9be4735 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <sys/mman.h>
 
-#include "util.h"
+#include "fd-util.h"
 #include "sigbus.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int fd = -1;
index 2c18090ae55e03aa2d0b097b3b2cec34abbba646..33ff3755bc6d5c66c26b561915305485f2d3a7f4 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "socket-util.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "fd-util.h"
 #include "in-addr-util.h"
-#include "util.h"
-#include "macro.h"
 #include "log.h"
-#include "async.h"
+#include "macro.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
 
 static void test_socket_address_parse(void) {
         SocketAddress a;
@@ -38,28 +41,25 @@ static void test_socket_address_parse(void) {
 
         assert_se(socket_address_parse(&a, "65535") >= 0);
 
-        if (socket_ipv6_is_supported()) {
-                assert_se(socket_address_parse(&a, "[::1]") < 0);
-                assert_se(socket_address_parse(&a, "[::1]8888") < 0);
-                assert_se(socket_address_parse(&a, "::1") < 0);
-                assert_se(socket_address_parse(&a, "[::1]:0") < 0);
-                assert_se(socket_address_parse(&a, "[::1]:65536") < 0);
-                assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0);
+        /* The checks below will pass even if ipv6 is disabled in
+         * kernel. The underlying glibc's inet_pton() is just a string
+         * parser and doesn't make any syscalls. */
 
-                assert_se(socket_address_parse(&a, "8888") >= 0);
-                assert_se(a.sockaddr.sa.sa_family == AF_INET6);
+        assert_se(socket_address_parse(&a, "[::1]") < 0);
+        assert_se(socket_address_parse(&a, "[::1]8888") < 0);
+        assert_se(socket_address_parse(&a, "::1") < 0);
+        assert_se(socket_address_parse(&a, "[::1]:0") < 0);
+        assert_se(socket_address_parse(&a, "[::1]:65536") < 0);
+        assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0);
 
-                assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0);
-                assert_se(a.sockaddr.sa.sa_family == AF_INET6);
+        assert_se(socket_address_parse(&a, "8888") >= 0);
+        assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET));
 
-                assert_se(socket_address_parse(&a, "[::1]:8888") >= 0);
-                assert_se(a.sockaddr.sa.sa_family == AF_INET6);
-        } else {
-                assert_se(socket_address_parse(&a, "[::1]:8888") < 0);
+        assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0);
+        assert_se(a.sockaddr.sa.sa_family == AF_INET6);
 
-                assert_se(socket_address_parse(&a, "8888") >= 0);
-                assert_se(a.sockaddr.sa.sa_family == AF_INET);
-        }
+        assert_se(socket_address_parse(&a, "[::1]:8888") >= 0);
+        assert_se(a.sockaddr.sa.sa_family == AF_INET6);
 
         assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0);
         assert_se(a.sockaddr.sa.sa_family == AF_INET);
index 4ec648ae66c4c5ac91653e910b476f65900d8bd6..1d8eda0c15583122cc1221288db496cf70ecaebb 100644 (file)
@@ -23,6 +23,7 @@
 #include <string.h>
 
 #include "strbuf.h"
+#include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
new file mode 100644 (file)
index 0000000..25444c7
--- /dev/null
@@ -0,0 +1,61 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 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 "string-util.h"
+
+static void test_string_erase(void) {
+        char *x;
+
+        x = strdupa("");
+        assert_se(streq(string_erase(x), ""));
+
+        x = strdupa("1");
+        assert_se(streq(string_erase(x), "x"));
+
+        x = strdupa("12");
+        assert_se(streq(string_erase(x), "xx"));
+
+        x = strdupa("123");
+        assert_se(streq(string_erase(x), "xxx"));
+
+        x = strdupa("1234");
+        assert_se(streq(string_erase(x), "xxxx"));
+
+        x = strdupa("12345");
+        assert_se(streq(string_erase(x), "xxxxx"));
+
+        x = strdupa("123456");
+        assert_se(streq(string_erase(x), "xxxxxx"));
+
+        x = strdupa("1234567");
+        assert_se(streq(string_erase(x), "xxxxxxx"));
+
+        x = strdupa("12345678");
+        assert_se(streq(string_erase(x), "xxxxxxxx"));
+
+        x = strdupa("123456789");
+        assert_se(streq(string_erase(x), "xxxxxxxxx"));
+}
+
+int main(int argc, char *argv[]) {
+        test_string_erase();
+        return 0;
+}
index 6cec8768b115dcba6c1879e594b4e8245ecee767..10fc98ced55b9d4054509909e8fc26b0c216673c 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <stdio.h>
 
-#include "util.h"
+#include "string-util.h"
 #include "terminal-util.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         char *p;
index 623c9265210c1f1b4aeb0e66ce679977b19e3d2d..c27f15283ec91ea4e9455bedda4b56ef8a73c774 100644 (file)
 
 #include <string.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "specifier.h"
+#include "string-util.h"
 #include "strv.h"
+#include "util.h"
 
 static void test_specifier_printf(void) {
         static const Specifier table[] = {
index 858a4081da84c5dd4f0d1ea0562dff74b17fff72..e411d479ab81c3a17228620086b85064490bece5 100644 (file)
@@ -21,8 +21,9 @@
 
 #include <string.h>
 
-#include "util.h"
+#include "string-util.h"
 #include "strxcpyx.h"
+#include "util.h"
 
 static void test_strpcpy(void) {
         char target[25];
index 0e5ab1645fb85a8c2badc93ce2faf6495f92eff9..da27cde3dabfd5735f682a4ad33bbcaf25cfb39f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "architecture.h"
 #include "automount.h"
+#include "bus-xml-policy.h"
+#include "busname.h"
 #include "cgroup.h"
 #include "compress.h"
 #include "condition.h"
 #include "execute.h"
 #include "install.h"
 #include "job.h"
+#include "journald-server.h"
 #include "kill.h"
+#include "link-config.h"
+#include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
 #include "mount.h"
@@ -33,7 +39,6 @@
 #include "scope.h"
 #include "service.h"
 #include "slice.h"
-#include "snapshot.h"
 #include "socket-util.h"
 #include "socket.h"
 #include "swap.h"
 #include "unit-name.h"
 #include "unit.h"
 #include "util.h"
-#include "architecture.h"
-#include "link-config.h"
-#include "bus-xml-policy.h"
-#include "busname.h"
-#include "journald-server.h"
-#include "locale-util.h"
+#include "rlimit-util.h"
 
 #include "test-tables.h"
 
@@ -97,7 +97,6 @@ int main(int argc, char **argv) {
         test_table(service_state, SERVICE_STATE);
         test_table(service_type, SERVICE_TYPE);
         test_table(slice_state, SLICE_STATE);
-        test_table(snapshot_state, SNAPSHOT_STATE);
         test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY);
         test_table(socket_exec_command, SOCKET_EXEC_COMMAND);
         test_table(socket_result, SOCKET_RESULT);
index d81fdb99231fee7d1dd99eeba452ff7b4c2fec6a..e940b5a204ce229d00d63d559b9fd6fc0fc60651 100644 (file)
 #include <stdio.h>
 #include <stdbool.h>
 
-#include "terminal-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
 #include "macro.h"
+#include "terminal-util.h"
 #include "util.h"
-#include "log.h"
 
 static void test_default_term_for_tty(void) {
         puts(default_term_for_tty("/dev/tty23"));
index 3840fff061793cee1e1086ff68b689699dff5f43..820e4aaee25bb3b1c3d16575a35fd813dbbf9bae 100644 (file)
@@ -57,6 +57,28 @@ static void test_parse_sec(void) {
         assert_se(parse_sec(".3 infinity", &u) < 0);
 }
 
+static void test_parse_time(void) {
+        usec_t u;
+
+        assert_se(parse_time("5", &u, 1) >= 0);
+        assert_se(u == 5);
+
+        assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0);
+        assert_se(u == 5 * USEC_PER_MSEC);
+
+        assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0);
+        assert_se(u == 5 * USEC_PER_SEC);
+
+        assert_se(parse_time("5s", &u, 1) >= 0);
+        assert_se(u == 5 * USEC_PER_SEC);
+
+        assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0);
+        assert_se(u == 5 * USEC_PER_SEC);
+
+        assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0);
+        assert_se(u == 5 * USEC_PER_SEC);
+}
+
 static void test_parse_nsec(void) {
         nsec_t u;
 
@@ -161,6 +183,7 @@ static void test_get_timezones(void) {
 
 int main(int argc, char *argv[]) {
         test_parse_sec();
+        test_parse_time();
         test_parse_nsec();
         test_format_timespan(1);
         test_format_timespan(USEC_PER_MSEC);
index 221dd67eb2f139346370cc21bdd68af34f30261b..a8bd722e443c730098bb5605b5ca4e2384a52d32 100644 (file)
 ***/
 
 #include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "string-util.h"
+#include "util.h"
 
 int main(int argc, char** argv) {
         const char *p = argv[1] ?: "/tmp";
index 2b765a3e90412d37f7929e375a5027bb24eea264..9cc64f7c6805affbb2afc299029d97b53d22a44a 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>
-#include <unistd.h>
 #include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <sys/mount.h>
 #include <sys/signalfd.h>
+#include <unistd.h>
 
+#include "fs-util.h"
 #include "missing.h"
 #include "selinux-util.h"
 #include "signal-util.h"
-#include "udev.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "udev.h"
 
 static int fake_filesystems(void) {
         static const struct fakefs {
@@ -42,7 +44,7 @@ static int fake_filesystems(void) {
                 { "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", "/usr/lib/udev/rules.d",  "failed to mount empty /usr/lib/udev/rules.d" },
+                { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" },
         };
         unsigned int i;
         int err;
@@ -64,7 +66,7 @@ static int fake_filesystems(void) {
                 err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
                 if (err < 0) {
                         err = -errno;
-                        fprintf(stderr, "%s %m", fakefss[i].error);
+                        fprintf(stderr, "%s %m\n", fakefss[i].error);
                         return err;
                 }
         }
index bc5baa2fcbe2fee1a570aa87b2439e497509a99f..4dcf10e26db46a59e61f405eb4a5b52dd83c1c38 100644 (file)
 
 #include <stddef.h>
 
-#include "util.h"
+#include "alloc-util.h"
 #include "uid-range.h"
+#include "user-util.h"
+#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_free_ UidRange *p = NULL;
index 8358789e6f00b86defad436bddee1a7de3fc2ada..c3973a316e08a596e0a32c75153e226c90733028 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
+#include <fcntl.h>
 #include <stddef.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/capability.h>
 #include <unistd.h>
-#include <fcntl.h>
 
-#include "install.h"
-#include "install-printf.h"
-#include "specifier.h"
-#include "util.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "hashmap.h"
+#include "hostname-util.h"
+#include "install-printf.h"
+#include "install.h"
 #include "load-fragment.h"
+#include "macro.h"
+#include "specifier.h"
+#include "string-util.h"
 #include "strv.h"
-#include "fileio.h"
 #include "test-helper.h"
-#include "hostname-util.h"
+#include "user-util.h"
+#include "util.h"
 
 static int test_unit_file_get_set(void) {
         int r;
@@ -554,76 +559,215 @@ static void test_load_env_file_5(void) {
 
 static void test_install_printf(void) {
         char    name[] = "name.service",
-                path[] = "/run/systemd/system/name.service",
-                user[] = "xxxx-no-such-user";
-        UnitFileInstallInfo i = {name, path, user};
-        UnitFileInstallInfo i2 = {name, path, NULL};
+                path[] = "/run/systemd/system/name.service";
+        UnitFileInstallInfo i = { .name = name, .path = path, };
+        UnitFileInstallInfo i2 = { .name= name, .path = path, };
         char    name3[] = "name@inst.service",
                 path3[] = "/run/systemd/system/name.service";
-        UnitFileInstallInfo i3 = {name3, path3, user};
-        UnitFileInstallInfo i4 = {name3, path3, NULL};
+        UnitFileInstallInfo i3 = { .name = name3, .path = path3, };
+        UnitFileInstallInfo i4 = { .name = name3, .path = path3, };
 
-        _cleanup_free_ char *mid, *bid, *host;
+        _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL;
 
         assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
         assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
         assert_se((host = gethostname_malloc()));
+        assert_se((user = getusername_malloc()));
+        assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0);
 
 #define expect(src, pattern, result)                                    \
         do {                                                            \
                 _cleanup_free_ char *t = NULL;                          \
                 _cleanup_free_ char                                     \
                         *d1 = strdup(i.name),                           \
-                        *d2 = strdup(i.path),                           \
-                        *d3 = strdup(i.user);                           \
+                        *d2 = strdup(i.path);                           \
                 assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \
                 memzero(i.name, strlen(i.name));                        \
                 memzero(i.path, strlen(i.path));                        \
-                memzero(i.user, strlen(i.user));                        \
-                assert_se(d1 && d2 && d3);                                 \
+                assert_se(d1 && d2);                                    \
                 if (result) {                                           \
                         printf("%s\n", t);                              \
-                        assert_se(streq(t, result));                       \
-                } else assert_se(t == NULL);                               \
+                        assert_se(streq(t, result));                    \
+                } else assert_se(t == NULL);                            \
                 strcpy(i.name, d1);                                     \
                 strcpy(i.path, d2);                                     \
-                strcpy(i.user, d3);                                     \
         } while(false)
 
-        assert_se(setenv("USER", "root", 1) == 0);
-
         expect(i, "%n", "name.service");
         expect(i, "%N", "name");
         expect(i, "%p", "name");
         expect(i, "%i", "");
-        expect(i, "%u", "xxxx-no-such-user");
-
-        DISABLE_WARNING_NONNULL;
-        expect(i, "%U", NULL);
-        REENABLE_WARNING;
+        expect(i, "%u", user);
+        expect(i, "%U", uid);
 
         expect(i, "%m", mid);
         expect(i, "%b", bid);
         expect(i, "%H", host);
 
-        expect(i2, "%u", "root");
-        expect(i2, "%U", "0");
+        expect(i2, "%u", user);
+        expect(i2, "%U", uid);
 
         expect(i3, "%n", "name@inst.service");
         expect(i3, "%N", "name@inst");
         expect(i3, "%p", "name");
-        expect(i3, "%u", "xxxx-no-such-user");
-
-        DISABLE_WARNING_NONNULL;
-        expect(i3, "%U", NULL);
-        REENABLE_WARNING;
+        expect(i3, "%u", user);
+        expect(i3, "%U", uid);
 
         expect(i3, "%m", mid);
         expect(i3, "%b", bid);
         expect(i3, "%H", host);
 
-        expect(i4, "%u", "root");
-        expect(i4, "%U", "0");
+        expect(i4, "%u", user);
+        expect(i4, "%U", uid);
+}
+
+static uint64_t make_cap(int cap) {
+        return ((uint64_t) 1ULL << (uint64_t) cap);
+}
+
+static void test_config_parse_bounding_set(void) {
+        /* int config_parse_bounding_set(
+                 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;
+        uint64_t capability_bounding_set_drop = 0;
+
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "CAP_NET_RAW",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW));
+
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
+
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL));
+
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "~",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
+
+        capability_bounding_set_drop = 0;
+        r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+                              "CapabilityBoundingSet", 0, "  'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
+                              &capability_bounding_set_drop, NULL);
+        assert_se(r >= 0);
+        assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
+}
+
+static void test_config_parse_rlimit(void) {
+        struct rlimit * rl[_RLIMIT_MAX] = {};
+
+        assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_NOFILE]);
+        assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55);
+        assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+
+        assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_NOFILE]);
+        assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY);
+        assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max);
+
+        rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]);
+
+        assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_CPU]);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == 56);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+        assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_CPU]);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == 57);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+        assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_CPU]);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+        assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_CPU]);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == 2);
+        assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max);
+
+        rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]);
+
+        assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_RTTIME]);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+        assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_RTTIME]);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+        assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_RTTIME]);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+        assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0);
+        assert_se(rl[RLIMIT_RTTIME]);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC);
+        assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max);
+
+        rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]);
+}
+
+static void test_config_parse_pass_environ(void) {
+        /* int config_parse_pass_environ(
+                 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;
+        _cleanup_strv_free_ char **passenv = NULL;
+
+        r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
+                              "PassEnvironment", 0, "A B",
+                              &passenv, NULL);
+        assert_se(r >= 0);
+        assert_se(strv_length(passenv) == 2);
+        assert_se(streq(passenv[0], "A"));
+        assert_se(streq(passenv[1], "B"));
+
+        r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
+                              "PassEnvironment", 0, "",
+                              &passenv, NULL);
+        assert_se(r >= 0);
+        assert_se(strv_isempty(passenv));
+
+        r = config_parse_pass_environ(NULL, "fake", 1, "section", 1,
+                              "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\",
+                              &passenv, NULL);
+        assert_se(r >= 0);
+        assert_se(strv_length(passenv) == 1);
+        assert_se(streq(passenv[0], "normal_name"));
+
 }
 
 int main(int argc, char *argv[]) {
@@ -634,6 +778,9 @@ int main(int argc, char *argv[]) {
 
         r = test_unit_file_get_set();
         test_config_parse_exec();
+        test_config_parse_bounding_set();
+        test_config_parse_rlimit();
+        test_config_parse_pass_environ();
         test_load_env_file_1();
         test_load_env_file_2();
         test_load_env_file_3();
index e5405fb7f3b7d139971b40de2cf08ef95292cd6b..842ca40102ca514602289e8cded3febc54c7e7ab 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <pwd.h>
 
+#include "alloc-util.h"
+#include "hostname-util.h"
+#include "macro.h"
 #include "manager.h"
-#include "unit.h"
+#include "path-util.h"
+#include "specifier.h"
+#include "string-util.h"
+#include "test-helper.h"
 #include "unit-name.h"
 #include "unit-printf.h"
-#include "specifier.h"
+#include "unit.h"
+#include "user-util.h"
 #include "util.h"
-#include "macro.h"
-#include "path-util.h"
-#include "test-helper.h"
-#include "hostname-util.h"
 
 static void test_unit_name_is_valid(void) {
         assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
@@ -191,15 +194,15 @@ static int test_unit_printf(void) {
         Unit *u, *u2;
         int r;
 
-        _cleanup_free_ char *mid, *bid, *host, *root_uid;
-        struct passwd *root;
+        _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL;
 
         assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
         assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
-        assert_se((host = gethostname_malloc()));
-
-        assert_se((root = getpwnam("root")));
-        assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0);
+        assert_se(host = gethostname_malloc());
+        assert_se(user = getusername_malloc());
+        assert_se(asprintf(&uid, UID_FMT, getuid()));
+        assert_se(get_home_dir(&home) >= 0);
+        assert_se(get_shell(&shell) >= 0);
 
         r = manager_new(MANAGER_USER, true, &m);
         if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
@@ -220,8 +223,6 @@ static int test_unit_printf(void) {
                         assert_se(streq(t, expected));                     \
         }
 
-        assert_se(setenv("USER", "root", 1) == 0);
-        assert_se(setenv("HOME", "/root", 1) == 0);
         assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
 
         assert_se(u = unit_new(m, sizeof(Service)));
@@ -240,9 +241,9 @@ static int test_unit_printf(void) {
         expect(u, "%p", "blah");
         expect(u, "%P", "blah");
         expect(u, "%i", "");
-        expect(u, "%u", root->pw_name);
-        expect(u, "%U", root_uid);
-        expect(u, "%h", root->pw_dir);
+        expect(u, "%u", user);
+        expect(u, "%U", uid);
+        expect(u, "%h", home);
         expect(u, "%m", mid);
         expect(u, "%b", bid);
         expect(u, "%H", host);
@@ -260,9 +261,9 @@ static int test_unit_printf(void) {
         expect(u2, "%P", "blah");
         expect(u2, "%i", "foo-foo");
         expect(u2, "%I", "foo/foo");
-        expect(u2, "%u", root->pw_name);
-        expect(u2, "%U", root_uid);
-        expect(u2, "%h", root->pw_dir);
+        expect(u2, "%u", user);
+        expect(u2, "%U", uid);
+        expect(u2, "%h", home);
         expect(u2, "%m", mid);
         expect(u2, "%b", bid);
         expect(u2, "%H", host);
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
new file mode 100644 (file)
index 0000000..09d3708
--- /dev/null
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2015 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 "macro.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+static void test_uid_to_name_one(uid_t uid, const char *name) {
+        _cleanup_free_ char *t = NULL;
+
+        assert_se(t = uid_to_name(uid));
+        assert_se(streq_ptr(t, name));
+}
+
+static void test_gid_to_name_one(gid_t gid, const char *name) {
+        _cleanup_free_ char *t = NULL;
+
+        assert_se(t = gid_to_name(gid));
+        assert_se(streq_ptr(t, name));
+}
+
+int main(int argc, char*argv[]) {
+
+        test_uid_to_name_one(0, "root");
+        test_uid_to_name_one(0xFFFF, "65535");
+        test_uid_to_name_one(0xFFFFFFFF, "4294967295");
+
+        test_gid_to_name_one(0, "root");
+        test_gid_to_name_one(TTY_GID, "tty");
+        test_gid_to_name_one(0xFFFF, "65535");
+        test_gid_to_name_one(0xFFFFFFFF, "4294967295");
+
+        return 0;
+}
index 346f8524c620c4fbdda4337b8db4489cbab15d00..0af8349732e052d7641356b4d662f01d8f7d7dac 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "utf8.h"
 #include "util.h"
+#include "string-util.h"
 
 static void test_utf8_is_printable(void) {
         assert_se(utf8_is_printable("ascii is valid\tunicode", 22));
index 503e84080349f4f66c253e66699ee9b64cb133ed..f6ed55878cc383b0e3b58e131f614fd56778b956 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <errno.h>
 #include <fcntl.h>
-#include <locale.h>
-#include <math.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/xattr.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
 #include "def.h"
+#include "escape.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
+#include "fstab-util.h"
+#include "glob-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
 #include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
 #include "process-util.h"
 #include "rm-rf.h"
 #include "signal-util.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
 #include "strv.h"
+#include "user-util.h"
 #include "util.h"
 #include "virt.h"
+#include "web-util.h"
+#include "xattr-util.h"
 
 static void test_streq_ptr(void) {
         assert_se(streq_ptr(NULL, NULL));
@@ -221,63 +236,6 @@ static void test_close_many(void) {
         unlink(name2);
 }
 
-static void test_parse_boolean(void) {
-        assert_se(parse_boolean("1") == 1);
-        assert_se(parse_boolean("y") == 1);
-        assert_se(parse_boolean("Y") == 1);
-        assert_se(parse_boolean("yes") == 1);
-        assert_se(parse_boolean("YES") == 1);
-        assert_se(parse_boolean("true") == 1);
-        assert_se(parse_boolean("TRUE") == 1);
-        assert_se(parse_boolean("on") == 1);
-        assert_se(parse_boolean("ON") == 1);
-
-        assert_se(parse_boolean("0") == 0);
-        assert_se(parse_boolean("n") == 0);
-        assert_se(parse_boolean("N") == 0);
-        assert_se(parse_boolean("no") == 0);
-        assert_se(parse_boolean("NO") == 0);
-        assert_se(parse_boolean("false") == 0);
-        assert_se(parse_boolean("FALSE") == 0);
-        assert_se(parse_boolean("off") == 0);
-        assert_se(parse_boolean("OFF") == 0);
-
-        assert_se(parse_boolean("garbage") < 0);
-        assert_se(parse_boolean("") < 0);
-        assert_se(parse_boolean("full") < 0);
-}
-
-static void test_parse_pid(void) {
-        int r;
-        pid_t pid;
-
-        r = parse_pid("100", &pid);
-        assert_se(r == 0);
-        assert_se(pid == 100);
-
-        r = parse_pid("0x7FFFFFFF", &pid);
-        assert_se(r == 0);
-        assert_se(pid == 2147483647);
-
-        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
-        r = parse_pid("0", &pid);
-        assert_se(r == -ERANGE);
-        assert_se(pid == 65);
-
-        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
-        r = parse_pid("-100", &pid);
-        assert_se(r == -ERANGE);
-        assert_se(pid == 65);
-
-        pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
-        r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
-        assert_se(r == -ERANGE);
-        assert_se(pid == 65);
-
-        r = parse_pid("junk", &pid);
-        assert_se(r == -EINVAL);
-}
-
 static void test_parse_uid(void) {
         int r;
         uid_t uid;
@@ -293,96 +251,6 @@ static void test_parse_uid(void) {
         assert_se(r == -EINVAL);
 }
 
-static void test_safe_atou16(void) {
-        int r;
-        uint16_t l;
-
-        r = safe_atou16("12345", &l);
-        assert_se(r == 0);
-        assert_se(l == 12345);
-
-        r = safe_atou16("123456", &l);
-        assert_se(r == -ERANGE);
-
-        r = safe_atou16("junk", &l);
-        assert_se(r == -EINVAL);
-}
-
-static void test_safe_atoi16(void) {
-        int r;
-        int16_t l;
-
-        r = safe_atoi16("-12345", &l);
-        assert_se(r == 0);
-        assert_se(l == -12345);
-
-        r = safe_atoi16("36536", &l);
-        assert_se(r == -ERANGE);
-
-        r = safe_atoi16("junk", &l);
-        assert_se(r == -EINVAL);
-}
-
-static void test_safe_atolli(void) {
-        int r;
-        long long l;
-
-        r = safe_atolli("12345", &l);
-        assert_se(r == 0);
-        assert_se(l == 12345);
-
-        r = safe_atolli("junk", &l);
-        assert_se(r == -EINVAL);
-}
-
-static void test_safe_atod(void) {
-        int r;
-        double d;
-        char *e;
-
-        r = safe_atod("junk", &d);
-        assert_se(r == -EINVAL);
-
-        r = safe_atod("0.2244", &d);
-        assert_se(r == 0);
-        assert_se(fabs(d - 0.2244) < 0.000001);
-
-        r = safe_atod("0,5", &d);
-        assert_se(r == -EINVAL);
-
-        errno = 0;
-        strtod("0,5", &e);
-        assert_se(*e == ',');
-
-        /* Check if this really is locale independent */
-        if (setlocale(LC_NUMERIC, "de_DE.utf8")) {
-
-                r = safe_atod("0.2244", &d);
-                assert_se(r == 0);
-                assert_se(fabs(d - 0.2244) < 0.000001);
-
-                r = safe_atod("0,5", &d);
-                assert_se(r == -EINVAL);
-
-                errno = 0;
-                assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001);
-        }
-
-        /* And check again, reset */
-        assert_se(setlocale(LC_NUMERIC, "C"));
-
-        r = safe_atod("0.2244", &d);
-        assert_se(r == 0);
-        assert_se(fabs(d - 0.2244) < 0.000001);
-
-        r = safe_atod("0,5", &d);
-        assert_se(r == -EINVAL);
-
-        errno = 0;
-        strtod("0,5", &e);
-        assert_se(*e == ',');
-}
-
 static void test_strappend(void) {
         _cleanup_free_ char *t1, *t2, *t3, *t4;
 
@@ -895,74 +763,6 @@ static void test_protect_errno(void) {
         assert_se(errno == 12);
 }
 
-static void test_parse_size(void) {
-        uint64_t bytes;
-
-        assert_se(parse_size("111", 1024, &bytes) == 0);
-        assert_se(bytes == 111);
-
-        assert_se(parse_size("111.4", 1024, &bytes) == 0);
-        assert_se(bytes == 111);
-
-        assert_se(parse_size(" 112 B", 1024, &bytes) == 0);
-        assert_se(bytes == 112);
-
-        assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0);
-        assert_se(bytes == 112);
-
-        assert_se(parse_size("3.5 K", 1024, &bytes) == 0);
-        assert_se(bytes == 3*1024 + 512);
-
-        assert_se(parse_size("3. K", 1024, &bytes) == 0);
-        assert_se(bytes == 3*1024);
-
-        assert_se(parse_size("3.0 K", 1024, &bytes) == 0);
-        assert_se(bytes == 3*1024);
-
-        assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0);
-        assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512);
-
-        assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("3.5G3B", 1024, &bytes) == 0);
-        assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3);
-
-        assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0);
-        assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4);
-
-        assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("4T3G3B", 1024, &bytes) == 0);
-        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
-
-        assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0);
-        assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
-
-        assert_se(parse_size("12P", 1024, &bytes) == 0);
-        assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
-
-        assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("3E 2P", 1024, &bytes) == 0);
-        assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
-
-        assert_se(parse_size("12X", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL);
-
-        assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE);
-        assert_se(parse_size("-1", 1024, &bytes) == -ERANGE);
-        assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE);
-
-        assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE);
-
-        assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
-}
-
 static void test_parse_cpu_set(void) {
         cpu_set_t *c = NULL;
         int ncpus;
@@ -996,19 +796,76 @@ static void test_parse_cpu_set(void) {
 
         /* Use commas as separators */
         ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
-        assert_se(ncpus < 0);
-        assert_se(!c);
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+        for (cpu = 0; cpu < 4; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        for (cpu = 8; cpu < 12; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
+
+        /* Commas with spaces (and trailing comma, space) */
+        ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+        for (cpu = 0; cpu < 8; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
 
         /* Ranges */
         ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
-        assert_se(ncpus < 0);
-        assert_se(!c);
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+        for (cpu = 0; cpu < 4; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        for (cpu = 8; cpu < 12; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
+
+        /* Ranges with trailing comma, space */
+        ncpus = parse_cpu_set_and_warn("0-3  8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+        for (cpu = 0; cpu < 4; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        for (cpu = 8; cpu < 12; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
+
+        /* Negative range (returns empty cpu_set) */
+        ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
+        c = mfree(c);
+
+        /* Overlapping ranges */
+        ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
+        for (cpu = 0; cpu < 12; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
+
+        /* Mix ranges and individual CPUs */
+        ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus >= 1024);
+        assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
+        assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
+        assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
+        for (cpu = 4; cpu < 12; cpu++)
+                assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+        c = mfree(c);
 
         /* Garbage */
         ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
         assert_se(ncpus < 0);
         assert_se(!c);
 
+        /* Range with garbage */
+        ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
+        assert_se(ncpus < 0);
+        assert_se(!c);
+
         /* Empty string */
         c = NULL;
         ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
@@ -1554,507 +1411,6 @@ static void test_execute_directory(void) {
         (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
 }
 
-static void test_extract_first_word(void) {
-        const char *p, *original;
-        char *t;
-
-        p = original = "foobar waldo";
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "foobar"));
-        free(t);
-        assert_se(p == original + 7);
-
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"foobar\" \'waldo\'";
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "\"foobar\""));
-        free(t);
-        assert_se(p == original + 9);
-
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "\'waldo\'"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"foobar\" \'waldo\'";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
-        assert_se(streq(t, "foobar"));
-        free(t);
-        assert_se(p == original + 9);
-
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"";
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
-        assert_se(streq(t, "\""));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\"";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
-        assert_se(p == original + 1);
-
-        p = original = "\'";
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
-        assert_se(streq(t, "\'"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\'";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
-        assert_se(p == original + 1);
-
-        p = original = "\'fooo";
-        assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
-        assert_se(streq(t, "\'fooo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\'fooo";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\'fooo";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "fooo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "yay\'foo\'bar";
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "yay\'foo\'bar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "yay\'foo\'bar";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
-        assert_se(streq(t, "yayfoobar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "   foobar   ";
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "foobar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = " foo\\ba\\x6ar ";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
-        assert_se(streq(t, "foo\ba\x6ar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = " foo\\ba\\x6ar ";
-        assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
-        assert_se(streq(t, "foobax6ar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "    f\\u00f6o \"pi\\U0001F4A9le\"   ";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
-        assert_se(streq(t, "föo"));
-        free(t);
-        assert_se(p == original + 13);
-
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0);
-        assert_se(streq(t, "pi\360\237\222\251le"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "fooo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "fooo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "fooo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "fooo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "foo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "foo::bar";
-        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
-        assert_se(streq(t, "foo"));
-        free(t);
-        assert_se(p == original + 5);
-
-        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
-        assert_se(streq(t, "bar"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word(&p, &t, ":", 0) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "foo\\:bar::waldo";
-        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
-        assert_se(streq(t, "foo:bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        assert_se(extract_first_word(&p, &t, ":", 0) == 1);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word(&p, &t, ":", 0) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "foo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "foo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "fooo bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "fooo bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
-        assert_se(streq(t, "fooo bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "fooo\\ bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "\\w+@\\K[\\d.]+";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
-        assert_se(p == original + 1);
-
-        p = original = "\\w+@\\K[\\d.]+";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "\\w+@\\K[\\d.]+"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\\w+\\b";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
-        assert_se(streq(t, "\\w+\b"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "-N ''";
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
-        assert_se(streq(t, "-N"));
-        free(t);
-        assert_se(p == original + 3);
-
-        assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
-        assert_se(streq(t, ""));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = ":foo\\:bar::waldo:";
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
-        assert_se(t);
-        assert_se(streq(t, ""));
-        free(t);
-        assert_se(p == original + 1);
-
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
-        assert_se(streq(t, "foo:bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
-        assert_se(t);
-        assert_se(streq(t, ""));
-        free(t);
-        assert_se(p == original + 11);
-
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(p == original + 17);
-
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
-        assert_se(streq(t, ""));
-        free(t);
-        assert_se(p == NULL);
-
-        assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
-        assert_se(!t);
-        assert_se(!p);
-}
-
-static void test_extract_first_word_and_warn(void) {
-        const char *p, *original;
-        char *t;
-
-        p = original = "foobar waldo";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foobar"));
-        free(t);
-        assert_se(p == original + 7);
-
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"foobar\" \'waldo\'";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foobar"));
-        free(t);
-        assert_se(p == original + 9);
-
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "waldo"));
-        free(t);
-        assert_se(isempty(p));
-
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
-        assert_se(!t);
-        assert_se(isempty(p));
-
-        p = original = "\"";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
-        assert_se(p == original + 1);
-
-        p = original = "\'";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
-        assert_se(p == original + 1);
-
-        p = original = "\'fooo";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\'fooo";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = " foo\\ba\\x6ar ";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foo\ba\x6ar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = " foo\\ba\\x6ar ";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foobax6ar"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "    f\\u00f6o \"pi\\U0001F4A9le\"   ";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "föo"));
-        free(t);
-        assert_se(p == original + 13);
-
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "pi\360\237\222\251le"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo\\"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
-        assert_se(p == original + 5);
-
-        p = original = "\"foo\\";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "foo"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "fooo\\ bar quux";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "fooo\\ bar"));
-        free(t);
-        assert_se(p == original + 10);
-
-        p = original = "\\w+@\\K[\\d.]+";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "\\w+@\\K[\\d.]+"));
-        free(t);
-        assert_se(isempty(p));
-
-        p = original = "\\w+\\b";
-        assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
-        assert_se(streq(t, "\\w+\b"));
-        free(t);
-        assert_se(isempty(p));
-}
-
-static void test_extract_many_words(void) {
-        const char *p, *original;
-        char *a, *b, *c;
-
-        p = original = "foobar waldi piep";
-        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, "foobar"));
-        assert_se(streq_ptr(b, "waldi"));
-        assert_se(streq_ptr(c, "piep"));
-        free(a);
-        free(b);
-        free(c);
-
-        p = original = "'foobar' wa\"ld\"i   ";
-        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, "'foobar'"));
-        assert_se(streq_ptr(b, "wa\"ld\"i"));
-        assert_se(streq_ptr(c, NULL));
-        free(a);
-        free(b);
-
-        p = original = "'foobar' wa\"ld\"i   ";
-        assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, "foobar"));
-        assert_se(streq_ptr(b, "waldi"));
-        assert_se(streq_ptr(c, NULL));
-        free(a);
-        free(b);
-
-        p = original = "";
-        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, NULL));
-        assert_se(streq_ptr(b, NULL));
-        assert_se(streq_ptr(c, NULL));
-
-        p = original = "  ";
-        assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, NULL));
-        assert_se(streq_ptr(b, NULL));
-        assert_se(streq_ptr(c, NULL));
-
-        p = original = "foobar";
-        assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
-        assert_se(p == original);
-
-        p = original = "foobar waldi";
-        assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
-        assert_se(p == original+7);
-        assert_se(streq_ptr(a, "foobar"));
-        free(a);
-
-        p = original = "     foobar    ";
-        assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
-        assert_se(isempty(p));
-        assert_se(streq_ptr(a, "foobar"));
-        free(a);
-}
-
 static int parse_item(const char *key, const char *value) {
         assert_se(key);
 
@@ -2203,20 +1559,6 @@ static void test_shell_maybe_quote(void) {
         test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
 }
 
-static void test_parse_mode(void) {
-        mode_t m;
-
-        assert_se(parse_mode("-1", &m) < 0);
-        assert_se(parse_mode("", &m) < 0);
-        assert_se(parse_mode("888", &m) < 0);
-        assert_se(parse_mode("77777", &m) < 0);
-
-        assert_se(parse_mode("544", &m) >= 0 && m == 0544);
-        assert_se(parse_mode("777", &m) >= 0 && m == 0777);
-        assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
-        assert_se(parse_mode("0", &m) >= 0 && m == 0);
-}
-
 static void test_tempfn(void) {
         char *ret = NULL, *p;
 
@@ -2297,6 +1639,12 @@ cleanup:
         assert_se(rmdir(t) >= 0);
 }
 
+static void test_runlevel_to_target(void) {
+        assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
+        assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
+        assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET));
+}
+
 int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
@@ -2309,13 +1657,7 @@ int main(int argc, char *argv[]) {
         test_div_round_up();
         test_first_word();
         test_close_many();
-        test_parse_boolean();
-        test_parse_pid();
         test_parse_uid();
-        test_safe_atou16();
-        test_safe_atoi16();
-        test_safe_atolli();
-        test_safe_atod();
         test_strappend();
         test_strstrip();
         test_delete_chars();
@@ -2342,7 +1684,6 @@ int main(int argc, char *argv[]) {
         test_memdup_multiply();
         test_u64log2();
         test_protect_errno();
-        test_parse_size();
         test_parse_cpu_set();
         test_config_parse_iec_uint64();
         test_strextend();
@@ -2374,9 +1715,6 @@ int main(int argc, char *argv[]) {
         test_search_and_fopen_nulstr();
         test_glob_exists();
         test_execute_directory();
-        test_extract_first_word();
-        test_extract_first_word_and_warn();
-        test_extract_many_words();
         test_parse_proc_cmdline();
         test_raw_clone();
         test_same_fd();
@@ -2384,10 +1722,10 @@ int main(int argc, char *argv[]) {
         test_sparse_write();
         test_shell_escape();
         test_shell_maybe_quote();
-        test_parse_mode();
         test_tempfn();
         test_strcmp_ptr();
         test_fgetxattrat_fake();
+        test_runlevel_to_target();
 
         return 0;
 }
index ea109fbde0c57cc599709342fd1ae5e1b96e22e6..548d75a3c302aee0f9aabd208b880ae0a00f0938 100644 (file)
 
 #include <stdarg.h>
 
-#include "xml.h"
+#include "alloc-util.h"
+#include "string-util.h"
 #include "util.h"
+#include "xml.h"
 
 static void test_one(const char *data, ...) {
         void *state = NULL;
index 68fbe3f5b85a8323509d61b52960edfd83778581..564d72773a2e725d5429d2cd649a73e533e438d9 100644 (file)
@@ -30,6 +30,7 @@
 #include "bus-error.h"
 #include "bus-util.h"
 #include "pager.h"
+#include "parse-util.h"
 #include "spawn-polkit-agent.h"
 #include "strv.h"
 #include "terminal-util.h"
index 6de9e246f65e364f03708986085b8fe861b279f2..968ef8a7880f5fd88bcc78dba154b0174209fbc2 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
-#include "sd-messages.h"
-#include "sd-event.h"
 #include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-messages.h"
 
-#include "util.h"
-#include "strv.h"
-#include "def.h"
-#include "clock-util.h"
-#include "path-util.h"
-#include "fileio-label.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "alloc-util.h"
 #include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "clock-util.h"
+#include "def.h"
 #include "event-util.h"
+#include "fileio-label.h"
+#include "fs-util.h"
+#include "path-util.h"
 #include "selinux-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
 
 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
index 28ad378a9383f9fec2178d5769ecf1f3ca28291f..5881bc0c452c2437c4910471b9747208037f5e48 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-
+#include "alloc-util.h"
+#include "def.h"
+#include "extract-word.h"
+#include "string-util.h"
+#include "timesyncd-conf.h"
 #include "timesyncd-manager.h"
 #include "timesyncd-server.h"
-#include "timesyncd-conf.h"
 
 int manager_parse_server_string(Manager *m, ServerType type, const char *string) {
-        const char *word, *state;
-        size_t length;
         ServerName *first;
         int r;
 
@@ -35,17 +36,20 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
 
         first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers;
 
-        FOREACH_WORD_QUOTED(word, length, string, state) {
-                char buffer[length+1];
+        for (;;) {
+                _cleanup_free_ char *word = NULL;
                 bool found = false;
                 ServerName *n;
 
-                memcpy(buffer, word, length);
-                buffer[length] = 0;
+                r = extract_first_word(&string, &word, NULL, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to parse timesyncd server syntax \"%s\": %m", string);
+                if (r == 0)
+                        break;
 
                 /* Filter out duplicates */
                 LIST_FOREACH(names, n, first)
-                        if (streq_ptr(n->string, buffer)) {
+                        if (streq_ptr(n->string, word)) {
                                 found = true;
                                 break;
                         }
@@ -53,7 +57,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
                 if (found)
                         continue;
 
-                r = server_name_new(m, NULL, type, buffer);
+                r = server_name_new(m, NULL, type, word);
                 if (r < 0)
                         return r;
         }
@@ -96,8 +100,8 @@ int config_parse_servers(
 int manager_parse_config_file(Manager *m) {
         assert(m);
 
-        return config_parse_many("/etc/systemd/timesyncd.conf",
-                                 CONF_DIRS_NULSTR("systemd/timesyncd.conf"),
+        return config_parse_many(PKGSYSCONFDIR "/timesyncd.conf",
+                                 CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"),
                                  "Time\0",
                                  config_item_perf_lookup, timesyncd_gperf_lookup,
                                  false, m);
index 40e0fd31fedf0918b3d355dc83e4ac46139c20a1..8dca538b3bb2d2306466808eb10592705499f6c0 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <errno.h>
-#include <time.h>
 #include <math.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <sys/socket.h>
 #include <sys/timerfd.h>
 #include <sys/timex.h>
-#include <sys/socket.h>
-#include <resolv.h>
 #include <sys/types.h>
+#include <time.h>
 
-#include "missing.h"
-#include "util.h"
-#include "sparse-endian.h"
-#include "log.h"
-#include "socket-util.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "list.h"
+#include "log.h"
+#include "missing.h"
+#include "network-util.h"
 #include "ratelimit.h"
+#include "socket-util.h"
+#include "sparse-endian.h"
+#include "string-util.h"
 #include "strv.h"
-#include "sd-daemon.h"
-#include "network-util.h"
+#include "time-util.h"
 #include "timesyncd-conf.h"
 #include "timesyncd-manager.h"
-#include "time-util.h"
+#include "util.h"
 
 #ifndef ADJ_SETOFFSET
 #define ADJ_SETOFFSET                   0x0100  /* add 'time' to current time */
@@ -365,7 +370,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
 
         r = clock_adjtime(CLOCK_REALTIME, &tmx);
         if (r < 0)
-                return r;
+                return -errno;
 
         touch("/var/lib/systemd/clock");
 
@@ -662,7 +667,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
                 m->sync = true;
                 r = manager_adjust_clock(m, offset, leap_sec);
                 if (r < 0)
-                        log_error_errno(errno, "Failed to call clock_adjtime(): %m");
+                        log_error_errno(r, "Failed to call clock_adjtime(): %m");
         }
 
         log_debug("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s",
index ec3fe1fc4e891b8e8ce958715c2fa1c57d83d5c7..f98e6b4cf0052eefde2a008f02a93cb2e737e797 100644 (file)
@@ -19,6 +19,7 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "timesyncd-server.h"
 
 int server_address_new(
index 3cb7d435cd5a08e9873718727824f4ad33ee8af1..7f70eaaea0f8d93a421d54dd1e1693bae5e8ce02 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "sd-event.h"
 #include "sd-daemon.h"
-#include "capability.h"
+#include "sd-event.h"
+
+#include "capability-util.h"
 #include "clock-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
 #include "network-util.h"
 #include "signal-util.h"
-
-#include "timesyncd-manager.h"
 #include "timesyncd-conf.h"
+#include "timesyncd-manager.h"
+#include "user-util.h"
 
 static int load_clock_timestamp(uid_t uid, gid_t gid) {
         _cleanup_close_ int fd = -1;
@@ -57,12 +60,12 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
 
                 /* Try to fix the access mode, so that we can still
                    touch the file after dropping priviliges */
-                fchmod(fd, 0644);
-                fchown(fd, uid, gid);
+                (void) fchmod(fd, 0644);
+                (void) fchown(fd, uid, gid);
 
         } else
                 /* create stamp file with the compiled-in date */
-                touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
+                (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
 
         ct = now(CLOCK_REALTIME);
         if (ct < min) {
@@ -150,7 +153,7 @@ int main(int argc, char *argv[]) {
 
         /* if we got an authoritative time, store it in the file system */
         if (m->sync)
-                touch("/var/lib/systemd/clock");
+                (void) touch("/var/lib/systemd/clock");
 
         sd_event_get_exit_code(m->event, &r);
 
index d219764bc69a2ff71a294f4d668076c9b0605c4c..74b6b91593d7b9b2fdfa48b553162b4da344116a 100644 (file)
 #include <unistd.h>
 
 #include "acl-util.h"
+#include "alloc-util.h"
 #include "btrfs-util.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "chattr-util.h"
 #include "conf-files.h"
 #include "copy.h"
+#include "def.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
 #include "label.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
 #include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "selinux-util.h"
 #include "set.h"
 #include "specifier.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
 #include "strv.h"
+#include "umask-util.h"
+#include "user-util.h"
 #include "util.h"
 
 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
@@ -69,6 +86,8 @@ typedef enum ItemType {
         CREATE_DIRECTORY = 'd',
         TRUNCATE_DIRECTORY = 'D',
         CREATE_SUBVOLUME = 'v',
+        CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
+        CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
         CREATE_FIFO = 'p',
         CREATE_SYMLINK = 'L',
         CREATE_CHAR_DEVICE = 'c',
@@ -140,7 +159,7 @@ static char **arg_include_prefixes = NULL;
 static char **arg_exclude_prefixes = NULL;
 static char *arg_root = NULL;
 
-static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
+static const char conf_file_dirs[] = CONF_PATHS_NULSTR("tmpfiles.d");
 
 #define MAX_DEPTH 256
 
@@ -180,6 +199,8 @@ static bool takes_ownership(ItemType t) {
                       CREATE_DIRECTORY,
                       TRUNCATE_DIRECTORY,
                       CREATE_SUBVOLUME,
+                      CREATE_SUBVOLUME_INHERIT_QUOTA,
+                      CREATE_SUBVOLUME_NEW_QUOTA,
                       CREATE_FIFO,
                       CREATE_SYMLINK,
                       CREATE_CHAR_DEVICE,
@@ -1198,16 +1219,16 @@ static int create_item(Item *i) {
         case CREATE_DIRECTORY:
         case TRUNCATE_DIRECTORY:
         case CREATE_SUBVOLUME:
+        case CREATE_SUBVOLUME_INHERIT_QUOTA:
+        case CREATE_SUBVOLUME_NEW_QUOTA:
 
                 RUN_WITH_UMASK(0000)
                         mkdir_parents_label(i->path, 0755);
 
-                if (i->type == CREATE_SUBVOLUME)
-                        RUN_WITH_UMASK((~i->mode) & 0777) {
+                if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
+                        RUN_WITH_UMASK((~i->mode) & 0777)
                                 r = btrfs_subvol_make(i->path);
-                                log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
-                        }
-                else
+                } else
                         r = 0;
 
                 if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
@@ -1236,6 +1257,28 @@ static int create_item(Item *i) {
 
                 log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
 
+                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);
+                                return 0;
+                        }
+                        if (r == -EROFS) {
+                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
+                                return 0;
+                        }
+                        if (r == -ENOPROTOOPT) {
+                                log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path);
+                                return 0;
+                        }
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
+                        if (r > 0)
+                                log_debug("Adjusted quota for subvolume \"%s\".", i->path);
+                        if (r == 0)
+                                log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
+                }
+
                 r = path_set_perms(i, i->path);
                 if (r < 0)
                         return r;
@@ -1492,6 +1535,8 @@ static int remove_item(Item *i) {
         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:
@@ -1561,8 +1606,7 @@ static int clean_item_instance(Item *i, const char* instance) {
         if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
                 return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
 
-        mountpoint = s.st_dev != ps.st_dev ||
-                     (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
+        mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
 
         log_debug("Cleanup threshold for %s \"%s\" is %s",
                   mountpoint ? "mount point" : "directory",
@@ -1583,6 +1627,8 @@ static int clean_item(Item *i) {
         switch (i->type) {
         case CREATE_DIRECTORY:
         case CREATE_SUBVOLUME:
+        case CREATE_SUBVOLUME_INHERIT_QUOTA:
+        case CREATE_SUBVOLUME_NEW_QUOTA:
         case TRUNCATE_DIRECTORY:
         case IGNORE_PATH:
         case COPY_FILES:
@@ -1819,6 +1865,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         case CREATE_DIRECTORY:
         case CREATE_SUBVOLUME:
+        case CREATE_SUBVOLUME_INHERIT_QUOTA:
+        case CREATE_SUBVOLUME_NEW_QUOTA:
         case TRUNCATE_DIRECTORY:
         case CREATE_FIFO:
         case IGNORE_PATH:
@@ -1983,8 +2031,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 i.mode = m;
                 i.mode_set = true;
         } else
-                i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
-                        ? 0755 : 0644;
+                i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
 
         if (!isempty(age) && !streq(age, "-")) {
                 const char *a = age;
@@ -2075,7 +2122,7 @@ static int parse_argv(int argc, char *argv[]) {
                 {}
         };
 
-        int c;
+        int c, r;
 
         assert(argc >= 0);
         assert(argv);
@@ -2118,12 +2165,9 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        free(arg_root);
-                        arg_root = path_make_absolute_cwd(optarg);
-                        if (!arg_root)
-                                return log_oom();
-
-                        path_kill_slashes(arg_root);
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case '?':
@@ -2186,7 +2230,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
                         continue;
 
                 ORDERED_HASHMAP_FOREACH(j, items, iter) {
-                        if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
+                        if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
                                 continue;
 
                         if (path_equal(j->path, i->path)) {
index 93cce186f06f0f19211e9156e76f3fc8d2e6c7e1..8cfe10330d5e077148d896d0434817c701595676 100644 (file)
 #include <sys/un.h>
 #include <unistd.h>
 
+#include "alloc-util.h"
 #include "ask-password-api.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "util.h"
@@ -120,23 +125,30 @@ static int ask_password_plymouth(
 
                         y = now(CLOCK_MONOTONIC);
 
-                        if (y > until)
-                                return -ETIME;
+                        if (y > until) {
+                                r = -ETIME;
+                                goto finish;
+                        }
 
                         sleep_for = (int) ((until - y) / USEC_PER_MSEC);
                 }
 
-                if (flag_file && access(flag_file, F_OK) < 0)
-                        return -errno;
+                if (flag_file && access(flag_file, F_OK) < 0) {
+                        r = -errno;
+                        goto finish;
+                }
 
                 j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
                 if (j < 0) {
                         if (errno == EINTR)
                                 continue;
 
-                        return -errno;
-                } else if (j == 0)
-                        return -ETIME;
+                        r = -errno;
+                        goto finish;
+                } else if (j == 0) {
+                        r = -ETIME;
+                        goto finish;
+                }
 
                 if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
                         flush_fd(notify);
@@ -149,9 +161,12 @@ static int ask_password_plymouth(
                         if (errno == EINTR || errno == EAGAIN)
                                 continue;
 
-                        return -errno;
-                } else if (k == 0)
-                        return -EIO;
+                        r = -errno;
+                        goto finish;
+                } else if (k == 0) {
+                        r = -EIO;
+                        goto finish;
+                }
 
                 p += k;
 
@@ -166,12 +181,14 @@ static int ask_password_plymouth(
                                  * with a normal password request */
                                 packet = mfree(packet);
 
-                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
-                                        return -ENOMEM;
+                                if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
 
                                 r = loop_write(fd, packet, n+1, true);
                                 if (r < 0)
-                                        return r;
+                                        goto finish;
 
                                 flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
                                 p = 0;
@@ -179,7 +196,8 @@ static int ask_password_plymouth(
                         }
 
                         /* No password, because UI not shown */
-                        return -ENOENT;
+                        r = -ENOENT;
+                        goto finish;
 
                 } else if (buffer[0] == 2 || buffer[0] == 9) {
                         uint32_t size;
@@ -191,32 +209,43 @@ static int ask_password_plymouth(
 
                         memcpy(&size, buffer+1, sizeof(size));
                         size = le32toh(size);
-                        if (size + 5 > sizeof(buffer))
-                                return -EIO;
+                        if (size + 5 > sizeof(buffer)) {
+                                r = -EIO;
+                                goto finish;
+                        }
 
                         if (p-5 < size)
                                 continue;
 
                         l = strv_parse_nulstr(buffer + 5, size);
-                        if (!l)
-                                return -ENOMEM;
+                        if (!l) {
+                                r = -ENOMEM;
+                                goto finish;
+                        }
 
                         *ret = l;
                         break;
 
-                } else
+                } else {
                         /* Unknown packet */
-                        return -EIO;
+                        r = -EIO;
+                        goto finish;
+                }
         }
 
-        return 0;
+        r = 0;
+
+finish:
+        memory_erase(buffer, sizeof(buffer));
+        return r;
 }
 
 static int parse_password(const char *filename, char **wall) {
         _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL;
+        bool accept_cached = false, echo = false;
+        size_t packet_length = 0;
         uint64_t not_after = 0;
         unsigned pid = 0;
-        bool accept_cached = false, echo = false;
 
         const ConfigTableItem items[] = {
                 { "Ask", "Socket",       config_parse_string,   0, &socket_name   },
@@ -270,7 +299,6 @@ static int parse_password(const char *filename, char **wall) {
 
         } else {
                 union sockaddr_union sa = {};
-                size_t packet_length = 0;
                 _cleanup_close_ int socket_fd = -1;
 
                 assert(arg_action == ACTION_QUERY ||
@@ -284,7 +312,7 @@ static int parse_password(const char *filename, char **wall) {
                 }
 
                 if (arg_plymouth) {
-                        _cleanup_strv_free_ char **passwords = NULL;
+                        _cleanup_strv_free_erase_ char **passwords = NULL;
 
                         r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords);
                         if (r >= 0) {
@@ -308,7 +336,7 @@ static int parse_password(const char *filename, char **wall) {
                         }
 
                 } else {
-                        _cleanup_free_ char *password = NULL;
+                        _cleanup_string_free_erase_ char *password = NULL;
                         int tty_fd = -1;
 
                         if (arg_console) {
@@ -340,26 +368,36 @@ static int parse_password(const char *filename, char **wall) {
                         }
                 }
 
-                if (IN_SET(r, -ETIME, -ENOENT))
+                if (IN_SET(r, -ETIME, -ENOENT)) {
                         /* If the query went away, that's OK */
-                        return 0;
-
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query password: %m");
+                        r = 0;
+                        goto finish;
+                }
+                if (r < 0) {
+                        log_error_errno(r, "Failed to query password: %m");
+                        goto finish;
+                }
 
                 socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-                if (socket_fd < 0)
-                        return log_error_errno(errno, "socket(): %m");
+                if (socket_fd < 0) {
+                        r = log_error_errno(errno, "socket(): %m");
+                        goto finish;
+                }
 
                 sa.un.sun_family = AF_UNIX;
                 strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
 
                 r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+                memory_erase(packet, packet_length);
                 if (r < 0)
                         return log_error_errno(errno, "Failed to send: %m");
         }
 
         return 0;
+
+finish:
+        memory_erase(packet, packet_length);
+        return r;
 }
 
 static int wall_tty_block(void) {
@@ -381,7 +419,7 @@ static int wall_tty_block(void) {
 
         fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
         if (fd < 0)
-                return log_error_errno(errno, "Failed to open %s: %m", p);
+                return log_debug_errno(errno, "Failed to open %s: %m", p);
 
         return fd;
 }
@@ -437,7 +475,7 @@ static int show_passwords(void) {
                 if (errno == ENOENT)
                         return 0;
 
-                return log_error_errno(errno, "Failed top open /run/systemd/ask-password: %m");
+                return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m");
         }
 
         FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) {
index ba112ce218dade8105f9923878e216f515a49d28..f5d8be3dc1a71827731b769dc4db86ae1d78715c 100644 (file)
@@ -1,5 +1,4 @@
 /udev.pc
 /keyboard-keys-from-name.gperf
 /keyboard-keys-from-name.h
-/keyboard-keys-to-name.h
 /keyboard-keys-list.txt
index 1d1798dd10f2a4ef7ba77e869a30d6a156ae29d4..1e414664ce74bc12551fef57ad4711d789be522a 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <ctype.h>
-#include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
+#include <linux/bsg.h>
+#include <linux/hdreg.h>
 #include <scsi/scsi.h>
-#include <scsi/sg.h>
 #include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
-#include <sys/types.h>
 #include <sys/stat.h>
-#include <linux/hdreg.h>
-#include <linux/bsg.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
+#include "fd-util.h"
 #include "libudev-private.h"
-#include "udev-util.h"
 #include "log.h"
+#include "udev-util.h"
 
 #define COMMAND_TIMEOUT_MSEC (30 * 1000)
 
index 001bae7a245ddcda497b48045774a97f164f3fce..72f284f71082cf51da598a0da1db88f8c53ed412 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
-#include <time.h>
+#include <limits.h>
+#include <linux/cdrom.h>
 #include <scsi/sg.h>
-#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
 #include "libudev-private.h"
 #include "random-util.h"
 
index b3a1f0bca1f987ff934ea8a3b17b5c6ae8a493b3..b6c95cd4524e08a8a89f12873cc9e5b8d247a181 100644 (file)
  *
  */
 
-#include <stdio.h>
-#include <stddef.h>
 #include <errno.h>
 #include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
 
+#include "alloc-util.h"
 #include "libudev-private.h"
 #include "macro.h"
+#include "string-util.h"
 
 #define BUFSIZE 16
 #define UDEV_ALARM_TIMEOUT 180
index a4b05d1becd5a6b261ef67fbe6e05bca59924fb4..0647008d90df2810c7dbac425f3372f42dc5817e 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <sys/ioctl.h>
 #include <net/if.h>
+#include <sys/ioctl.h>
 #include <linux/ethtool.h>
 #include <linux/sockios.h>
 
+#include "conf-parser.h"
 #include "ethtool-util.h"
-
+#include "log.h"
+#include "string-table.h"
 #include "strxcpyx.h"
 #include "util.h"
-#include "log.h"
-#include "conf-parser.h"
 
 static const char* const duplex_table[_DUP_MAX] = {
         [DUP_FULL] = "full",
index 4b8c5053a4f25f8e7362c09707604723770a8068..776674e9945369e822beaa23b1d1ceacabb7d5a3 100644 (file)
 #include <netinet/ether.h>
 #include <linux/netdevice.h>
 
+#include "sd-netlink.h"
 
-#include "missing.h"
-#include "link-config.h"
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "conf-parser.h"
 #include "ethtool-util.h"
-
+#include "fd-util.h"
 #include "libudev-private.h"
-#include "sd-netlink.h"
-#include "util.h"
+#include "link-config.h"
 #include "log.h"
-#include "strv.h"
-#include "path-util.h"
-#include "conf-parser.h"
-#include "conf-files.h"
+#include "missing.h"
 #include "netlink-util.h"
 #include "network-internal.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
 #include "random-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
 
 struct link_config_ctx {
         LIST_HEAD(link_config, links);
index c52db2ce5549f044d1daf7ccdcb3d269e6c03c05..4fcbee8b926c18a605f35499d74804bf117a0a73 100644 (file)
 
 #pragma once
 
-#include "ethtool-util.h"
+#include "libudev.h"
+
 #include "condition.h"
+#include "ethtool-util.h"
 #include "list.h"
-#include "libudev.h"
 
 typedef struct link_config_ctx link_config_ctx;
 typedef struct link_config link_config;
index adb91869df0be7403daad3f5eb4d1ebcfad8391a..46556916429b6352424b34e7e880332003e0ae56 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
-#include <getopt.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
+#include "fd-util.h"
 #include "libudev-private.h"
 #include "scsi_id.h"
+#include "string-util.h"
 #include "udev-util.h"
 
 static const struct option options[] = {
index de3b4f75816635afdaa39b960668dc185eabe897..c7ef783684b88ac8d744dde0bfd89e907df018c6 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <stdio.h>
 #include <errno.h>
-#include <string.h>
 #include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
 #include <inttypes.h>
+#include <linux/bsg.h>
+#include <linux/types.h>
 #include <scsi/scsi.h>
 #include <scsi/sg.h>
-#include <linux/types.h>
-#include <linux/bsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
 #include "libudev.h"
+
 #include "libudev-private.h"
+#include "random-util.h"
 #include "scsi.h"
 #include "scsi_id.h"
-#include "random-util.h"
+#include "string-util.h"
 
 /*
  * A priority based list of id, naa, and binary/ascii for the identifier
index b8066ea6e9c40fef5be6987a2fbd3c9be657b7f0..d0e47ec6d888ae217f7b1ffbf07a1c2f844ed346 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <blkid/blkid.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/stat.h>
-#include <blkid/blkid.h>
 
 #include "sd-id128.h"
-#include "gpt.h"
+
+#include "alloc-util.h"
 #include "efivars.h"
+#include "fd-util.h"
+#include "gpt.h"
+#include "string-util.h"
 #include "udev.h"
 
 static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) {
index 3352821567e405723ab6287bd0dbf4decca48bb3..cfaa4638044cf707248428d327f5b545edc5a067 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <sys/ioctl.h>
 
 #ifdef HAVE_LINUX_BTRFS_H
 #include <linux/btrfs.h>
 #endif
 
+#include "fd-util.h"
 #include "missing.h"
+#include "string-util.h"
 #include "udev.h"
 
 static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) {
index 72109d93d2129c52b11da7fefe67832b0e3ff94d..f4a065a97d8c2c6987a051aebfbb08dff8efbc6f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <fnmatch.h>
 #include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
 
-#include "udev.h"
 #include "sd-hwdb.h"
 
+#include "alloc-util.h"
 #include "hwdb-util.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "udev.h"
 
 static sd_hwdb *hwdb;
 
index e3fa4bc162cd4e1ffdb5cb787dafa21851aa5241..fddafbd4dc1b811a7b8a4e6022e2dea43586a772 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <errno.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
 #include <string.h>
-#include <errno.h>
+#include <unistd.h>
 #include <linux/limits.h>
 #include <linux/input.h>
 
+#include "fd-util.h"
+#include "string-util.h"
 #include "udev.h"
 #include "util.h"
 
index d63a8e2760e35768ccdacc827c419724e5607399..aa10beafb0ba9615583f4a13b53400793cfbbe23 100644 (file)
 ***/
 
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
 #include <linux/input.h>
 
+#include "fd-util.h"
+#include "parse-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
 #include "udev.h"
 
 static const struct key *keyboard_lookup_key(const char *str, unsigned len);
index 81e78a8aa30e93ed99595b6a718371757b867246..9665f678fd5862fb643611d7f8918d6bf5661a99 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
 #include <errno.h>
 #include <libkmod.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "string-util.h"
 #include "udev.h"
 
 static struct kmod_ctx *ctx = NULL;
index 589f1f7822609c9897ee199c11238b1806878180..bf5c9c6b779a31d1ce286bbf958327ddeffc5217 100644 (file)
@@ -27,7 +27,7 @@
  * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
  *
  * Two character prefixes based on the type of interface:
- *   en -- ethernet
+ *   en -- Ethernet
  *   sl -- serial line IP (slip)
  *   wl -- wlan
  *   ww -- wwan
  * exported.
  * The usual USB configuration == 1 and interface == 0 values are suppressed.
  *
- * PCI ethernet card with firmware index "1":
+ * PCI Ethernet card with firmware index "1":
  *   ID_NET_NAME_ONBOARD=eno1
  *   ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
  *
- * PCI ethernet card in hotplug slot with firmware index number:
+ * PCI Ethernet card in hotplug slot with firmware index number:
  *   /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
  *   ID_NET_NAME_MAC=enx000000000466
  *   ID_NET_NAME_PATH=enp5s0
  *   ID_NET_NAME_SLOT=ens1
  *
- * PCI ethernet multi-function card with 2 ports:
+ * PCI Ethernet multi-function card with 2 ports:
  *   /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
  *   ID_NET_NAME_MAC=enx78e7d1ea46da
  *   ID_NET_NAME_PATH=enp2s0f0
  *   ID_NET_NAME_PATH=enp0s29u1u2
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <net/if.h>
 #include <net/if_arp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 #include <linux/pci_regs.h>
 
-#include "udev.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "string-util.h"
+#include "udev.h"
 
 enum netname_type{
         NET_UNDEF,
index d4589470fb46b32fcf412b442dd93d14a44a6457..f72894b5c58bdaafdbb94ea28329b2fd19ab8f71 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include "alloc-util.h"
 #include "link-config.h"
-#include "udev.h"
 #include "log.h"
+#include "udev.h"
 
 static link_config_ctx *ctx = NULL;
 
index 01e2c659ae13bab30b384f0ae0984c7bcc1c1428..aa18c7e4207cd6f5de4e2b5752147296b328f7d4 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
 #include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "string-util.h"
 #include "udev.h"
 
 _printf_(2,3)
@@ -591,31 +593,23 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path)
         return parent;
 }
 
-static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) {
-        struct udev_device *scsi_dev;
+/* Handle devices of AP bus in System z platform. */
+static struct udev_device *handle_ap(struct udev_device *parent, char **path) {
+        const char *type, *func;
 
         assert(parent);
-        assert(dev);
         assert(path);
 
-        scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
-        if (scsi_dev != NULL) {
-                const char *wwpn;
-                const char *lun;
-                const char *hba_id;
-
-                hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id");
-                wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn");
-                lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun");
-                if (hba_id != NULL && lun != NULL && wwpn != NULL) {
-                        path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun);
-                        goto out;
-                }
-        }
+        type = udev_device_get_sysattr_value(parent, "type");
+        func = udev_device_get_sysattr_value(parent, "ap_functions");
 
-        path_prepend(path, "ccw-%s", udev_device_get_sysname(parent));
+        if (type != NULL && func != NULL) {
+                path_prepend(path, "ap-%s-%s", type, func);
+                goto out;
+        }
+        path_prepend(path, "ap-%s", udev_device_get_sysname(parent));
 out:
-        parent = skip_subsystem(parent, "ccw");
+        parent = skip_subsystem(parent, "ap");
         return parent;
 }
 
@@ -627,13 +621,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
 
         assert(dev);
 
-        /* S390 ccw bus */
-        parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
-        if (parent != NULL) {
-                handle_ccw(parent, dev, &path);
-                goto out;
-        }
-
         /* walk up the chain of devices and compose path */
         parent = dev;
         while (parent != NULL) {
@@ -681,6 +668,25 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
                         parent = skip_subsystem(parent, "scm");
                         supported_transport = true;
                         supported_parent = true;
+                } else if (streq(subsys, "ccw")) {
+                        path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "ccw");
+                        supported_transport = true;
+                        supported_parent = true;
+                } else if (streq(subsys, "ccwgroup")) {
+                        path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "ccwgroup");
+                        supported_transport = true;
+                        supported_parent = true;
+                } else if (streq(subsys, "ap")) {
+                        parent = handle_ap(parent, &path);
+                        supported_transport = true;
+                        supported_parent = true;
+                } else if (streq(subsys, "iucv")) {
+                        path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent));
+                        parent = skip_subsystem(parent, "iucv");
+                        supported_transport = true;
+                        supported_parent = true;
                 }
 
                 if (parent)
@@ -703,7 +709,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
         if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport)
                 path = mfree(path);
 
-out:
         if (path != NULL) {
                 char tag[UTIL_NAME_SIZE];
                 size_t i;
index 7bf4e7f24d806302eb64ecbee85d9c85b382e367..bbda9de08c13e5508e5c13049df858095377b715 100644 (file)
@@ -22,7 +22,9 @@
 #include <stdlib.h>
 #include <errno.h>
 
-#include "systemd/sd-login.h"
+#include "sd-login.h"
+
+#include "login-util.h"
 #include "logind-acl.h"
 #include "udev.h"
 #include "util.h"
@@ -56,7 +58,7 @@ static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool
 
         r = devnode_acl(path, true, false, 0, true, uid);
         if (r < 0) {
-                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path);
+                log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path);
                 goto finish;
         }
 
index d309dc31cb79f843441f5ca22ddb0bafdaa69984..587649eff0aa6d15e5f306cd1c53875ec60db787 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
 #include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <unistd.h>
 
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "string-util.h"
 #include "udev.h"
 
 static void set_usb_iftype(char *to, int if_class_num, size_t len) {
index 4f625251d66197f97465360498801d9e1dd95a90..e6b36f124fdff21cf1e7285caf322016c42dd0b7 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <getopt.h>
 #include <stdio.h>
 #include <string.h>
-#include <getopt.h>
 
+#include "string-util.h"
 #include "udev.h"
 
 static bool initialized;
index 56277f551fef769e363f3f3f0651279f2648823b..1e05be51a549d6185301755ea74f06e19e2d19a3 100644 (file)
 #include <sys/socket.h>
 #include <sys/un.h>
 
-#include "socket-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "socket-util.h"
 #include "udev.h"
 
 /* wire protocol magic must match */
index 1e34cbc2f53857f52c85aebc3af91e1aada200e3..5d6542d3ad4854e60be9817429b3d5e0fb5e778a 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <ctype.h>
-#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <net/if.h>
-#include <sys/prctl.h>
 #include <poll.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/epoll.h>
-#include <sys/wait.h>
+#include <sys/prctl.h>
 #include <sys/signalfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
-#include "netlink-util.h"
+#include "alloc-util.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "netlink-util.h"
 #include "process-util.h"
 #include "signal-util.h"
+#include "string-util.h"
 #include "udev.h"
 
 typedef struct Spawn {
@@ -438,9 +441,7 @@ static int spawn_exec(struct udev_event *event,
         execve(argv[0], argv, envp);
 
         /* exec failed */
-        log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
-
-        return -errno;
+        return log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
 }
 
 static void spawn_read(struct udev_event *event,
index e730fb45f15938fa3c1c43e4f94d5a0adee69d9d..c2edf2c5cdcc694cd19003393777fcf62e934bad 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
-#include "udev.h"
-#include "smack-util.h"
-#include "selinux-util.h"
 #include "formats-util.h"
+#include "fs-util.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "string-util.h"
+#include "udev.h"
 
 static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
         struct stat stats;
@@ -261,8 +263,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
                 mode |= S_IFCHR;
 
         if (lstat(devnode, &stats) != 0) {
-                err = -errno;
-                log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
+                err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
                 goto out;
         }
 
index 10bf3880b049379aa562c50de8872f3e09ebbee9..c06ace09cf171c9c877a90b35914e962c0f28371 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stddef.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
 #include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <fnmatch.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <time.h>
+#include <unistd.h>
 
-#include "udev.h"
-#include "path-util.h"
+#include "alloc-util.h"
 #include "conf-files.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "glob-util.h"
+#include "path-util.h"
+#include "stat-util.h"
 #include "strbuf.h"
+#include "string-util.h"
 #include "strv.h"
-#include "util.h"
 #include "sysctl-util.h"
+#include "udev.h"
+#include "user-util.h"
+#include "util.h"
 
 #define PREALLOC_TOKEN          2048
 
@@ -51,7 +58,8 @@ static const char* const rules_dirs[] = {
         "/etc/udev/rules.d",
         "/run/udev/rules.d",
         UDEVLIBEXECDIR "/rules.d",
-        NULL};
+        NULL
+};
 
 struct udev_rules {
         struct udev *udev;
index d17fc8c1ea717c4b9cdb3b80ea6ab1211e3cb218..1f9c8120c0add2c43cf379862cc3bd3cc15ce462 100644 (file)
 
 #pragma once
 
-#include <sys/types.h>
 #include <sys/param.h>
+#include <sys/types.h>
 
-#include "macro.h"
-#include "sd-netlink.h"
 #include "libudev.h"
-#include "libudev-private.h"
-#include "util.h"
+#include "sd-netlink.h"
+
 #include "label.h"
+#include "libudev-private.h"
+#include "macro.h"
 #include "strv.h"
+#include "util.h"
 
 struct udev_event {
         struct udev *udev;
index 00609e31b52202d4af5ef76d5c32a07fc1c473de..031a099d77b9f07b6c83af90d0865e694d37d483 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdlib.h>
+#include <ctype.h>
 #include <getopt.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
 
-#include "util.h"
-#include "strbuf.h"
+#include "alloc-util.h"
 #include "conf-files.h"
-
-#include "udev.h"
+#include "fileio.h"
+#include "fs-util.h"
 #include "hwdb-internal.h"
 #include "hwdb-util.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "udev.h"
+#include "util.h"
 
 /*
  * Generic udev properties, key/value database based on modalias strings.
index b3d5565c48bf100ad4201ae8b5150b3b500b5ce3..7182668f234a18a935853491fcab4bcb03128b4e 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
 #include <ctype.h>
-#include <unistd.h>
 #include <dirent.h>
 #include <errno.h>
-#include <getopt.h>
 #include <fcntl.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
-#include "udev.h"
+#include "fd-util.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "udev.h"
 #include "udevadm-util.h"
 
 static bool skip_attribute(const char *name) {
index 5e93955186f7b474d4fdba730c32d8aa2a07f260..30aa53feb2b08b93100b3a9115e21746109f12c6 100644 (file)
 #include <sys/time.h>
 #include <sys/epoll.h>
 
-#include "udev.h"
-#include "udev-util.h"
+#include "fd-util.h"
 #include "formats-util.h"
+#include "udev-util.h"
+#include "udev.h"
 
 static bool udev_exit;
 
index 3d6ca7a98589342c36fc3e9a7e5d37b8e6c14df0..c25071b0fee7b718747ab43f7636671af10bece5 100644 (file)
@@ -26,6 +26,7 @@
 #include <getopt.h>
 #include <poll.h>
 
+#include "parse-util.h"
 #include "udev.h"
 #include "util.h"
 
index 35a73494391f68f4209daaf3e26b9cb1dda70a65..0b180d03eb399abc772c1ab4413f2707d8915104 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
 #include <errno.h>
 #include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 
+#include "string-util.h"
 #include "udev.h"
 
 static void help(struct udev *udev) {
index d04e618d0d2a27c8d2f27f7dd5bfd7c875371b2b..ff427cf29217e125d96b0f9c3bd330847d823ec4 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
 #include <errno.h>
-#include <signal.h>
 #include <getopt.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <sys/signalfd.h>
+#include <unistd.h>
 
-#include "udev.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "udev.h"
 
 static void help(void) {
 
index 7af9665f8a31da36459076aced0df87b3ecec598..9d52345d92316aef6fe8cef3e94e5226564c4c51 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
 #include <stddef.h>
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
-#include <getopt.h>
-#include <errno.h>
-#include <fcntl.h>
 
-#include "udev.h"
+#include "string-util.h"
 #include "udev-util.h"
+#include "udev.h"
 #include "udevadm-util.h"
 #include "util.h"
 
index 3f0e45e26c9940793310e3971c13cc40c0142dc6..3539c1d6ab15a48088cca120518e9a0ba28657a2 100644 (file)
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "string-util.h"
 #include "udevadm-util.h"
 
 struct udev_device *find_device(struct udev *udev,
index b86d8921f36a68c7a6865ce38cc2bab374d6a6c3..60f122ebdab69ece78f88c2130d1bf44ce84f2b3 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdio.h>
-#include <stddef.h>
 #include <errno.h>
 #include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
 
 #include "selinux-util.h"
+#include "string-util.h"
 #include "udev.h"
 
 static int adm_version(struct udev *udev, int argc, char *argv[]) {
index e4d2f477458d33ee0b2a05de35484a64bb1c68df..5364b92a57c9950e2722da652203cd4654fa9021 100644 (file)
 #include "sd-daemon.h"
 #include "sd-event.h"
 
+#include "alloc-util.h"
 #include "cgroup-util.h"
 #include "cpu-set-util.h"
 #include "dev-setup.h"
 #include "event-util.h"
+#include "fd-util.h"
 #include "fileio.h"
 #include "formats-util.h"
+#include "fs-util.h"
 #include "hashmap.h"
+#include "io-util.h"
 #include "netlink-util.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
 #include "process-util.h"
 #include "selinux-util.h"
 #include "signal-util.h"
+#include "socket-util.h"
+#include "string-util.h"
 #include "terminal-util.h"
 #include "udev-util.h"
 #include "udev.h"
+#include "user-util.h"
 
 static bool arg_debug = false;
 static int arg_daemonize = false;
@@ -1549,7 +1558,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
 
         r = sd_event_default(&manager->event);
         if (r < 0)
-                return log_error_errno(errno, "could not allocate event loop: %m");
+                return log_error_errno(r, "could not allocate event loop: %m");
 
         r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
         if (r < 0)
index 5c57db44c161be5a0f629be57623c3d57a3074ea..607d78a0191e91f7b3370fa0a07e1f7d4f2acd9c 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/ioctl.h>
 #include <linux/videodev2.h>
 
+#include "fd-util.h"
 #include "util.h"
 
 int main(int argc, char *argv[]) {
index 01bbde8455495dccd0fdda4736fced23b696a4a2..4c44d5061370a0e7000e8e3e29e0d1a456f8e26f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include "util.h"
+#include "fd-util.h"
+#include "io-util.h"
 #include "selinux-util.h"
+#include "util.h"
 
 #define MESSAGE                                                         \
         "This file was created by systemd-update-done. Its only \n"     \
index bcabf65a36dd89dec25486c76022553e766c704d..d50063cbcdd161620170a6199c47f93493c6ecce 100644 (file)
 
 #include "sd-bus.h"
 
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "formats-util.h"
 #include "log.h"
 #include "macro.h"
-#include "util.h"
 #include "special.h"
-#include "utmp-wtmp.h"
-#include "bus-util.h"
-#include "bus-error.h"
 #include "unit-name.h"
-#include "formats-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
 
 typedef struct Context {
         sd_bus *bus;
index 7c736c44d25e45fc3ee746017537194fd7512f57..252cbdb26cf50ec8cde5ad1e91956a4d7ed3047f 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
 #include <errno.h>
+#include <unistd.h>
 
+#include "fileio.h"
 #include "log.h"
+#include "string-util.h"
 #include "util.h"
-#include "fileio.h"
 
 int main(int argc, char*argv[]) {
 
index 6353579283fd3d87b304272f0813dd4e86a84454..a5f4529cfdbd1c4c88aeb758a9f3f5e4efed1355 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdbool.h>
 #include <limits.h>
-#include <sys/ioctl.h>
-#include <linux/tiocl.h>
 #include <linux/kd.h>
+#include <linux/tiocl.h>
 #include <linux/vt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
 
-#include "util.h"
-#include "log.h"
-#include "virt.h"
+#include "alloc-util.h"
+#include "fd-util.h"
 #include "fileio.h"
+#include "io-util.h"
+#include "locale-util.h"
+#include "log.h"
 #include "process-util.h"
-#include "terminal-util.h"
 #include "signal-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
+#include "virt.h"
 
 static bool is_vconsole(int fd) {
         unsigned char data[1];
@@ -270,7 +275,7 @@ int main(int argc, char **argv) {
 
         fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
         if (fd < 0) {
-                log_error_errno(errno, "Failed to open %s: %m", vc);
+                log_error_errno(fd, "Failed to open %s: %m", vc);
                 return EXIT_FAILURE;
         }
 
index d97fbe24d492a71b49084ae630dd6780f6a81728..b6b474393daa8c7c049d9f093a9f17523b88ea6b 100755 (executable)
@@ -53,7 +53,7 @@ Description=Testsuite service
 After=multi-user.target
 
 [Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok'
 Type=oneshot
 EOF
 
index 4be2365e2f00c89ce0513e20cf6be7f881dc04bc..2997da06ff1e42855376e841dee147044181a9f0 100755 (executable)
@@ -59,7 +59,7 @@ Description=Testsuite service
 After=multi-user.target
 
 [Service]
-ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;'
+ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok'
 Type=oneshot
 EOF
 
index 6f32c240cd58e97c3235ba585b25845439604acb..42d475fe2fbaef2dbe8db279d9595ac0bae56538 100755 (executable)
@@ -23,7 +23,7 @@ grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1
 grep 'hello\.service' /root/list-jobs.txt && exit 1
 systemctl stop sleep.service hello-after-sleep.target || exit 1
 
-# Test for a crash when enqueueing a JOB_NOP when other job already exists
+# Test for a crash when enqueuing a JOB_NOP when other job already exists
 systemctl start --no-block hello-after-sleep.target || exit 1
 # hello.service should still be waiting, so these try-restarts will collapse
 # into NOPs.
diff --git a/test/end.service b/test/end.service
new file mode 100644 (file)
index 0000000..6e1996f
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=End the test
+After=testsuite.service
+OnFailure=poweroff.target
+OnFailureJobMode=replace-irreversibly
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -x -c 'systemctl poweroff --no-block'
+TimeoutStartSec=5m
diff --git a/test/end.service.in b/test/end.service.in
deleted file mode 100644 (file)
index 4857ffe..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=End the test
-After=testsuite.service
-
-[Service]
-ExecStart=@SYSTEMCTL@ poweroff --no-block
diff --git a/test/exec-environment-empty.service b/test/exec-environment-empty.service
deleted file mode 100644 (file)
index 0219ca4..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Unit]
-Description=Test for Environment
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test ! "$VAR1" = "word1 word2") && $(test ! "$VAR2" = word3) && $(test ! "$VAR3" = \'$word 5 6\')'
-Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
-Environment=
diff --git a/test/exec-environment.service b/test/exec-environment.service
deleted file mode 100644 (file)
index 4586b4c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for Environment
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')'
-Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
diff --git a/test/exec-group.service b/test/exec-group.service
deleted file mode 100644 (file)
index 1aa04b5..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for Group
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test $(id -n -g) = nobody)'
-Group=nobody
diff --git a/test/exec-umask-0177.service b/test/exec-umask-0177.service
deleted file mode 100644 (file)
index af92958..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[Unit]
-Description=Test for UMask
-
-[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "600")'
-UMask=0177
-PrivateTmp=yes
diff --git a/test/exec-umask-default.service b/test/exec-umask-default.service
deleted file mode 100644 (file)
index 41e20a6..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for UMask default
-
-[Service]
-ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "644")'
-PrivateTmp=yes
diff --git a/test/exec-user.service b/test/exec-user.service
deleted file mode 100644 (file)
index 2ca08eb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Unit]
-Description=Test for User
-
-[Service]
-ExecStart=/bin/sh -c 'exit $(test "$USER" = nobody)'
-User=nobody
diff --git a/test/paths.target b/test/paths.target
deleted file mode 120000 (symlink)
index e9939c9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../units/paths.target
\ No newline at end of file
diff --git a/test/test-execute/exec-capabilityboundingset-invert.service b/test/test-execute/exec-capabilityboundingset-invert.service
new file mode 100644 (file)
index 0000000..fd5d248
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"'
+Type=oneshot
+CapabilityBoundingSet=~CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-merge.service b/test/test-execute/exec-capabilityboundingset-merge.service
new file mode 100644 (file)
index 0000000..5c7fcaf
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER
+CapabilityBoundingSet=CAP_KILL CAP_CHOWN
diff --git a/test/test-execute/exec-capabilityboundingset-reset.service b/test/test-execute/exec-capabilityboundingset-reset.service
new file mode 100644 (file)
index 0000000..d7d3320
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER CAP_KILL
+CapabilityBoundingSet=
diff --git a/test/test-execute/exec-capabilityboundingset-simple.service b/test/test-execute/exec-capabilityboundingset-simple.service
new file mode 100644 (file)
index 0000000..bf1a7f5
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for CapabilityBoundingSet
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"'
+Type=oneshot
+CapabilityBoundingSet=CAP_FOWNER CAP_KILL
diff --git a/test/test-execute/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service
new file mode 100644 (file)
index 0000000..9c92d4b
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for Environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
+Environment=
similarity index 53%
rename from test/exec-environment-multiple.service
rename to test/test-execute/exec-environment-multiple.service
index 479005a5d876a0b98dfabd33b73575e26a1b2247..b9bc225635a9a1697ebba4dc044e9a199cef324d 100644 (file)
@@ -2,6 +2,7 @@
 Description=Test for Environment
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = foobar)'
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = foobar'
+Type=oneshot
 Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
 Environment="VAR3=foobar"
diff --git a/test/test-execute/exec-environment.service b/test/test-execute/exec-environment.service
new file mode 100644 (file)
index 0000000..06e77af
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service
new file mode 100644 (file)
index 0000000..f6b8462
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for EnvironmentFile
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+EnvironmentFile=/tmp/test-exec_environmentfile.conf
diff --git a/test/test-execute/exec-group.service b/test/test-execute/exec-group.service
new file mode 100644 (file)
index 0000000..be7c796
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for Group
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"'
+Type=oneshot
+Group=nobody
similarity index 68%
rename from test/exec-ignoresigpipe-no.service
rename to test/test-execute/exec-ignoresigpipe-no.service
index 69b2e9d8a8458a2ae50ae090c52bccb589b7b463..73addf5f05500bb0b6ed546bfe60d99fdb6e5ee7 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for IgnoreSIGPIPE=no
 
 [Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
 Type=oneshot
 IgnoreSIGPIPE=no
similarity index 69%
rename from test/exec-ignoresigpipe-yes.service
rename to test/test-execute/exec-ignoresigpipe-yes.service
index 877ec8aed01854f9dff5bae77979ecd14abf46fb..f81c01719e9ad74b790d5add5e1ae9fde90b5d24 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for IgnoreSIGPIPE=yes
 
 [Service]
-ExecStart=/bin/sh -c 'kill -PIPE 0'
+ExecStart=/bin/sh -x -c 'kill -PIPE 0'
 Type=oneshot
 IgnoreSIGPIPE=yes
diff --git a/test/test-execute/exec-ioschedulingclass-best-effort.service b/test/test-execute/exec-ioschedulingclass-best-effort.service
new file mode 100644 (file)
index 0000000..29bb851
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=best-effort
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "best-effort"'
+Type=oneshot
+IOSchedulingClass=best-effort
diff --git a/test/test-execute/exec-ioschedulingclass-idle.service b/test/test-execute/exec-ioschedulingclass-idle.service
new file mode 100644 (file)
index 0000000..87dbed1
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=idle
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "idle"'
+Type=oneshot
+IOSchedulingClass=idle
diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service
new file mode 100644 (file)
index 0000000..b6af122
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=none
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"'
+Type=oneshot
+IOSchedulingClass=none
diff --git a/test/test-execute/exec-ioschedulingclass-realtime.service b/test/test-execute/exec-ioschedulingclass-realtime.service
new file mode 100644 (file)
index 0000000..d920d5c
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for IOSchedulingClass=realtime
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "realtime"'
+Type=oneshot
+IOSchedulingClass=realtime
diff --git a/test/test-execute/exec-oomscoreadjust-negative.service b/test/test-execute/exec-oomscoreadjust-negative.service
new file mode 100644 (file)
index 0000000..2234c53
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for OOMScoreAdjust
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq -100'
+Type=oneshot
+OOMScoreAdjust=-100
diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service
new file mode 100644 (file)
index 0000000..456a8f8
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for OOMScoreAdjust
+
+[Service]
+ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq 100'
+Type=oneshot
+OOMScoreAdjust=100
diff --git a/test/test-execute/exec-passenvironment-absent.service b/test/test-execute/exec-passenvironment-absent.service
new file mode 100644 (file)
index 0000000..7d5e32a
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PassEnvironment with variables absent from the execution environment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
diff --git a/test/test-execute/exec-passenvironment-empty.service b/test/test-execute/exec-passenvironment-empty.service
new file mode 100644 (file)
index 0000000..c93c197
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for PassEnvironment and erasing the variable list
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
+PassEnvironment=
diff --git a/test/test-execute/exec-passenvironment-repeated.service b/test/test-execute/exec-passenvironment-repeated.service
new file mode 100644 (file)
index 0000000..5e8c56f
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for PassEnvironment with a variable name repeated
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2
+PassEnvironment=VAR1 VAR3
diff --git a/test/test-execute/exec-passenvironment.service b/test/test-execute/exec-passenvironment.service
new file mode 100644 (file)
index 0000000..b4a9909
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PassEnvironment
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"'
+Type=oneshot
+PassEnvironment=VAR1 VAR2 VAR3
similarity index 53%
rename from test/exec-personality-s390.service
rename to test/test-execute/exec-personality-s390.service
index f3c3b03e3d83036d72e3b9f0f203b1bdf7c51e19..89f7de89d03b3fae82c12cbfacbeb1a1d1e1ee3e 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for Personality=s390
 
 [Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "s390")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "s390"'
 Type=oneshot
 Personality=s390
similarity index 53%
rename from test/exec-personality-x86-64.service
rename to test/test-execute/exec-personality-x86-64.service
index 5bb5d910d0dd41b8e00d2cb44d835ccfd5ad97ae..433e69a6d10d818a1f07ed3bf21c282218691a41 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for Personality=x86-64
 
 [Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"'
 Type=oneshot
 Personality=x86-64
similarity index 52%
rename from test/exec-personality-x86.service
rename to test/test-execute/exec-personality-x86.service
index 0b370a6480eebb17d95ec3fe2c8d6404a6d7974a..a623a08cbedaad967afaec5d5632e172428bf067 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for Personality=x86
 
 [Service]
-ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")'
+ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"'
 Type=oneshot
 Personality=x86
similarity index 63%
rename from test/exec-privatedevices-no.service
rename to test/test-execute/exec-privatedevices-no.service
index cf4f275fb62cce24e4d191e6adddade69385da32..77aeb951b5dbbfb9bd892763ef078418b6a99822 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for PrivateDev=no
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)'
+ExecStart=/bin/sh -x -c 'test -c /dev/mem'
 Type=oneshot
 PrivateDevices=no
similarity index 63%
rename from test/exec-privatedevices-yes.service
rename to test/test-execute/exec-privatedevices-yes.service
index 85b3f4f9810e3d7b6a268e290d6c8807b25a58e1..ab958b646eda7f0eeff403dc1f03ab6c081f6104 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for PrivateDev=yes
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)'
+ExecStart=/bin/sh -c 'test ! -c /dev/mem'
 Type=oneshot
 PrivateDevices=yes
diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service
new file mode 100644 (file)
index 0000000..3df543e
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for PrivateNetwork
+
+[Service]
+ExecStart=/bin/sh -x -c 'i=$$(ip link | grep ": " | grep -v ": lo:"); test -z "$$i"'
+Type=oneshot
+PrivateNetwork=yes
similarity index 55%
rename from test/exec-privatetmp-no.service
rename to test/test-execute/exec-privatetmp-no.service
index d69e552a63de41bf02ecfb581b4c58db41b64254..59f60f47557b63a7cf08be9dd04fa05fb52ae65a 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for PrivateTmp=no
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp'
 Type=oneshot
 PrivateTmp=no
similarity index 55%
rename from test/exec-privatetmp-yes.service
rename to test/test-execute/exec-privatetmp-yes.service
index 881a040b87e1a69c62e6f5d5d65adddf8f75b9b4..907c291b81c9f0bebad0b59a3109b57d78a2a5e4 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for PrivateTmp=yes
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test ! -f /tmp/test-exec_privatetmp)'
+ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp'
 Type=oneshot
 PrivateTmp=yes
similarity index 57%
rename from test/exec-runtimedirectory-mode.service
rename to test/test-execute/exec-runtimedirectory-mode.service
index ba6d7ee39ff60a173778c7653f75aefd3aaf1a9b..842721d5c2e0a051b8acee70e151f77792ed27f3 100644 (file)
@@ -2,7 +2,7 @@
 Description=Test for RuntimeDirectoryMode
 
 [Service]
-ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")'
+ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a /tmp/test-exec_runtimedirectory-mode); test "$$mode" = "750"'
 Type=oneshot
 RuntimeDirectory=test-exec_runtimedirectory-mode
 RuntimeDirectoryMode=0750
similarity index 63%
rename from test/exec-runtimedirectory-owner.service
rename to test/test-execute/exec-runtimedirectory-owner.service
index 077e08d1c58827866131db4d6458b5c48b18ddc0..1f438c182e83cc28ecd9412df9c6b2d719a58067 100644 (file)
@@ -2,7 +2,7 @@
 Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set)
 
 [Service]
-ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")'
+ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"'
 Type=oneshot
 Group=nobody
 User=root
similarity index 61%
rename from test/exec-runtimedirectory.service
rename to test/test-execute/exec-runtimedirectory.service
index c12a6c63d68da26c99412b90298dae9d401bd517..ec46c9d49b2bbf22d40aa51f300e492142270117 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for RuntimeDirectory
 
 [Service]
-ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)'
+ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory'
 Type=oneshot
 RuntimeDirectory=test-exec_runtimedirectory
similarity index 70%
rename from test/exec-systemcallerrornumber.service
rename to test/test-execute/exec-systemcallerrornumber.service
index 255a8b231a8e9ec32fe8dfba47ae16ca2633476d..ff7da3c1a49c20156693dbc7c147ad48106c9e94 100644 (file)
@@ -2,6 +2,7 @@
 Description=Test for SystemCallErrorNumber
 
 [Service]
-ExecStart=/usr/bin/uname -a
+ExecStart=/bin/sh -x -c 'uname -a'
+Type=oneshot
 SystemCallFilter=~uname
 SystemCallErrorNumber=EACCES
similarity index 93%
rename from test/exec-systemcallfilter-failing.service
rename to test/test-execute/exec-systemcallfilter-failing.service
index c6ce9368c91435a8359e28884c9005f16da3a3a9..5c6422f0fd5ba36ef1fb70234539b1572de4a6e1 100644 (file)
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
 
 [Service]
 ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
 SystemCallFilter=ioperm
 SystemCallFilter=~ioperm
 SystemCallFilter=ioperm
similarity index 93%
rename from test/exec-systemcallfilter-failing2.service
rename to test/test-execute/exec-systemcallfilter-failing2.service
index b7f7c2aff99ec66a146d04f7296013a0c1413e0c..3516078e1ffb94395cf4f1591e8c5abb6b3a3ee0 100644 (file)
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
 
 [Service]
 ExecStart=/bin/echo "This should not be seen"
+Type=oneshot
 SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST
similarity index 94%
rename from test/exec-systemcallfilter-not-failing.service
rename to test/test-execute/exec-systemcallfilter-not-failing.service
index feb206ab6d0b7fd3aec48bdfda0478a14cdebae6..c794b67edd89fc3560e1e0524771e8a1d0a2a703 100644 (file)
@@ -3,6 +3,7 @@ Description=Test for SystemCallFilter
 
 [Service]
 ExecStart=/bin/echo "Foo bar"
+Type=oneshot
 SystemCallFilter=~read write open execve ioperm
 SystemCallFilter=ioctl
 SystemCallFilter=read write open execve
similarity index 88%
rename from test/exec-systemcallfilter-not-failing2.service
rename to test/test-execute/exec-systemcallfilter-not-failing2.service
index cca469aa3dc2ba4260a15ebbe530d4fb4de26980..a62c81bd488596c1cf9581142ab2311ca0bb9a9b 100644 (file)
@@ -3,4 +3,5 @@ Description=Test for SystemCallFilter
 
 [Service]
 ExecStart=/bin/echo "Foo bar"
+Type=oneshot
 SystemCallFilter=
diff --git a/test/test-execute/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service
new file mode 100644 (file)
index 0000000..a5e8fc4
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for UMask
+
+[Service]
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"'
+Type=oneshot
+UMask=0177
+PrivateTmp=yes
diff --git a/test/test-execute/exec-umask-default.service b/test/test-execute/exec-umask-default.service
new file mode 100644 (file)
index 0000000..487f5e9
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for UMask default
+
+[Service]
+ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"'
+Type=oneshot
+PrivateTmp=yes
diff --git a/test/test-execute/exec-user.service b/test/test-execute/exec-user.service
new file mode 100644 (file)
index 0000000..0a00c1a
--- /dev/null
@@ -0,0 +1,7 @@
+[Unit]
+Description=Test for User
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"'
+Type=oneshot
+User=nobody
similarity index 57%
rename from test/exec-workingdirectory.service
rename to test/test-execute/exec-workingdirectory.service
index 10855d682ad108b5b2c35fb1cc6e64d2c218a8bb..fe3c420d2d3c3ef1496ea61055e7c20479ef0b0e 100644 (file)
@@ -2,6 +2,6 @@
 Description=Test for WorkingDirectory
 
 [Service]
-ExecStart=/bin/sh -c 'echo $PWD; exit $(test $PWD = "/tmp/test-exec_workingdirectory")'
+ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"'
 Type=oneshot
 WorkingDirectory=/tmp/test-exec_workingdirectory
index 8272e52e175e2a8a3139083425750f10d11b6e10..2f5ec9b93f71a8a1a0a22793a4e429d5bf461c62 100644 (file)
@@ -260,7 +260,7 @@ install_dbus() {
     inst $ROOTLIBDIR/system/dbus.service
 
     find \
-        /etc/dbus-1 -xtype f \
+        /etc/dbus-1 /usr/share/dbus-1 -xtype f \
         | while read file; do
         inst $file
     done
@@ -305,7 +305,7 @@ install_terminfo() {
 
 setup_testsuite() {
     cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/
-    sed "s#@SYSTEMCTL@#$(type -P systemctl)#g" $TEST_BASE_DIR/end.service.in > $initdir/etc/systemd/system/end.service
+    cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/
 
     mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
     ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
diff --git a/test/test-path/basic.target b/test/test-path/basic.target
new file mode 120000 (symlink)
index 0000000..a882b72
--- /dev/null
@@ -0,0 +1 @@
+../../units/basic.target
\ No newline at end of file
diff --git a/test/test-path/paths.target b/test/test-path/paths.target
new file mode 120000 (symlink)
index 0000000..b402796
--- /dev/null
@@ -0,0 +1 @@
+../../units/paths.target
\ No newline at end of file
diff --git a/test/test-path/sysinit.target b/test/test-path/sysinit.target
new file mode 120000 (symlink)
index 0000000..9d10e5b
--- /dev/null
@@ -0,0 +1 @@
+../../units/sysinit.target
\ No newline at end of file
index 24fb0a25e16f35e1c361bfa85a3fe8a7d2260265..56b72c98f75904b9a5d878a28522f25dd8e7fa6c 100644 (file)
@@ -1,5 +1,5 @@
 [Service]
 Type=oneshot
 RemainAfterExit=yes
-ExecStart=/bin/echo 'I'm unstoppable!'
+ExecStart=/bin/echo "I'm unstoppable!"
 ExecStop=/bin/systemctl start --no-block unstoppable.service
index aa652b197f150cccd5e7913e58fa18edde3a3273..9f25b83392a3b386b204f64a80cf2c0f42a50696 100644 (file)
@@ -7,5 +7,5 @@
 
 # See tmpfiles.d(5) for details
 
-v /home 0755 - - -
-v /srv 0755 - - -
+Q /home 0755 - - -
+q /srv 0755 - - -
index 5a3124a0fc1c90aa134eccb73e0291fec741df6e..9fa3878d6b5f92dac3b290760497e9d99217c660 100644 (file)
@@ -7,7 +7,7 @@
 
 # See tmpfiles.d(5) for details
 
-v /var/lib/machines 0700 - - -
+Q /var/lib/machines 0700 - - -
 
 # Remove old temporary snapshots, but only at boot. Ideally we'd have
 # "self-destroying" btrfs snapshots that go away if the last last
index ffdd82fd9cf5352188513fde77ed01b15f129c8c..6bbd1aa341e529661862f7cbcaaa8f07b6a932a1 100644 (file)
@@ -8,8 +8,8 @@
 # See tmpfiles.d(5) for details
 
 # Clear tmp directories separately, to make them easier to override
-v /tmp 1777 root root 10d
-v /var/tmp 1777 root root 30d
+q /tmp 1777 root root 10d
+q /var/tmp 1777 root root 30d
 
 # Exclude namespace mountpoints created with PrivateTmp=yes
 x /tmp/systemd-private-%b-*
index 472680c3bfdcfc168ad9e6867d2fafb9fc5e2d47..ae7952e77a8c797d71ef924cd547ac05842d108a 100644 (file)
@@ -7,7 +7,7 @@
 
 # See tmpfiles.d(5) for details
 
-v /var 0755 - - -
+q /var 0755 - - -
 
 L /var/run - - - - ../run
 
index 883f51f73cba6f19bb9b78fcf4d67b20fe671d73..c89740df05ca12240b05007c998a858f5d6325c6 100644 (file)
@@ -78,4 +78,5 @@
 /systemd-update-utmp.service
 /systemd-user-sessions.service
 /systemd-vconsole-setup.service
+/tmp.mount
 /user@.service
index c0e3df9d0fff2ef5a4551132b18692815228cf58..841f049b58c1cfedff8e9a7066f7da2dabb4fac7 100644 (file)
@@ -10,5 +10,5 @@ Description=System Slice
 Documentation=man:systemd.special(7)
 DefaultDependencies=no
 Before=slices.target
-Wants=-.slice
+Requires=-.slice
 After=-.slice
index 2c20935d831e8b064a16be0d7499a84134fed9f7..9e4e9dd338a36254eea76584f64c75bc583a2e3c 100644 (file)
@@ -14,7 +14,7 @@ Before=sockets.target
 
 [Socket]
 ReceiveBuffer=8M
-ListenNetlink=route 273
+ListenNetlink=route 1361
 PassCredentials=yes
 
 [Install]
index 03349931d9d81e5d05768b2708084b778f1c1888..2e79adff447be4651adf338f56dc3a94f695ab6e 100644 (file)
@@ -39,6 +39,7 @@ DeviceAllow=char-pts rw
 # implement the --image= option. Add these here, too.
 DeviceAllow=/dev/loop-control rw
 DeviceAllow=block-loop rw
+DeviceAllow=block-blkext rw
 
 [Install]
 WantedBy=machines.target
similarity index 100%
rename from units/tmp.mount
rename to units/tmp.mount.m4
index b0ad24c488af82c3388bc6df46b6500e300033f4..e8148b78c711ba3e71d4067ae2f1d4c0e7854362 100644 (file)
@@ -12,6 +12,3 @@ DefaultDependencies=no
 Requires=systemd-exit.service
 After=systemd-exit.service
 AllowIsolate=yes
-
-[Install]
-Alias=ctrl-alt-del.target