summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ac-power/ac-power.c2
-rw-r--r--src/activate/activate.c44
-rw-r--r--src/analyze/analyze-verify.c36
-rw-r--r--src/analyze/analyze.c2
-rw-r--r--src/backlight/backlight.c16
-rw-r--r--src/binfmt/binfmt.c23
-rw-r--r--src/bootchart/bootchart.c31
-rw-r--r--src/bootchart/bootchart.conf3
-rw-r--r--src/bootchart/store.c4
-rw-r--r--src/bootchart/svg.c10
-rw-r--r--src/bus-proxyd/bus-policy.c207
-rw-r--r--src/bus-proxyd/bus-policy.h10
-rw-r--r--src/bus-proxyd/bus-proxyd.c669
-rw-r--r--src/bus-proxyd/test-bus-policy.c97
-rw-r--r--src/cgls/cgls.c12
-rw-r--r--src/cgroups-agent/cgroups-agent.c4
-rw-r--r--src/cgtop/cgtop.c4
-rw-r--r--src/console/consoled-manager.c16
-rw-r--r--src/console/consoled-session.c6
-rw-r--r--src/console/consoled-terminal.c13
-rw-r--r--src/console/consoled.c4
-rw-r--r--src/core/audit-fd.c2
-rw-r--r--src/core/automount.c59
-rw-r--r--src/core/build.h2
-rw-r--r--src/core/busname.c146
-rw-r--r--src/core/cgroup.c137
-rw-r--r--src/core/cgroup.h5
-rw-r--r--src/core/condition.c264
-rw-r--r--src/core/dbus-cgroup.c42
-rw-r--r--src/core/dbus-execute.c19
-rw-r--r--src/core/dbus-job.c4
-rw-r--r--src/core/dbus-manager.c112
-rw-r--r--src/core/dbus-scope.c2
-rw-r--r--src/core/dbus-timer.c143
-rw-r--r--src/core/dbus-timer.h3
-rw-r--r--src/core/dbus-unit.c79
-rw-r--r--src/core/dbus.c174
-rw-r--r--src/core/device.c16
-rw-r--r--src/core/execute.c150
-rw-r--r--src/core/execute.h5
-rw-r--r--src/core/hostname-setup.c8
-rw-r--r--src/core/ima-setup.c67
-rw-r--r--src/core/job.c87
-rw-r--r--src/core/job.h15
-rw-r--r--src/core/killall.c10
-rw-r--r--src/core/kmod-setup.c24
-rw-r--r--src/core/load-dropin.c14
-rw-r--r--src/core/load-fragment-gperf.gperf.m493
-rw-r--r--src/core/load-fragment.c215
-rw-r--r--src/core/load-fragment.h7
-rw-r--r--src/core/locale-setup.c4
-rw-r--r--src/core/loopback-setup.c14
-rw-r--r--src/core/machine-id-setup.c171
-rw-r--r--src/core/machine-id-setup.h1
-rw-r--r--src/core/main.c217
-rw-r--r--src/core/manager.c335
-rw-r--r--src/core/manager.h4
-rw-r--r--src/core/mount-setup.c86
-rw-r--r--src/core/mount-setup.h1
-rw-r--r--src/core/mount.c258
-rw-r--r--src/core/namespace.c35
-rw-r--r--src/core/path.c47
-rw-r--r--src/core/scope.c27
-rw-r--r--src/core/selinux-access.c11
-rw-r--r--src/core/selinux-access.h2
-rw-r--r--src/core/selinux-setup.c2
-rw-r--r--src/core/service.c219
-rw-r--r--src/core/service.h3
-rw-r--r--src/core/shutdown.c51
-rw-r--r--src/core/slice.c2
-rw-r--r--src/core/smack-setup.c12
-rw-r--r--src/core/snapshot.c16
-rw-r--r--src/core/socket.c163
-rw-r--r--src/core/swap.c63
-rw-r--r--src/core/system.conf3
-rw-r--r--src/core/timer.c50
-rw-r--r--src/core/transaction.c139
-rw-r--r--src/core/umount.c8
-rw-r--r--src/core/unit.c185
-rw-r--r--src/core/unit.h30
-rw-r--r--src/core/user.conf3
-rw-r--r--src/cryptsetup/cryptsetup-generator.c444
-rw-r--r--src/cryptsetup/cryptsetup.c34
-rw-r--r--src/dbus1-generator/dbus1-generator.c70
-rw-r--r--src/debug-generator/debug-generator.c9
-rw-r--r--src/delta/delta.c21
-rw-r--r--src/detect-virt/detect-virt.c6
-rw-r--r--src/efi-boot-generator/efi-boot-generator.c12
-rw-r--r--src/firstboot/firstboot.c110
-rw-r--r--src/fsck/fsck.c21
-rw-r--r--src/fstab-generator/fstab-generator.c98
-rw-r--r--src/getty-generator/getty-generator.c2
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c112
-rw-r--r--src/hibernate-resume/hibernate-resume-generator.c18
-rw-r--r--src/hibernate-resume/hibernate-resume.c4
-rw-r--r--src/hostname/hostnamectl.c4
-rw-r--r--src/hostname/hostnamed.c41
-rw-r--r--src/initctl/initctl.c23
-rw-r--r--src/journal-remote/journal-gatewayd.c46
-rw-r--r--src/journal-remote/journal-remote-parse.c8
-rw-r--r--src/journal-remote/journal-remote-write.c8
-rw-r--r--src/journal-remote/journal-remote.c168
-rw-r--r--src/journal-remote/journal-upload-journal.c61
-rw-r--r--src/journal-remote/journal-upload.c78
-rw-r--r--src/journal-remote/microhttpd-util.c19
-rw-r--r--src/journal/cat.c6
-rw-r--r--src/journal/catalog.c34
-rw-r--r--src/journal/compress.c11
-rw-r--r--src/journal/coredump-vacuum.c12
-rw-r--r--src/journal/coredump.c321
-rw-r--r--src/journal/coredump.conf3
-rw-r--r--src/journal/coredumpctl.c71
-rw-r--r--src/journal/journal-authenticate.c2
-rw-r--r--src/journal/journal-file.c4
-rw-r--r--src/journal/journal-send.c42
-rw-r--r--src/journal/journal-vacuum.c45
-rw-r--r--src/journal/journal-vacuum.h2
-rw-r--r--src/journal/journal-verify.c6
-rw-r--r--src/journal/journalctl.c242
-rw-r--r--src/journal/journald-audit.c551
-rw-r--r--src/journal/journald-audit.h29
-rw-r--r--src/journal/journald-console.c6
-rw-r--r--src/journal/journald-console.h2
-rw-r--r--src/journal/journald-kmsg.c18
-rw-r--r--src/journal/journald-kmsg.h2
-rw-r--r--src/journal/journald-native.c119
-rw-r--r--src/journal/journald-native.h4
-rw-r--r--src/journal/journald-server.c188
-rw-r--r--src/journal/journald-server.h4
-rw-r--r--src/journal/journald-stream.c44
-rw-r--r--src/journal/journald-syslog.c81
-rw-r--r--src/journal/journald-syslog.h4
-rw-r--r--src/journal/journald-wall.c4
-rw-r--r--src/journal/journald-wall.h2
-rw-r--r--src/journal/journald.c2
-rw-r--r--src/journal/journald.conf3
-rw-r--r--src/journal/sd-journal.c91
-rw-r--r--src/journal/test-catalog.c16
-rw-r--r--src/journal/test-compress.c22
-rw-r--r--src/journal/test-journal-interleaving.c10
-rw-r--r--src/journal/test-journal-syslog.c6
-rw-r--r--src/journal/test-journal-verify.c6
-rw-r--r--src/journal/test-journal.c70
-rw-r--r--src/journal/test-mmap-cache.c22
-rw-r--r--src/kernel-install/90-loaderentry.install2
-rw-r--r--src/libsystemd-network/dhcp-internal.h2
-rw-r--r--src/libsystemd-network/dhcp-lease-internal.h10
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h2
-rw-r--r--src/libsystemd-network/dhcp6-internal.h2
-rw-r--r--src/libsystemd-network/dhcp6-option.c44
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h3
-rw-r--r--src/libsystemd-network/ipv4ll-internal.h2
-rw-r--r--src/libsystemd-network/network-internal.c38
-rw-r--r--src/libsystemd-network/network-internal.h2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c188
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c101
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c176
-rw-r--r--src/libsystemd-network/sd-dhcp6-lease.c4
-rw-r--r--src/libsystemd-network/sd-icmp6-nd.c8
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c6
-rw-r--r--src/libsystemd-network/sd-pppoe.c802
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c126
-rw-r--r--src/libsystemd-network/test-icmp6-rs.c36
-rw-r--r--src/libsystemd-network/test-pppoe.c181
-rw-r--r--src/libsystemd-terminal/evcat.c54
-rw-r--r--src/libsystemd-terminal/grdev-drm.c154
-rw-r--r--src/libsystemd-terminal/grdev.c16
-rw-r--r--src/libsystemd-terminal/idev-evdev.c42
-rw-r--r--src/libsystemd-terminal/idev-keyboard.c413
-rw-r--r--src/libsystemd-terminal/idev.c12
-rw-r--r--src/libsystemd-terminal/modeset.c38
-rw-r--r--src/libsystemd-terminal/subterm.c89
-rw-r--r--src/libsystemd-terminal/sysview.c125
-rw-r--r--src/libsystemd-terminal/term-screen.c4
-rw-r--r--src/libsystemd/libsystemd.sym.m416
-rw-r--r--src/libsystemd/sd-bus/PORTING-DBUS110
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c76
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h (renamed from src/shared/bus-errors.h)5
-rw-r--r--src/libsystemd/sd-bus/bus-control.c371
-rw-r--r--src/libsystemd/sd-bus/bus-control.h2
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c25
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c496
-rw-r--r--src/libsystemd/sd-bus/bus-creds.h15
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c303
-rw-r--r--src/libsystemd/sd-bus/bus-dump.h12
-rw-r--r--src/libsystemd/sd-bus/bus-error-mapping.gperf50
-rw-r--r--src/libsystemd/sd-bus/bus-error.c115
-rw-r--r--src/libsystemd/sd-bus/bus-error.h39
-rw-r--r--src/libsystemd/sd-bus/bus-internal.c20
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h6
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c631
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.h13
-rw-r--r--src/libsystemd/sd-bus/bus-match.c72
-rw-r--r--src/libsystemd/sd-bus/bus-message.c219
-rw-r--r--src/libsystemd/sd-bus/bus-message.h20
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c15
-rw-r--r--src/libsystemd/sd-bus/bus-protocol.h16
-rw-r--r--src/libsystemd/sd-bus/bus-slot.c16
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c4
-rw-r--r--src/libsystemd/sd-bus/bus-track.c2
-rw-r--r--src/libsystemd/sd-bus/bus-util.c43
-rw-r--r--src/libsystemd/sd-bus/busctl-introspect.c793
-rw-r--r--src/libsystemd/sd-bus/busctl-introspect.h34
-rw-r--r--src/libsystemd/sd-bus/busctl.c1623
-rw-r--r--src/libsystemd/sd-bus/kdbus.h402
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c198
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c76
-rw-r--r--src/libsystemd/sd-bus/test-bus-creds.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c91
-rw-r--r--src/libsystemd/sd-bus/test-bus-gvariant.c6
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel-bloom.c51
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel.c26
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c10
-rw-r--r--src/libsystemd/sd-bus/test-bus-match.c19
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c16
-rw-r--r--src/libsystemd/sd-bus/test-bus-server.c16
-rw-r--r--src/libsystemd/sd-bus/test-bus-zero-copy.c20
-rw-r--r--src/libsystemd/sd-event/sd-event.c33
-rw-r--r--src/libsystemd/sd-resolve/test-resolve.c16
-rw-r--r--src/libsystemd/sd-rtnl/local-addresses.c148
-rw-r--r--src/libsystemd/sd-rtnl/local-addresses.h5
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c208
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-types.c41
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.c17
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.h1
-rw-r--r--src/libsystemd/sd-rtnl/sd-rtnl.c10
-rw-r--r--src/libsystemd/sd-rtnl/test-local-addresses.c58
-rw-r--r--src/libsystemd/sd-rtnl/test-rtnl.c8
-rw-r--r--src/libudev/libudev-device-private.c9
-rw-r--r--src/libudev/libudev-device.c28
-rw-r--r--src/libudev/libudev-hwdb.c22
-rw-r--r--src/libudev/libudev-monitor.c32
-rw-r--r--src/libudev/libudev-private.h16
-rw-r--r--src/libudev/libudev-util.c14
-rw-r--r--src/libudev/libudev.c123
-rw-r--r--src/libudev/libudev.h6
-rw-r--r--src/locale/localectl.c30
-rw-r--r--src/locale/localed.c117
-rw-r--r--src/login/inhibit.c18
-rw-r--r--src/login/loginctl.c38
-rw-r--r--src/login/logind-button.c38
-rw-r--r--src/login/logind-core.c2
-rw-r--r--src/login/logind-dbus.c12
-rw-r--r--src/login/logind-inhibit.c2
-rw-r--r--src/login/logind-seat-dbus.c2
-rw-r--r--src/login/logind-seat.c14
-rw-r--r--src/login/logind-session-dbus.c2
-rw-r--r--src/login/logind-session.c32
-rw-r--r--src/login/logind-user.c18
-rw-r--r--src/login/logind.c185
-rw-r--r--src/login/logind.conf3
-rw-r--r--src/login/pam_systemd.c7
-rw-r--r--src/login/test-inhibit.c18
-rw-r--r--src/login/user-sessions.c6
-rw-r--r--src/machine-id-commit/machine-id-commit.c105
-rw-r--r--src/machine/machine-dbus.c4
-rw-r--r--src/machine/machine.c13
-rw-r--r--src/machine/machinectl.c73
-rw-r--r--src/machine/machined-dbus.c8
-rw-r--r--src/machine/machined.c66
-rw-r--r--src/modules-load/modules-load.c33
-rw-r--r--src/network/networkctl.c212
-rw-r--r--src/network/networkd-address.c155
-rw-r--r--src/network/networkd-dhcp4.c71
-rw-r--r--src/network/networkd-dhcp6.c210
-rw-r--r--src/network/networkd-ipv4ll.c24
-rw-r--r--src/network/networkd-link.c452
-rw-r--r--src/network/networkd-link.h24
-rw-r--r--src/network/networkd-manager.c81
-rw-r--r--src/network/networkd-netdev-bond.c12
-rw-r--r--src/network/networkd-netdev-gperf.gperf83
-rw-r--r--src/network/networkd-netdev-macvlan.c2
-rw-r--r--src/network/networkd-netdev-tunnel.c61
-rw-r--r--src/network/networkd-netdev-tuntap.c27
-rw-r--r--src/network/networkd-netdev-veth.c14
-rw-r--r--src/network/networkd-netdev-vlan.c2
-rw-r--r--src/network/networkd-netdev-vxlan.c93
-rw-r--r--src/network/networkd-netdev-vxlan.h10
-rw-r--r--src/network/networkd-netdev.c79
-rw-r--r--src/network/networkd-netdev.h7
-rw-r--r--src/network/networkd-network-gperf.gperf4
-rw-r--r--src/network/networkd-network.c35
-rw-r--r--src/network/networkd-route.c181
-rw-r--r--src/network/networkd-wait-online-manager.c6
-rw-r--r--src/network/networkd-wait-online.c4
-rw-r--r--src/network/networkd.c31
-rw-r--r--src/network/networkd.h38
-rw-r--r--src/notify/notify.c2
-rw-r--r--src/nspawn/nspawn.c1054
-rw-r--r--src/nss-myhostname/nss-myhostname.c82
-rw-r--r--src/nss-resolve/nss-resolve.c2
-rw-r--r--src/path/path.c8
-rw-r--r--src/quotacheck/quotacheck.c12
-rw-r--r--src/random-seed/random-seed.c27
-rw-r--r--src/rc-local-generator/rc-local-generator.c2
-rw-r--r--src/remount-fs/remount-fs.c10
-rw-r--r--src/reply-password/reply-password.c10
-rw-r--r--src/resolve-host/resolve-host.c12
-rw-r--r--src/resolve/resolved-bus.c38
-rw-r--r--src/resolve/resolved-conf.c11
-rw-r--r--src/resolve/resolved-dns-packet.c67
-rw-r--r--src/resolve/resolved-dns-rr.c10
-rw-r--r--src/resolve/resolved-dns-scope.c35
-rw-r--r--src/resolve/resolved-dns-stream.c4
-rw-r--r--src/resolve/resolved-dns-zone.c2
-rw-r--r--src/resolve/resolved-link.c16
-rw-r--r--src/resolve/resolved-manager.c24
-rw-r--r--src/resolve/resolved.c18
-rw-r--r--src/resolve/resolved.conf.in3
-rw-r--r--src/rfkill/rfkill.c53
-rw-r--r--src/run/run.c666
-rw-r--r--src/shared/architecture.c8
-rw-r--r--src/shared/architecture.h14
-rw-r--r--src/shared/ask-password-api.c24
-rw-r--r--src/shared/audit.c18
-rw-r--r--src/shared/audit.h2
-rw-r--r--src/shared/barrier.h2
-rw-r--r--src/shared/base-filesystem.c18
-rw-r--r--src/shared/calendarspec.c12
-rw-r--r--src/shared/cap-list.c62
-rw-r--r--src/shared/cap-list.h (renamed from src/core/condition.h)7
-rw-r--r--src/shared/capability.c60
-rw-r--r--src/shared/capability.h2
-rw-r--r--src/shared/cgroup-util.c26
-rw-r--r--src/shared/cgroup-util.h7
-rw-r--r--src/shared/clean-ipc.c38
-rw-r--r--src/shared/condition-util.c267
-rw-r--r--src/shared/condition.c527
-rw-r--r--src/shared/condition.h (renamed from src/shared/condition-util.h)55
-rw-r--r--src/shared/conf-files.c4
-rw-r--r--src/shared/conf-parser.c64
-rw-r--r--src/shared/conf-parser.h22
-rw-r--r--src/shared/copy.c84
-rw-r--r--src/shared/copy.h4
-rw-r--r--src/shared/def.h12
-rw-r--r--src/shared/env-util.c2
-rw-r--r--src/shared/ether-addr-util.h27
-rw-r--r--src/shared/exit-status.h1
-rw-r--r--src/shared/fileio.c91
-rw-r--r--src/shared/fileio.h1
-rw-r--r--src/shared/generator.c14
-rw-r--r--src/shared/hashmap.c1702
-rw-r--r--src/shared/hashmap.h315
-rw-r--r--src/shared/in-addr-util.c13
-rw-r--r--src/shared/install.c75
-rw-r--r--src/shared/install.h2
-rw-r--r--src/shared/locale-util.h4
-rw-r--r--src/shared/log.c364
-rw-r--r--src/shared/log.h91
-rw-r--r--src/shared/logs-show.c82
-rw-r--r--src/shared/macro.h27
-rw-r--r--src/shared/memfd-util.c (renamed from src/shared/memfd.c)56
-rw-r--r--src/shared/memfd-util.h (renamed from src/shared/memfd.h)2
-rw-r--r--src/shared/mempool.c9
-rw-r--r--src/shared/mempool.h1
-rw-r--r--src/shared/missing.h125
-rw-r--r--src/shared/mkdir.c4
-rw-r--r--src/shared/pager.c28
-rw-r--r--src/shared/path-util.c6
-rw-r--r--src/shared/path-util.h2
-rw-r--r--src/shared/ptyfwd.c536
-rw-r--r--src/shared/ptyfwd.h9
-rw-r--r--src/shared/selinux-util.c16
-rw-r--r--src/shared/selinux-util.h2
-rw-r--r--src/shared/set.c166
-rw-r--r--src/shared/set.h120
-rw-r--r--src/shared/sleep-config.c13
-rw-r--r--src/shared/smack-util.c30
-rw-r--r--src/shared/smack-util.h1
-rw-r--r--src/shared/socket-label.c12
-rw-r--r--src/shared/socket-util.c14
-rw-r--r--src/shared/spawn-ask-password-agent.c4
-rw-r--r--src/shared/spawn-polkit-agent.c4
-rw-r--r--src/shared/strv.c122
-rw-r--r--src/shared/strv.h7
-rw-r--r--src/shared/switch-root.c58
-rw-r--r--src/shared/time-dst.c2
-rw-r--r--src/shared/udev-util.h2
-rw-r--r--src/shared/uid-range.c4
-rw-r--r--src/shared/unaligned.h66
-rw-r--r--src/shared/unit-name.c87
-rw-r--r--src/shared/unit-name.h4
-rw-r--r--src/shared/utf8.c55
-rw-r--r--src/shared/utf8.h8
-rw-r--r--src/shared/util.c744
-rw-r--r--src/shared/util.h53
-rw-r--r--src/shared/virt.c22
-rw-r--r--src/shared/watchdog.c34
-rw-r--r--src/shutdownd/shutdownd.c34
-rw-r--r--src/sleep/sleep.c49
-rw-r--r--src/socket-proxy/socket-proxyd.c90
-rw-r--r--src/sysctl/sysctl.c19
-rw-r--r--src/system-update-generator/system-update-generator.c8
-rw-r--r--src/systemctl/systemctl.c820
-rw-r--r--src/systemd/sd-bus.h122
-rw-r--r--src/systemd/sd-dhcp-client.h4
-rw-r--r--src/systemd/sd-dhcp-lease.h5
-rw-r--r--src/systemd/sd-dhcp6-client.h5
-rw-r--r--src/systemd/sd-event.h4
-rw-r--r--src/systemd/sd-pppoe.h53
-rw-r--r--src/systemd/sd-rtnl.h12
-rw-r--r--src/sysusers/sysusers.c169
-rw-r--r--src/sysv-generator/sysv-generator.c30
-rw-r--r--src/test/test-architecture.c3
-rw-r--r--src/test/test-boot-timestamps.c6
-rw-r--r--src/test/test-cap-list.c47
-rw-r--r--src/test/test-capability.c2
-rw-r--r--src/test/test-cgroup-util.c2
-rw-r--r--src/test/test-condition-util.c107
-rw-r--r--src/test/test-condition.c194
-rw-r--r--src/test/test-conf-files.c2
-rw-r--r--src/test/test-copy.c141
-rw-r--r--src/test/test-engine.c6
-rw-r--r--src/test/test-execute.c178
-rw-r--r--src/test/test-fileio.c74
-rw-r--r--src/test/test-hashmap-plain.c30
-rw-r--r--src/test/test-hostname.c2
-rw-r--r--src/test/test-libudev.c15
-rw-r--r--src/test/test-locale-util.c59
-rw-r--r--src/test/test-ns.c4
-rw-r--r--src/test/test-path-util.c39
-rw-r--r--src/test/test-path.c271
-rw-r--r--src/test/test-socket-util.c2
-rw-r--r--src/test/test-strv.c69
-rw-r--r--src/test/test-tables.c4
-rw-r--r--src/test/test-udev.c14
-rw-r--r--src/test/test-uid-range.c2
-rw-r--r--src/test/test-unaligned.c93
-rw-r--r--src/test/test-unit-file.c22
-rw-r--r--src/test/test-unit-name.c2
-rw-r--r--src/test/test-utf8.c30
-rw-r--r--src/test/test-util.c68
-rw-r--r--src/test/test-watchdog.c4
-rw-r--r--src/timedate/timedatectl.c10
-rw-r--r--src/timedate/timedated.c68
-rw-r--r--src/timesync/timesyncd-conf.c9
-rw-r--r--src/timesync/timesyncd-manager.c98
-rw-r--r--src/timesync/timesyncd.c10
-rw-r--r--src/timesync/timesyncd.conf.in3
-rw-r--r--src/tmpfiles/tmpfiles.c296
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c38
-rw-r--r--src/udev/accelerometer/accelerometer.c11
-rw-r--r--src/udev/ata_id/ata_id.c12
-rw-r--r--src/udev/cdrom_id/cdrom_id.c13
-rw-r--r--src/udev/collect/collect.c10
-rw-r--r--src/udev/net/ethtool-util.c18
-rw-r--r--src/udev/net/link-config-gperf.gperf1
-rw-r--r--src/udev/net/link-config.c68
-rw-r--r--src/udev/net/link-config.h6
-rw-r--r--src/udev/scsi_id/scsi_id.c17
-rw-r--r--src/udev/scsi_id/scsi_serial.c8
-rw-r--r--src/udev/udev-builtin-keyboard.c6
-rw-r--r--src/udev/udev-builtin-kmod.c24
-rw-r--r--src/udev/udev-builtin-net_setup_link.c4
-rw-r--r--src/udev/udev-builtin-path_id.c108
-rw-r--r--src/udev/udev-builtin-uaccess.c4
-rw-r--r--src/udev/udev-ctrl.c18
-rw-r--r--src/udev/udev-event.c55
-rw-r--r--src/udev/udev-node.c14
-rw-r--r--src/udev/udev-rules.c66
-rw-r--r--src/udev/udev-watch.c10
-rw-r--r--src/udev/udev.h16
-rw-r--r--src/udev/udevadm-hwdb.c8
-rw-r--r--src/udev/udevadm-info.c30
-rw-r--r--src/udev/udevadm-monitor.c6
-rw-r--r--src/udev/udevadm-test.c6
-rw-r--r--src/udev/udevadm-trigger.c80
-rw-r--r--src/udev/udevadm-util.c49
-rw-r--r--src/udev/udevadm-util.h22
-rw-r--r--src/udev/udevadm.c8
-rw-r--r--src/udev/udevd.c137
-rw-r--r--src/update-done/update-done.c42
-rw-r--r--src/update-utmp/update-utmp.c28
-rw-r--r--src/vconsole/90-vconsole.rules.in11
-rw-r--r--src/vconsole/vconsole-setup.c42
475 files changed, 22865 insertions, 11328 deletions
diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c
index bd1b6ecc72..2f25734612 100644
--- a/src/ac-power/ac-power.c
+++ b/src/ac-power/ac-power.c
@@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {
r = on_ac_power();
if (r < 0) {
- log_error("Failed to read AC status: %s", strerror(-r));
+ log_error_errno(r, "Failed to read AC status: %m");
return EXIT_FAILURE;
}
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 0a1df37f35..2689934c40 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -51,10 +51,8 @@ static int add_epoll(int epoll_fd, int fd) {
ev.data.fd = fd;
r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev);
- if (r < 0) {
- log_error("Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to add event on epoll fd:%d for fd:%d: %m", epoll_fd, fd);
return 0;
}
@@ -65,11 +63,8 @@ static int open_sockets(int *epoll_fd, bool accept) {
int count = 0;
n = sd_listen_fds(true);
- if (n < 0) {
- log_error("Failed to read listening file descriptors from environment: %s",
- strerror(-n));
- return n;
- }
+ if (n < 0)
+ return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
if (n > 0) {
log_info("Received %i descriptors via the environment.", n);
@@ -103,8 +98,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
fd = make_socket_fd(LOG_DEBUG, *address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC));
if (fd < 0) {
log_open();
- log_error("Failed to open '%s': %s", *address, strerror(-fd));
- return fd;
+ return log_error_errno(fd, "Failed to open '%s': %m", *address);
}
assert(fd == SD_LISTEN_FDS_START + count);
@@ -115,10 +109,8 @@ static int open_sockets(int *epoll_fd, bool accept) {
log_open();
*epoll_fd = epoll_create1(EPOLL_CLOEXEC);
- if (*epoll_fd < 0) {
- log_error("Failed to create epoll object: %m");
- return -errno;
- }
+ if (*epoll_fd < 0)
+ return log_error_errno(errno, "Failed to create epoll object: %m");
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + count; fd++) {
_cleanup_free_ char *name = NULL;
@@ -179,7 +171,7 @@ static int launch(char* name, char **argv, char **env, int fds) {
log_info("Execing %s (%s)", name, tmp);
execvpe(name, argv, envp);
- log_error("Failed to execp %s (%s): %m", name, tmp);
+ log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
return -errno;
}
@@ -196,28 +188,26 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
parent_pid = getpid();
child_pid = fork();
- if (child_pid < 0) {
- log_error("Failed to fork: %m");
- return -errno;
- }
+ if (child_pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
/* In the child */
if (child_pid == 0) {
r = dup2(fd, STDIN_FILENO);
if (r < 0) {
- log_error("Failed to dup connection to stdin: %m");
+ log_error_errno(errno, "Failed to dup connection to stdin: %m");
_exit(EXIT_FAILURE);
}
r = dup2(fd, STDOUT_FILENO);
if (r < 0) {
- log_error("Failed to dup connection to stdout: %m");
+ log_error_errno(errno, "Failed to dup connection to stdout: %m");
_exit(EXIT_FAILURE);
}
r = close(fd);
if (r < 0) {
- log_error("Failed to close dupped connection: %m");
+ log_error_errno(errno, "Failed to close dupped connection: %m");
_exit(EXIT_FAILURE);
}
@@ -231,7 +221,7 @@ static int launch1(const char* child, char** argv, char **env, int fd) {
_exit(EXIT_SUCCESS);
execvp(child, argv);
- log_error("Failed to exec child %s: %m", child);
+ log_error_errno(errno, "Failed to exec child %s: %m", child);
_exit(EXIT_FAILURE);
}
@@ -246,7 +236,7 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) {
fd2 = accept(fd, NULL, NULL);
if (fd2 < 0) {
- log_error("Failed to accept connection on fd:%d: %m", fd);
+ log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
return fd2;
}
@@ -275,7 +265,7 @@ static int install_chld_handler(void) {
r = sigaction(SIGCHLD, &act, 0);
if (r < 0)
- log_error("Failed to install SIGCHLD handler: %m");
+ log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
return r;
}
@@ -393,7 +383,7 @@ int main(int argc, char **argv, char **envp) {
if (errno == EINTR)
continue;
- log_error("epoll_wait() failed: %m");
+ log_error_errno(errno, "epoll_wait() failed: %m");
return EXIT_FAILURE;
}
diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
index 5b16b6c3d9..f569109268 100644
--- a/src/analyze/analyze-verify.c
+++ b/src/analyze/analyze-verify.c
@@ -74,7 +74,7 @@ static int verify_socket(Unit *u) {
/* This makes sure instance is created if necessary. */
r = socket_instantiate_service(SOCKET(u));
if (r < 0) {
- log_error_unit(u->id, "Socket %s cannot be started, failed to create instance.",
+ log_unit_error(u->id, "Socket %s cannot be started, failed to create instance.",
u->id);
return r;
}
@@ -84,10 +84,10 @@ static int verify_socket(Unit *u) {
Service *service;
service = SERVICE(UNIT_DEREF(SOCKET(u)->service));
- log_debug_unit(u->id, "%s uses %s", u->id, UNIT(service)->id);
+ log_unit_debug(u->id, "%s uses %s", u->id, UNIT(service)->id);
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_error_unit(u->id, "Service %s not loaded, %s cannot be started.",
+ log_unit_error(u->id, "Service %s not loaded, %s cannot be started.",
UNIT(service)->id, u->id);
return -ENOENT;
}
@@ -101,7 +101,7 @@ static int verify_executable(Unit *u, ExecCommand *exec) {
return 0;
if (access(exec->path, X_OK) < 0) {
- log_error_unit(u->id, "%s: command %s is not executable: %m",
+ log_unit_error(u->id, "%s: command %s is not executable: %m",
u->id, exec->path);
return -errno;
}
@@ -145,15 +145,15 @@ static int verify_documentation(Unit *u, bool check_man) {
int r = 0, k;
STRV_FOREACH(p, u->documentation) {
- log_debug_unit(u->id, "%s: found documentation item %s.", u->id, *p);
+ log_unit_debug(u->id, "%s: found documentation item %s.", u->id, *p);
if (check_man && startswith(*p, "man:")) {
k = show_man_page(*p + 4, true);
if (k != 0) {
if (k < 0)
- log_error_unit(u->id, "%s: can't show %s: %s",
+ log_unit_error(u->id, "%s: can't show %s: %s",
u->id, *p, strerror(-r));
else {
- log_error_unit(u->id, "%s: man %s command failed with code %d",
+ log_unit_error(u->id, "%s: man %s command failed with code %d",
u->id, *p + 4, k);
k = -ENOEXEC;
}
@@ -178,13 +178,13 @@ static int verify_unit(Unit *u, bool check_man) {
if (log_get_max_level() >= LOG_DEBUG)
unit_dump(u, stdout, "\t");
- log_debug_unit(u->id, "Creating %s/start job", u->id);
+ log_unit_debug(u->id, "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_error_unit(u->id, "Error: %s: %s",
+ log_unit_error(u->id, "Error: %s: %s",
err.name, err.message);
if (r < 0)
- log_error_unit(u->id, "Failed to create %s/start: %s",
+ log_unit_error(u->id, "Failed to create %s/start: %s",
u->id, strerror(-r));
k = verify_socket(u);
@@ -221,24 +221,20 @@ int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man)
/* set the path */
r = generate_path(&var, filenames);
- if (r < 0) {
- log_error("Failed to generate unit load path: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate unit load path: %m");
assert_se(set_unit_path(var) >= 0);
r = manager_new(running_as, true, &m);
- if (r < 0) {
- log_error("Failed to initalize manager: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to initalize manager: %m");
log_debug("Starting manager...");
r = manager_startup(m, serial, fdset);
if (r < 0) {
- log_error("Failed to start manager: %s", strerror(-r));
+ log_error_errno(r, "Failed to start manager: %m");
goto finish;
}
@@ -260,7 +256,7 @@ int verify_units(char **filenames, SystemdRunningAs running_as, bool check_man)
} else
k = manager_load_unit(m, NULL, *filename, &err, &units[count]);
if (k < 0) {
- log_error("Failed to load %s: %s", *filename, strerror(-k));
+ log_error_errno(k, "Failed to load %s: %m", *filename);
if (r == 0)
r = k;
} else
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 5e55988063..9a5fd741c7 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -1362,7 +1362,7 @@ int main(int argc, char *argv[]) {
r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index 0a2bac6f16..1271a66983 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -211,7 +211,7 @@ static unsigned get_max_brightness(struct udev_device *device) {
r = safe_atou(max_brightness_str, &max_brightness);
if (r < 0) {
- log_warning("Failed to parse 'max_brightness' \"%s\": %s", max_brightness_str, strerror(-r));
+ log_warning_errno(r, "Failed to parse 'max_brightness' \"%s\": %m", max_brightness_str);
return 0;
}
@@ -235,7 +235,7 @@ static void clamp_brightness(struct udev_device *device, char **value, unsigned
r = safe_atou(*value, &brightness);
if (r < 0) {
- log_warning("Failed to parse brightness \"%s\": %s", *value, strerror(-r));
+ log_warning_errno(r, "Failed to parse brightness \"%s\": %m", *value);
return;
}
@@ -285,8 +285,7 @@ int main(int argc, char *argv[]) {
r = mkdir_p("/var/lib/systemd/backlight", 0755);
if (r < 0) {
- log_error("Failed to create backlight directory /var/lib/systemd/backlight: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to create backlight directory /var/lib/systemd/backlight: %m");
return EXIT_FAILURE;
}
@@ -319,7 +318,7 @@ int main(int argc, char *argv[]) {
device = udev_device_new_from_subsystem_sysname(udev, ss, sysname);
if (!device) {
if (errno != 0)
- log_error("Failed to get backlight or LED device '%s:%s': %m", ss, sysname);
+ log_error_errno(errno, "Failed to get backlight or LED device '%s:%s': %m", ss, sysname);
else
log_oom();
@@ -387,7 +386,7 @@ int main(int argc, char *argv[]) {
if (r == -ENOENT)
return EXIT_SUCCESS;
- log_error("Failed to read %s: %s", saved, strerror(-r));
+ log_error_errno(r, "Failed to read %s: %m", saved);
return EXIT_FAILURE;
}
@@ -395,8 +394,7 @@ int main(int argc, char *argv[]) {
r = udev_device_set_sysattr_value(device, "brightness", value);
if (r < 0) {
- log_error("Failed to write system 'brightness' attribute: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to write system 'brightness' attribute: %m");
return EXIT_FAILURE;
}
@@ -416,7 +414,7 @@ int main(int argc, char *argv[]) {
r = write_string_file(saved, value);
if (r < 0) {
- log_error("Failed to write %s: %s", saved, strerror(-r));
+ log_error_errno(r, "Failed to write %s: %m", saved);
return EXIT_FAILURE;
}
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index c1c152239b..089b7754a4 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -36,15 +36,7 @@
#include "fileio.h"
#include "build.h"
-static const char conf_file_dirs[] =
- "/etc/binfmt.d\0"
- "/run/binfmt.d\0"
- "/usr/local/lib/binfmt.d\0"
- "/usr/lib/binfmt.d\0"
-#ifdef HAVE_SPLIT_USR
- "/lib/binfmt.d\0"
-#endif
- ;
+static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
static int delete_rule(const char *rule) {
_cleanup_free_ char *x = NULL, *fn = NULL;
@@ -72,10 +64,8 @@ static int apply_rule(const char *rule) {
delete_rule(rule);
r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule);
- if (r < 0) {
- log_error("Failed to add binary format: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add binary format: %m");
return 0;
}
@@ -91,8 +81,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
if (ignore_enoent && r == -ENOENT)
return 0;
- log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
}
log_debug("apply: %s", path);
@@ -104,7 +93,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
if (feof(f))
break;
- log_error("Failed to read file '%s', ignoring: %m", path);
+ log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
return -errno;
}
@@ -199,7 +188,7 @@ int main(int argc, char *argv[]) {
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
- log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
+ log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
goto finish;
}
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 813e38deeb..0808ba44ea 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -125,10 +125,9 @@ static void parse_conf(void) {
{ NULL, NULL, NULL, 0, NULL }
};
- config_parse(NULL, BOOTCHART_CONF, NULL,
- NULL,
- config_item_table_lookup, items,
- true, false, true, NULL);
+ config_parse_many(BOOTCHART_CONF,
+ CONF_DIRS_NULSTR("systemd/bootchart.conf"),
+ NULL, config_item_table_lookup, items, true, NULL);
if (init != NULL)
strscpy(arg_init_path, sizeof(arg_init_path), init);
@@ -194,8 +193,8 @@ static int parse_argv(int argc, char *argv[]) {
case 'f':
r = safe_atod(optarg, &arg_hz);
if (r < 0)
- log_warning("failed to parse --freq/-f argument '%s': %s",
- optarg, strerror(-r));
+ log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m",
+ optarg);
break;
case 'F':
arg_filter = false;
@@ -209,8 +208,8 @@ static int parse_argv(int argc, char *argv[]) {
case 'n':
r = safe_atoi(optarg, &arg_samples_len);
if (r < 0)
- log_warning("failed to parse --samples/-n argument '%s': %s",
- optarg, strerror(-r));
+ log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m",
+ optarg);
break;
case 'o':
path_kill_slashes(optarg);
@@ -226,14 +225,14 @@ static int parse_argv(int argc, char *argv[]) {
case 'x':
r = safe_atod(optarg, &arg_scale_x);
if (r < 0)
- log_warning("failed to parse --scale-x/-x argument '%s': %s",
- optarg, strerror(-r));
+ log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m",
+ optarg);
break;
case 'y':
r = safe_atod(optarg, &arg_scale_y);
if (r < 0)
- log_warning("failed to parse --scale-y/-y argument '%s': %s",
- optarg, strerror(-r));
+ log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m",
+ optarg);
break;
case 'e':
arg_entropy = true;
@@ -285,12 +284,12 @@ static void do_journal_append(char *file) {
f = open(file, O_RDONLY|O_CLOEXEC);
if (f < 0) {
- log_error("Failed to read bootchart data: %m");
+ log_error_errno(errno, "Failed to read bootchart data: %m");
return;
}
n = loop_read(f, p + 10, BOOTCHART_MAX, false);
if (n < 0) {
- log_error("Failed to read bootchart data: %s", strerror(-n));
+ log_error_errno(n, "Failed to read bootchart data: %m");
close(f);
return;
}
@@ -302,7 +301,7 @@ static void do_journal_append(char *file) {
r = sd_journal_sendv(iovec, j);
if (r < 0)
- log_error("Failed to send bootchart: %s", strerror(-r));
+ log_error_errno(r, "Failed to send bootchart: %m");
}
int main(int argc, char *argv[]) {
@@ -434,7 +433,7 @@ int main(int argc, char *argv[]) {
/* caught signal, probably HUP! */
break;
}
- log_error("nanosleep() failed: %m");
+ log_error_errno(errno, "nanosleep() failed: %m");
exit(EXIT_FAILURE);
}
} else {
diff --git a/src/bootchart/bootchart.conf b/src/bootchart/bootchart.conf
index d7e0dabe09..c73328fde2 100644
--- a/src/bootchart/bootchart.conf
+++ b/src/bootchart/bootchart.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/bootchart.conf.d/*.conf.
+#
# See bootchart.conf(5) for details
[Bootchart]
diff --git a/src/bootchart/store.c b/src/bootchart/store.c
index 9ea1b27de4..a66387c304 100644
--- a/src/bootchart/store.c
+++ b/src/bootchart/store.c
@@ -146,7 +146,7 @@ void log_sample(int sample, struct list_sample_data **ptr) {
/* block stuff */
vmstat = openat(procfd, "vmstat", O_RDONLY);
if (vmstat == -1) {
- log_error("Failed to open /proc/vmstat: %m");
+ log_error_errno(errno, "Failed to open /proc/vmstat: %m");
exit(EXIT_FAILURE);
}
}
@@ -178,7 +178,7 @@ vmstat_next:
/* overall CPU utilization */
schedstat = openat(procfd, "schedstat", O_RDONLY);
if (schedstat == -1) {
- log_error("Failed to open /proc/schedstat: %m");
+ log_error_errno(errno, "Failed to open /proc/schedstat: %m");
exit(EXIT_FAILURE);
}
}
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index faf377e506..e5569e1622 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -39,6 +39,7 @@
#include "svg.h"
#include "bootchart.h"
#include "list.h"
+#include "utf8.h"
#define time_to_graph(t) ((t) * arg_scale_x)
#define ps_to_graph(n) ((n) * arg_scale_y)
@@ -1006,12 +1007,15 @@ static void svg_ps_bars(void) {
/* pass 2 - ps boxes */
ps = ps_first;
while ((ps = get_next_ps(ps))) {
- _cleanup_free_ char *enc_name = NULL;
+ _cleanup_free_ char *enc_name = NULL, *escaped = NULL;
double endtime;
double starttime;
int t;
- enc_name = xml_comment_encode(ps->name);
+ if (!utf8_is_printable(ps->name, strlen(ps->name)))
+ escaped = utf8_escape_non_printable(ps->name);
+
+ enc_name = xml_comment_encode(escaped ? escaped : ps->name);
if (!enc_name)
continue;
@@ -1100,7 +1104,7 @@ static void svg_ps_bars(void) {
svg(" <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n",
time_to_graph(w - graph_start) + 5.0,
ps_to_graph(j) + 14.0,
- ps->name,
+ escaped ? escaped : ps->name,
ps->pid,
(ps->last->runtime - ps->first->runtime) / 1000000000.0,
arg_show_cgroup ? ps->cgroup : "");
diff --git a/src/bus-proxyd/bus-policy.c b/src/bus-proxyd/bus-policy.c
index 625f5ddaee..59cc1d788b 100644
--- a/src/bus-proxyd/bus-policy.c
+++ b/src/bus-proxyd/bus-policy.c
@@ -95,8 +95,7 @@ static int file_load(Policy *p, const char *path) {
if (r == -EISDIR)
return r;
- log_error("Failed to load %s: %s", path, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to load %s: %m", path);
}
q = c;
@@ -105,10 +104,8 @@ static int file_load(Policy *p, const char *path) {
int t;
t = xml_tokenize(&q, &name, &xml_state, &line);
- if (t < 0) {
- log_error("XML parse failure in %s: %s", path, strerror(-t));
- return t;
- }
+ if (t < 0)
+ return log_error_errno(t, "XML parse failure in %s: %m", path);
switch (state) {
@@ -358,7 +355,7 @@ static int file_load(Policy *p, const char *path) {
r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
if (r < 0) {
- log_error("Failed to resolve user %s, ignoring policy: %s", u, strerror(-r));
+ log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
free(i);
} else {
PolicyItem *first;
@@ -390,7 +387,7 @@ static int file_load(Policy *p, const char *path) {
r = get_group_creds(&g, &i->gid);
if (r < 0) {
- log_error("Failed to resolve group %s, ignoring policy: %s", g, strerror(-r));
+ log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
free(i);
} else {
PolicyItem *first;
@@ -533,7 +530,7 @@ static int file_load(Policy *p, const char *path) {
r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
if (r < 0)
- log_error("Failed to resolve user %s: %s", name, strerror(-r));
+ log_error_errno(r, "Failed to resolve user %s: %m", name);
else
i->uid_valid = true;
}
@@ -544,7 +541,7 @@ static int file_load(Policy *p, const char *path) {
r = get_group_creds(&g, &i->gid);
if (r < 0)
- log_error("Failed to resolve group %s: %s", name, strerror(-r));
+ log_error_errno(r, "Failed to resolve group %s: %m", name);
else
i->gid_valid = true;
}
@@ -593,14 +590,29 @@ static int file_load(Policy *p, const char *path) {
}
enum {
+ DENY,
ALLOW,
DUNNO,
- DENY,
};
+static const char *verdict_to_string(int v) {
+ switch (v) {
+
+ case DENY:
+ return "DENY";
+ case ALLOW:
+ return "ALLOW";
+ case DUNNO:
+ return "DUNNO";
+ }
+
+ return NULL;
+}
+
struct policy_check_filter {
- int class;
- const struct ucred *ucred;
+ PolicyItemClass class;
+ uid_t uid;
+ gid_t gid;
int message_type;
const char *name;
const char *interface;
@@ -627,7 +639,7 @@ static int check_policy_item(PolicyItem *i, const struct policy_check_filter *fi
if (i->name && !streq_ptr(i->name, filter->name))
break;
- if ((i->message_type != _POLICY_ITEM_CLASS_UNSET) && (i->message_type != filter->message_type))
+ if ((i->message_type != 0) && (i->message_type != filter->message_type))
break;
if (i->path && !streq_ptr(i->path, filter->path))
@@ -651,22 +663,20 @@ static int check_policy_item(PolicyItem *i, const struct policy_check_filter *fi
case POLICY_ITEM_OWN_PREFIX:
assert(filter->name);
- if (streq(i->name, "*") || startswith(i->name, filter->name))
+ if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
return is_permissive(i);
break;
case POLICY_ITEM_USER:
- assert(filter->ucred);
-
- if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->ucred->uid)))
- return is_permissive(i);
+ if (filter->uid != UID_INVALID)
+ if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
+ return is_permissive(i);
break;
case POLICY_ITEM_GROUP:
- assert(filter->ucred);
-
- if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->ucred->gid)))
- return is_permissive(i);
+ if (filter->gid != GID_INVALID)
+ if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
+ return is_permissive(i);
break;
case POLICY_ITEM_IGNORE:
@@ -680,97 +690,130 @@ static int check_policy_item(PolicyItem *i, const struct policy_check_filter *fi
static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
PolicyItem *i;
- int r, ret = DUNNO;
+ int verdict = DUNNO;
assert(filter);
/* Check all policies in a set - a broader one might be followed by a more specific one,
* and the order of rules in policy definitions matters */
LIST_FOREACH(items, i, items) {
- if (i->class != filter->class)
+ int v;
+
+ if (i->class != filter->class &&
+ !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
continue;
- r = check_policy_item(i, filter);
- if (r != DUNNO)
- ret = r;
+ v = check_policy_item(i, filter);
+ if (v != DUNNO)
+ verdict = v;
}
- return ret;
+ return verdict;
}
static int policy_check(Policy *p, const struct policy_check_filter *filter) {
PolicyItem *items;
- int r;
+ int verdict, v;
assert(p);
assert(filter);
+ assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
+
/*
* The policy check is implemented by the following logic:
*
- * 1. Check mandatory items. If the message matches any of these, it is decisive.
- * 2. See if the passed ucred match against the user/group hashmaps. A matching entry is also decisive.
- * 3. Consult the defaults if non of the above matched with a more specific rule.
- * 4. If the message isn't caught be the defaults either, reject it.
+ * 1. Check default items
+ * 2. Check group items
+ * 3. Check user items
+ * 4. Check mandatory items
+ *
+ * Later rules override earlier rules.
*/
- r = check_policy_items(p->mandatory_items, filter);
- if (r != DUNNO)
- return r;
+ verdict = check_policy_items(p->default_items, filter);
- if (filter->ucred) {
- items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->ucred->uid));
+ if (filter->gid != GID_INVALID) {
+ items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid));
if (items) {
- r = check_policy_items(items, filter);
- if (r != DUNNO)
- return r;
+ v = check_policy_items(items, filter);
+ if (v != DUNNO)
+ verdict = v;
}
+ }
- items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->ucred->gid));
+ if (filter->uid != UID_INVALID) {
+ items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid));
if (items) {
- r = check_policy_items(items, filter);
- if (r != DUNNO)
- return r;
+ v = check_policy_items(items, filter);
+ if (v != DUNNO)
+ verdict = v;
}
}
- return check_policy_items(p->default_items, filter);
+ v = check_policy_items(p->mandatory_items, filter);
+ if (v != DUNNO)
+ verdict = v;
+
+ return verdict;
}
-bool policy_check_own(Policy *p, const struct ucred *ucred, const char *name) {
+bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
struct policy_check_filter filter = {
.class = POLICY_ITEM_OWN,
- .ucred = ucred,
+ .uid = uid,
+ .gid = gid,
.name = name,
};
- return policy_check(p, &filter) == ALLOW;
+ int verdict;
+
+ assert(p);
+ assert(name);
+
+ verdict = policy_check(p, &filter);
+
+ log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+ "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
+ uid, gid, strna(name), strna(verdict_to_string(verdict)));
+
+ return verdict == ALLOW;
}
-bool policy_check_hello(Policy *p, const struct ucred *ucred) {
+bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
struct policy_check_filter filter = {
- .ucred = ucred,
+ .uid = uid,
+ .gid = gid,
};
- int user, group;
+ int verdict;
+
+ assert(p);
filter.class = POLICY_ITEM_USER;
- user = policy_check(p, &filter);
- if (user == DENY)
- return false;
+ verdict = policy_check(p, &filter);
- filter.class = POLICY_ITEM_GROUP;
- group = policy_check(p, &filter);
- if (group == DENY)
- return false;
+ if (verdict != DENY) {
+ int v;
- return !(user == DUNNO && group == DUNNO);
+ filter.class = POLICY_ITEM_GROUP;
+ v = policy_check(p, &filter);
+ if (v != DUNNO)
+ verdict = v;
+ }
+
+ log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+ "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
+ uid, gid, strna(verdict_to_string(verdict)));
+
+ return verdict == ALLOW;
}
bool policy_check_recv(Policy *p,
- const struct ucred *ucred,
+ uid_t uid,
+ gid_t gid,
int message_type,
const char *name,
const char *path,
@@ -779,7 +822,8 @@ bool policy_check_recv(Policy *p,
struct policy_check_filter filter = {
.class = POLICY_ITEM_RECV,
- .ucred = ucred,
+ .uid = uid,
+ .gid = gid,
.message_type = message_type,
.name = name,
.interface = interface,
@@ -787,11 +831,22 @@ bool policy_check_recv(Policy *p,
.member = member,
};
- return policy_check(p, &filter) == ALLOW;
+ int verdict;
+
+ assert(p);
+
+ verdict = policy_check(p, &filter);
+
+ log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+ "Recieve permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
+ uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
+
+ return verdict == ALLOW;
}
bool policy_check_send(Policy *p,
- const struct ucred *ucred,
+ uid_t uid,
+ gid_t gid,
int message_type,
const char *name,
const char *path,
@@ -800,7 +855,8 @@ bool policy_check_send(Policy *p,
struct policy_check_filter filter = {
.class = POLICY_ITEM_SEND,
- .ucred = ucred,
+ .uid = uid,
+ .gid = gid,
.message_type = message_type,
.name = name,
.interface = interface,
@@ -808,7 +864,17 @@ bool policy_check_send(Policy *p,
.member = member,
};
- return policy_check(p, &filter) == ALLOW;
+ int verdict;
+
+ assert(p);
+
+ verdict = policy_check(p, &filter);
+
+ log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
+ "Send permission check for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s interface=%s path=%s member=%s: %s",
+ uid, gid, bus_message_type_to_string(message_type), strna(name), strna(path), strna(interface), strna(member), strna(verdict_to_string(verdict)));
+
+ return verdict == ALLOW;
}
int policy_load(Policy *p, char **files) {
@@ -825,10 +891,8 @@ int policy_load(Policy *p, char **files) {
char **j;
r = conf_files_list(&l, ".conf", NULL, *i, NULL);
- if (r < 0) {
- log_error("Failed to get configuration file list: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get configuration file list: %m");
STRV_FOREACH(j, l)
file_load(p, *j);
@@ -936,6 +1000,7 @@ static void dump_items(PolicyItem *items, const char *prefix) {
printf("%sGroup: %s (%d)\n",
prefix, strna(group), i->gid);
}
+ printf("%s-\n", prefix);
}
}
diff --git a/src/bus-proxyd/bus-policy.h b/src/bus-proxyd/bus-policy.h
index 64fe1ffac5..933a53ceb5 100644
--- a/src/bus-proxyd/bus-policy.h
+++ b/src/bus-proxyd/bus-policy.h
@@ -76,17 +76,19 @@ typedef struct Policy {
int policy_load(Policy *p, char **files);
void policy_free(Policy *p);
-bool policy_check_own(Policy *p, const struct ucred *ucred, const char *name);
-bool policy_check_hello(Policy *p, const struct ucred *ucred);
+bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name);
+bool policy_check_hello(Policy *p, uid_t uid, gid_t gid);
bool policy_check_recv(Policy *p,
- const struct ucred *ucred,
+ uid_t uid,
+ gid_t gid,
int message_type,
const char *name,
const char *path,
const char *interface,
const char *member);
bool policy_check_send(Policy *p,
- const struct ucred *ucred,
+ uid_t uid,
+ gid_t gid,
int message_type,
const char *name,
const char *path,
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index 8c1b6a5ad6..5d304538fd 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -45,6 +45,8 @@
#include "def.h"
#include "capability.h"
#include "bus-policy.h"
+#include "bus-control.h"
+#include "smack-util.h"
static char *arg_address = NULL;
static char *arg_command_line_buffer = NULL;
@@ -61,7 +63,7 @@ static int help(void) {
" --configuration=PATH Configuration file or directory\n"
" --machine=MACHINE Connect to specified machine\n"
" --address=ADDRESS Connect to the bus specified by ADDRESS\n"
- " (default: " DEFAULT_SYSTEM_BUS_PATH ")\n",
+ " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
program_invocation_short_name);
return 0;
@@ -166,7 +168,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (!arg_address) {
- arg_address = strdup(DEFAULT_SYSTEM_BUS_PATH);
+ arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
if (!arg_address)
return log_oom();
}
@@ -309,48 +311,6 @@ static int synthesize_name_acquired(sd_bus *a, sd_bus *b, sd_bus_message *m) {
return sd_bus_send(b, n, NULL);
}
-static int process_policy(sd_bus *a, sd_bus *b, sd_bus_message *m) {
- _cleanup_bus_message_unref_ sd_bus_message *n = NULL;
- int r;
-
- assert(a);
- assert(b);
- assert(m);
-
- if (!a->is_kernel)
- return 0;
-
- if (!sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Properties", "GetAll"))
- return 0;
-
- if (!streq_ptr(m->path, "/org/gnome/DisplayManager/Slave"))
- return 0;
-
- r = sd_bus_message_new_method_errorf(m, &n, SD_BUS_ERROR_ACCESS_DENIED, "gdm, you are stupid");
- if (r < 0)
- return r;
-
- r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0) {
- log_error("Failed to append sender to gdm reply: %s", strerror(-r));
- return r;
- }
-
- r = bus_seal_synthetic_message(b, n);
- if (r < 0) {
- log_error("Failed to seal gdm reply: %s", strerror(-r));
- return r;
- }
-
- r = sd_bus_send(b, n, NULL);
- if (r < 0) {
- log_error("Failed to send gdm reply: %s", strerror(-r));
- return r;
- }
-
- return 1;
-}
-
static int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
int r;
@@ -452,8 +412,6 @@ static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bu
assert(name);
assert(_creds);
- assert_return(service_name_is_valid(name), -EINVAL);
-
r = sd_bus_get_name_creds(bus, name, mask, &c);
if (r == -ESRCH || r == -ENXIO)
return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
@@ -484,30 +442,7 @@ static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, s
return get_creds_by_name(bus, name, mask, _creds, error);
}
-static int peer_is_privileged(sd_bus *bus, sd_bus_message *m) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- uid_t uid;
- int r;
-
- r = get_creds_by_message(bus, m, SD_BUS_CREDS_UID, &creds, NULL);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_uid(creds, &uid);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_has_effective_cap(creds, CAP_SYS_ADMIN);
- if (r > 0)
- return true;
-
- if (uid == getuid())
- return true;
-
- return false;
-}
-
-static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
+static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m, Policy *policy, const struct ucred *ucred, Set *owned_names) {
int r;
assert(a);
@@ -520,14 +455,12 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
return 0;
- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- if (0 && !isempty(sd_bus_message_get_signature(m, true))) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ /* The "Hello()" call is is handled in process_hello() */
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_INVALID_ARGS, "Expected no parameters");
+ if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- return synthetic_reply_method_errno(m, r, &error);
- }
+ if (!sd_bus_message_has_signature(m, ""))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
return synthetic_reply_method_return(m, "s",
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
@@ -617,6 +550,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
const char *match;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &match);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -630,6 +566,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
const char *match;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &match);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -646,6 +585,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
@@ -656,6 +598,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
@@ -666,6 +611,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = get_creds_by_message(a, m, SD_BUS_CREDS_UID, &creds, &error);
if (r < 0)
return synthetic_reply_method_errno(m, r, &error);
@@ -676,7 +624,10 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
sd_id128_t server_id;
char buf[SD_ID128_STRING_MAX];
- r = sd_bus_get_server_id(a, &server_id);
+ if (!sd_bus_message_has_signature(m, ""))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
+ r = sd_bus_get_bus_id(a, &server_id);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -687,6 +638,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &name);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -700,11 +654,12 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
return synthetic_reply_method_return(m, "s", creds->unique_name);
- /* "Hello" is handled in process_hello() */
-
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
_cleanup_strv_free_ char **names = NULL;
+ if (!sd_bus_message_has_signature(m, ""))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_list_names(a, NULL, &names);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -717,6 +672,9 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
_cleanup_strv_free_ char **names = NULL;
+ if (!sd_bus_message_has_signature(m, ""))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_list_names(a, &names, NULL);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -733,20 +691,19 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
struct kdbus_cmd_name_list cmd = {};
struct kdbus_name_list *name_list;
- struct kdbus_cmd_free cmd_free;
struct kdbus_name_info *name;
_cleanup_strv_free_ char **owners = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
char *arg0;
int err = 0;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &arg0);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- if (!service_name_is_valid(arg0))
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
-
r = sd_bus_get_name_creds(a, arg0, 0, NULL);
if (r == -ESRCH || r == -ENXIO) {
sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
@@ -768,8 +725,8 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
char *n;
KDBUS_ITEM_FOREACH(item, name, items)
- if (item->type == KDBUS_ITEM_NAME)
- entry_name = item->str;
+ if (item->type == KDBUS_ITEM_OWNED_NAME)
+ entry_name = item->name.name;
if (!streq_ptr(entry_name, arg0))
continue;
@@ -786,10 +743,7 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
}
}
- cmd_free.flags = 0;
- cmd_free.offset = cmd.offset;
-
- r = ioctl(a->input_fd, KDBUS_CMD_FREE, &cmd_free);
+ r = bus_kernel_cmd_free(a, cmd.offset);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
@@ -801,13 +755,13 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
const char *name;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &name);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- if (!service_name_is_valid(name))
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
-
if (streq(name, "org.freedesktop.DBus"))
return synthetic_reply_method_return(m, "b", true);
@@ -820,13 +774,13 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
const char *name;
+ if (!sd_bus_message_has_signature(m, "s"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "s", &name);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- if (!service_name_is_valid(name))
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
-
r = sd_bus_release_name(a, name);
if (r < 0) {
if (r == -ESRCH)
@@ -837,11 +791,16 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
return synthetic_reply_method_errno(m, r, NULL);
}
+ set_remove(owned_names, (char*) name);
+
return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ if (!sd_bus_message_has_signature(m, ""))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_error_setf(&error, SD_BUS_ERROR_NOT_SUPPORTED, "%s() is not supported", sd_bus_message_get_member(m));
return synthetic_reply_method_errno(m, r, &error);
@@ -849,13 +808,18 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
const char *name;
uint32_t flags, param;
+ bool in_queue;
+
+ if (!sd_bus_message_has_signature(m, "su"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
r = sd_bus_message_read(m, "su", &name, &flags);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- if (!service_name_is_valid(name))
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
+ if (policy && !policy_check_own(policy, ucred->uid, ucred->gid, name))
+ return synthetic_reply_method_errno(m, -EPERM, NULL);
+
if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
return synthetic_reply_method_errno(m, -EINVAL, NULL);
@@ -867,16 +831,25 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
if (!(flags & BUS_NAME_DO_NOT_QUEUE))
param |= SD_BUS_NAME_QUEUE;
+ r = set_put_strdup(owned_names, name);
+ if (r < 0)
+ return synthetic_reply_method_errno(m, r, NULL);
+
r = sd_bus_request_name(a, name, param);
if (r < 0) {
- if (r == -EEXIST)
- return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
if (r == -EALREADY)
return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
+
+ set_remove(owned_names, (char*) name);
+
+ if (r == -EEXIST)
+ return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
return synthetic_reply_method_errno(m, r, NULL);
}
- if (r == 0)
+ in_queue = (r == 0);
+
+ if (in_queue)
return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
@@ -886,12 +859,13 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
const char *name;
uint32_t flags;
+ if (!sd_bus_message_has_signature(m, "su"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
+
r = sd_bus_message_read(m, "su", &name, &flags);
if (r < 0)
return synthetic_reply_method_errno(m, r, NULL);
- if (!service_name_is_valid(name))
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
if (flags != 0)
return synthetic_reply_method_errno(m, -EINVAL, NULL);
@@ -921,8 +895,8 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
_cleanup_bus_message_unref_ sd_bus_message *msg = NULL;
_cleanup_strv_free_ char **args = NULL;
- if (!peer_is_privileged(a, m))
- return synthetic_reply_method_errno(m, -EPERM, NULL);
+ if (!sd_bus_message_has_signature(m, "a{ss}"))
+ return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
if (r < 0)
@@ -986,6 +960,166 @@ static int process_driver(sd_bus *a, sd_bus *b, sd_bus_message *m) {
}
}
+static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
+ int r;
+
+ assert(from);
+ assert(to);
+ assert(m);
+
+ if (!policy)
+ return 0;
+
+ if (from->is_kernel) {
+ uid_t sender_uid = UID_INVALID;
+ gid_t sender_gid = GID_INVALID;
+ char **sender_names = NULL;
+ bool granted = false;
+
+ /* Driver messages are always OK */
+ if (streq_ptr(m->sender, "org.freedesktop.DBus"))
+ return 0;
+
+ /* The message came from the kernel, and is sent to our legacy client. */
+ r = sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
+ if (r < 0)
+ return r;
+
+ (void) sd_bus_creds_get_uid(&m->creds, &sender_uid);
+ (void) sd_bus_creds_get_gid(&m->creds, &sender_gid);
+
+ /* First check whether the sender can send the message to our name */
+ if (set_isempty(owned_names)) {
+ if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, NULL, m->path, m->interface, m->member))
+ granted = true;
+ } else {
+ Iterator i;
+ char *n;
+
+ SET_FOREACH(n, owned_names, i)
+ if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, n, m->path, m->interface, m->member)) {
+ granted = true;
+ break;
+ }
+ }
+
+ if (granted) {
+ /* Then check whether us (the recipient) can recieve from the sender's name */
+ if (strv_isempty(sender_names)) {
+ if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
+ return 0;
+ } else {
+ char **n;
+
+ STRV_FOREACH(n, sender_names) {
+ if (policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member))
+ return 0;
+ }
+ }
+ }
+
+ /* Return an error back to the caller */
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
+
+ /* Return 1, indicating that the message shall not be processed any further */
+ return 1;
+ }
+
+ if (to->is_kernel) {
+ _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL;
+ uid_t destination_uid = UID_INVALID;
+ gid_t destination_gid = GID_INVALID;
+ const char *destination_unique = NULL;
+ char **destination_names = NULL;
+ bool granted = false;
+
+ /* Driver messages are always OK */
+ if (streq_ptr(m->destination, "org.freedesktop.DBus"))
+ return 0;
+
+ /* The message came from the legacy client, and is sent to kdbus. */
+ if (m->destination) {
+ r = bus_get_name_creds_kdbus(to, m->destination,
+ SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
+ SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID,
+ true, &destination_creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
+ if (r < 0)
+ return r;
+
+ (void) sd_bus_creds_get_uid(destination_creds, &destination_uid);
+ (void) sd_bus_creds_get_gid(destination_creds, &destination_gid);
+ }
+
+ /* First check if we (the sender) can send to this name */
+ if (strv_isempty(destination_names)) {
+ if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, m->path, m->interface, m->member))
+ granted = true;
+ } else {
+ char **n;
+
+ STRV_FOREACH(n, destination_names) {
+ if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, *n, m->path, m->interface, m->member)) {
+
+ /* If we made a receiver decision,
+ then remember which name's policy
+ we used, and to which unique ID it
+ mapped when we made the
+ decision. Then, let's pass this to
+ the kernel when sending the
+ message, so that it refuses the
+ operation should the name and
+ unique ID not map to each other
+ anymore. */
+
+ r = free_and_strdup(&m->destination_ptr, *n);
+ if (r < 0)
+ return r;
+
+ r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
+ if (r < 0)
+ break;
+
+ granted = true;
+ break;
+ }
+ }
+ }
+
+ /* Then check if the recipient can receive from our name */
+ if (granted) {
+ if (set_isempty(owned_names)) {
+ if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, NULL, m->path, m->interface, m->member))
+ return 0;
+ } else {
+ Iterator i;
+ char *n;
+
+ SET_FOREACH(n, owned_names, i)
+ if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, n, m->path, m->interface, m->member))
+ return 0;
+ }
+ }
+
+ /* Return an error back to the caller */
+ if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
+ return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
+
+ /* Return 1, indicating that the message shall not be processed any further */
+ return 1;
+ }
+
+ return 0;
+}
+
static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hello) {
_cleanup_bus_message_unref_ sd_bus_message *n = NULL;
bool is_hello;
@@ -1024,34 +1158,24 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hell
return 0;
r = sd_bus_message_new_method_return(m, &n);
- if (r < 0) {
- log_error("Failed to generate HELLO reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate HELLO reply: %m");
r = sd_bus_message_append(n, "s", a->unique_name);
- if (r < 0) {
- log_error("Failed to append unique name to HELLO reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0) {
- log_error("Failed to append sender to HELLO reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
r = bus_seal_synthetic_message(b, n);
- if (r < 0) {
- log_error("Failed to seal HELLO reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to seal HELLO reply: %m");
r = sd_bus_send(b, n, NULL);
- if (r < 0) {
- log_error("Failed to send HELLO reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send HELLO reply: %m");
n = sd_bus_message_unref(n);
r = sd_bus_message_new_signal(
@@ -1060,34 +1184,24 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hell
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"NameAcquired");
- if (r < 0) {
- log_error("Failed to allocate initial NameAcquired message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
r = sd_bus_message_append(n, "s", a->unique_name);
- if (r < 0) {
- log_error("Failed to append unique name to NameAcquired message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0) {
- log_error("Failed to append sender to NameAcquired message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
r = bus_seal_synthetic_message(b, n);
- if (r < 0) {
- log_error("Failed to seal NameAcquired message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to seal NameAcquired message: %m");
r = sd_bus_send(b, n, NULL);
- if (r < 0) {
- log_error("Failed to send NameAcquired message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send NameAcquired message: %m");
return 1;
}
@@ -1122,6 +1236,23 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) {
return 0;
}
+static int mac_smack_apply_label_and_drop_cap_mac_admin(pid_t its_pid, const char *new_label) {
+#ifdef HAVE_SMACK
+ int r = 0, k;
+
+ if (!mac_smack_use())
+ return 0;
+
+ if (new_label && its_pid > 0)
+ r = mac_smack_apply_pid(its_pid, new_label);
+
+ k = drop_capability(CAP_MAC_ADMIN);
+ return r < 0 ? r : k;
+#else
+ return 0;
+#endif
+}
+
int main(int argc, char *argv[]) {
_cleanup_bus_close_unref_ sd_bus *a = NULL, *b = NULL;
@@ -1131,7 +1262,8 @@ int main(int argc, char *argv[]) {
bool is_unix;
struct ucred ucred = {};
_cleanup_free_ char *peersec = NULL;
- Policy policy = {};
+ Policy policy_buffer = {}, *policy = NULL;
+ _cleanup_set_free_free_ Set *owned_names = NULL;
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_parse_environment();
@@ -1141,14 +1273,6 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = policy_load(&policy, arg_configuration);
- if (r < 0) {
- log_error("Failed to load policy: %s", strerror(-r));
- goto finish;
- }
-
- /* policy_dump(&policy); */
-
r = sd_listen_fds(0);
if (r == 0) {
in_fd = STDIN_FILENO;
@@ -1168,6 +1292,10 @@ int main(int argc, char *argv[]) {
if (is_unix) {
(void) getpeercred(in_fd, &ucred);
(void) getpeersec(in_fd, &peersec);
+
+ r = mac_smack_apply_label_and_drop_cap_mac_admin(getpid(), peersec);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set SMACK label (%s) and drop CAP_MAC_ADMIN: %m", peersec);
}
if (arg_drop_privileges) {
@@ -1177,7 +1305,7 @@ int main(int argc, char *argv[]) {
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
- log_error("Cannot resolve user name %s: %s", user, strerror(-r));
+ log_error_errno(r, "Cannot resolve user name %s: %m", user);
goto finish;
}
@@ -1186,34 +1314,54 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ owned_names = set_new(&string_hash_ops);
+ if (!owned_names) {
+ log_oom();
+ goto finish;
+ }
+
r = sd_bus_new(&a);
if (r < 0) {
- log_error("Failed to allocate bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate bus: %m");
goto finish;
}
- r = sd_bus_set_name(a, "sd-proxy");
+ r = sd_bus_set_description(a, "sd-proxy");
if (r < 0) {
- log_error("Failed to set bus name: %s", strerror(-r));
+ log_error_errno(r, "Failed to set bus name: %m");
goto finish;
}
r = sd_bus_set_address(a, arg_address);
if (r < 0) {
- log_error("Failed to set address to connect to: %s", strerror(-r));
+ log_error_errno(r, "Failed to set address to connect to: %m");
goto finish;
}
r = sd_bus_negotiate_fds(a, is_unix);
if (r < 0) {
- log_error("Failed to set FD negotiation: %s", strerror(-r));
+ log_error_errno(r, "Failed to set FD negotiation: %m");
+ goto finish;
+ }
+
+ r = sd_bus_negotiate_creds(a, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set credential negotiation: %m");
goto finish;
}
if (ucred.pid > 0) {
- a->fake_creds.pid = ucred.pid;
+ a->fake_pids.pid = ucred.pid;
+ a->fake_pids_valid = true;
+
a->fake_creds.uid = ucred.uid;
+ a->fake_creds.euid = UID_INVALID;
+ a->fake_creds.suid = UID_INVALID;
+ a->fake_creds.fsuid = UID_INVALID;
a->fake_creds.gid = ucred.gid;
+ a->fake_creds.egid = GID_INVALID;
+ a->fake_creds.sgid = GID_INVALID;
+ a->fake_creds.fsgid = GID_INVALID;
a->fake_creds_valid = true;
}
@@ -1226,43 +1374,97 @@ int main(int argc, char *argv[]) {
r = sd_bus_start(a);
if (r < 0) {
- log_error("Failed to start bus client: %s", strerror(-r));
+ log_error_errno(r, "Failed to start bus client: %m");
goto finish;
}
- r = sd_bus_get_server_id(a, &server_id);
+ r = sd_bus_get_bus_id(a, &server_id);
if (r < 0) {
- log_error("Failed to get server ID: %s", strerror(-r));
+ log_error_errno(r, "Failed to get server ID: %m");
goto finish;
}
+ if (a->is_kernel) {
+ if (!arg_configuration) {
+ const char *scope;
+
+ r = sd_bus_get_scope(a, &scope);
+ if (r < 0) {
+ log_error_errno(r, "Couldn't determine bus scope: %m");
+ goto finish;
+ }
+
+ if (streq(scope, "system"))
+ arg_configuration = strv_new(
+ "/etc/dbus-1/system.conf",
+ "/etc/dbus-1/system.d/",
+ "/etc/dbus-1/system-local.conf",
+ NULL);
+ else if (streq(scope, "user"))
+ arg_configuration = strv_new(
+ "/etc/dbus-1/session.conf",
+ "/etc/dbus-1/session.d/",
+ "/etc/dbus-1/session-local.conf",
+ NULL);
+ else {
+ log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
+ goto finish;
+ }
+
+ if (!arg_configuration) {
+ r = log_oom();
+ goto finish;
+ }
+ }
+
+ r = policy_load(&policy_buffer, arg_configuration);
+ if (r < 0) {
+ log_error_errno(r, "Failed to load policy: %m");
+ goto finish;
+ }
+
+ policy = &policy_buffer;
+ /* policy_dump(policy); */
+
+ if (!policy_check_hello(policy, ucred.uid, ucred.gid)) {
+ r = log_error_errno(EPERM, "Policy denied connection.");
+ goto finish;
+ }
+ }
+
r = sd_bus_new(&b);
if (r < 0) {
- log_error("Failed to allocate bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate bus: %m");
goto finish;
}
r = sd_bus_set_fd(b, in_fd, out_fd);
if (r < 0) {
- log_error("Failed to set fds: %s", strerror(-r));
+ log_error_errno(r, "Failed to set fds: %m");
goto finish;
}
r = sd_bus_set_server(b, 1, server_id);
if (r < 0) {
- log_error("Failed to set server mode: %s", strerror(-r));
+ log_error_errno(r, "Failed to set server mode: %m");
goto finish;
}
r = sd_bus_negotiate_fds(b, is_unix);
if (r < 0) {
- log_error("Failed to set FD negotiation: %s", strerror(-r));
+ log_error_errno(r, "Failed to set FD negotiation: %m");
+ goto finish;
+ }
+
+ r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set credential negotiation: %m");
goto finish;
}
r = sd_bus_set_anonymous(b, true);
if (r < 0) {
- log_error("Failed to set anonymous authentication: %s", strerror(-r));
+ log_error_errno(r, "Failed to set anonymous authentication: %m");
goto finish;
}
@@ -1270,13 +1472,13 @@ int main(int argc, char *argv[]) {
r = sd_bus_start(b);
if (r < 0) {
- log_error("Failed to start bus client: %s", strerror(-r));
+ log_error_errno(r, "Failed to start bus client: %m");
goto finish;
}
r = rename_service(a, b);
if (r < 0)
- log_debug("Failed to rename process: %s", strerror(-r));
+ log_debug_errno(r, "Failed to rename process: %m");
if (a->is_kernel) {
_cleanup_free_ char *match = NULL;
@@ -1284,7 +1486,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_get_unique_name(a, &unique);
if (r < 0) {
- log_error("Failed to get unique name: %s", strerror(-r));
+ log_error_errno(r, "Failed to get unique name: %m");
goto finish;
}
@@ -1304,7 +1506,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_add_match(a, NULL, match, NULL, NULL);
if (r < 0) {
- log_error("Failed to add match for NameLost: %s", strerror(-r));
+ log_error_errno(r, "Failed to add match for NameLost: %m");
goto finish;
}
@@ -1325,7 +1527,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_add_match(a, NULL, match, NULL, NULL);
if (r < 0) {
- log_error("Failed to add match for NameAcquired: %s", strerror(-r));
+ log_error_errno(r, "Failed to add match for NameAcquired: %m");
goto finish;
}
}
@@ -1339,18 +1541,22 @@ int main(int argc, char *argv[]) {
int k;
if (got_hello) {
+ /* Read messages from bus, to pass them on to our client */
+
r = sd_bus_process(a, &m);
if (r < 0) {
/* treat 'connection reset by peer' as clean exit condition */
if (r == -ECONNRESET)
r = 0;
else
- log_error("Failed to process bus a: %s", strerror(-r));
+ log_error_errno(r, "Failed to process bus a: %m");
goto finish;
}
if (m) {
+ bool processed = false;
+
/* We officially got EOF, let's quit */
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
r = 0;
@@ -1360,22 +1566,37 @@ int main(int argc, char *argv[]) {
k = synthesize_name_acquired(a, b, m);
if (k < 0) {
r = k;
- log_error("Failed to synthesize message: %s", strerror(-r));
+ log_error_errno(r, "Failed to synthesize message: %m");
goto finish;
}
patch_sender(a, m);
- k = sd_bus_send(b, m, NULL);
- if (k < 0) {
- if (k == -ECONNRESET)
- r = 0;
- else {
+ if (policy) {
+ k = process_policy(a, b, m, policy, &ucred, owned_names);
+ if (k < 0) {
r = k;
- log_error("Failed to send message: %s", strerror(-r));
+ log_error_errno(r, "Failed to process policy: %m");
+ goto finish;
+ } else if (k > 0) {
+ r = 1;
+ processed = true;
}
+ }
- goto finish;
+ if (!processed) {
+ k = sd_bus_send(b, m, NULL);
+ if (k < 0) {
+ if (k == -ECONNRESET)
+ r = 0;
+ else {
+ r = k;
+ log_error_errno(r, "Failed to send message to client: %m");
+ }
+
+ goto finish;
+ } else
+ r = 1;
}
}
@@ -1383,18 +1604,21 @@ int main(int argc, char *argv[]) {
continue;
}
+ /* Read messages from our client, to pass them on to the bus */
r = sd_bus_process(b, &m);
if (r < 0) {
/* treat 'connection reset by peer' as clean exit condition */
if (r == -ECONNRESET)
r = 0;
else
- log_error("Failed to process bus b: %s", strerror(-r));
+ log_error_errno(r, "Failed to process bus b: %m");
goto finish;
}
if (m) {
+ bool processed = false;
+
/* We officially got EOF, let's quit */
if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected")) {
r = 0;
@@ -1404,40 +1628,57 @@ int main(int argc, char *argv[]) {
k = process_hello(a, b, m, &got_hello);
if (k < 0) {
r = k;
- log_error("Failed to process HELLO: %s", strerror(-r));
+ log_error_errno(r, "Failed to process HELLO: %m");
goto finish;
+ } else if (k > 0) {
+ processed = true;
+ r = 1;
}
- if (k > 0)
- r = k;
- else {
- k = process_policy(a, b, m);
- if (k < 0) {
- r = k;
- log_error("Failed to process policy: %s", strerror(-r));
- goto finish;
- }
-
- k = process_driver(a, b, m);
+ if (!processed) {
+ k = process_driver(a, b, m, policy, &ucred, owned_names);
if (k < 0) {
r = k;
- log_error("Failed to process driver calls: %s", strerror(-r));
+ log_error_errno(r, "Failed to process driver calls: %m");
goto finish;
+ } else if (k > 0) {
+ processed = true;
+ r = 1;
}
- if (k > 0)
- r = k;
- else {
- k = sd_bus_send(a, m, NULL);
- if (k < 0) {
- if (k == -ECONNRESET)
- r = 0;
- else {
- r = k;
- log_error("Failed to send message: %s", strerror(-r));
+ if (!processed) {
+
+ for (;;) {
+ if (policy) {
+ k = process_policy(b, a, m, policy, &ucred, owned_names);
+ if (k < 0) {
+ r = k;
+ log_error_errno(r, "Failed to process policy: %m");
+ goto finish;
+ } else if (k > 0) {
+ processed = true;
+ r = 1;
+ break;
+ }
}
- goto finish;
+ k = sd_bus_send(a, m, NULL);
+ if (k < 0) {
+ if (k == -EREMCHG)
+ /* The name database changed since the policy check, hence let's check again */
+ continue;
+ else if (k == -ECONNRESET)
+ r = 0;
+ else {
+ r = k;
+ log_error_errno(r, "Failed to send message to bus: %m");
+ }
+
+ goto finish;
+ } else
+ r = 1;
+
+ break;
}
}
}
@@ -1448,31 +1689,31 @@ int main(int argc, char *argv[]) {
fd = sd_bus_get_fd(a);
if (fd < 0) {
- log_error("Failed to get fd: %s", strerror(-r));
+ log_error_errno(r, "Failed to get fd: %m");
goto finish;
}
events_a = sd_bus_get_events(a);
if (events_a < 0) {
- log_error("Failed to get events mask: %s", strerror(-r));
+ log_error_errno(r, "Failed to get events mask: %m");
goto finish;
}
r = sd_bus_get_timeout(a, &timeout_a);
if (r < 0) {
- log_error("Failed to get timeout: %s", strerror(-r));
+ log_error_errno(r, "Failed to get timeout: %m");
goto finish;
}
events_b = sd_bus_get_events(b);
if (events_b < 0) {
- log_error("Failed to get events mask: %s", strerror(-r));
+ log_error_errno(r, "Failed to get events mask: %m");
goto finish;
}
r = sd_bus_get_timeout(b, &timeout_b);
if (r < 0) {
- log_error("Failed to get timeout: %s", strerror(-r));
+ log_error_errno(r, "Failed to get timeout: %m");
goto finish;
}
@@ -1502,7 +1743,7 @@ int main(int argc, char *argv[]) {
r = ppoll(pollfd, 3, ts, NULL);
if (r < 0) {
- log_error("ppoll() failed: %m");
+ log_error_errno(errno, "ppoll() failed: %m");
goto finish;
}
}
@@ -1512,7 +1753,7 @@ finish:
"STOPPING=1\n"
"STATUS=Shutting down.");
- policy_free(&policy);
+ policy_free(&policy_buffer);
strv_free(arg_configuration);
free(arg_address);
diff --git a/src/bus-proxyd/test-bus-policy.c b/src/bus-proxyd/test-bus-policy.c
index c9a027e877..91ab33da4a 100644
--- a/src/bus-proxyd/test-bus-policy.c
+++ b/src/bus-proxyd/test-bus-policy.c
@@ -62,41 +62,29 @@ static int test_policy_load(Policy *p, const char *name)
int main(int argc, char *argv[]) {
Policy p = {};
- struct ucred ucred = {};
/* Ownership tests */
assert_se(test_policy_load(&p, "ownerships.conf") == 0);
- ucred.uid = 0;
- assert_se(policy_check_own(&p, &ucred, "org.test.test1") == true);
- ucred.uid = 1;
- assert_se(policy_check_own(&p, &ucred, "org.test.test1") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true);
+ assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true);
- ucred.uid = 0;
- assert_se(policy_check_own(&p, &ucred, "org.test.test2") == true);
- ucred.uid = 1;
- assert_se(policy_check_own(&p, &ucred, "org.test.test2") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true);
+ assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false);
- ucred.uid = 0;
- assert_se(policy_check_own(&p, &ucred, "org.test.test3") == false);
- ucred.uid = 1;
- assert_se(policy_check_own(&p, &ucred, "org.test.test3") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false);
+ assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false);
- ucred.uid = 0;
- assert_se(policy_check_own(&p, &ucred, "org.test.test4") == false);
- ucred.uid = 1;
- assert_se(policy_check_own(&p, &ucred, "org.test.test4") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false);
+ assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true);
policy_free(&p);
/* Signaltest */
assert_se(test_policy_load(&p, "signals.conf") == 0);
- ucred.uid = 0;
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true);
-
- ucred.uid = 1;
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true);
+ assert_se(policy_check_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false);
policy_free(&p);
@@ -104,14 +92,12 @@ int main(int argc, char *argv[]) {
assert_se(test_policy_load(&p, "methods.conf") == 0);
policy_dump(&p);
- ucred.uid = 0;
-
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true);
- assert_se(policy_check_send(&p, &ucred, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true);
- assert_se(policy_check_recv(&p, &ucred, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true);
+ assert_se(policy_check_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true);
policy_free(&p);
@@ -119,15 +105,54 @@ int main(int argc, char *argv[]) {
assert_se(test_policy_load(&p, "hello.conf") == 0);
policy_dump(&p);
- ucred.uid = 0;
- assert_se(policy_check_hello(&p, &ucred) == true);
+ assert_se(policy_check_hello(&p, 0, 0) == true);
+ assert_se(policy_check_hello(&p, 1, 0) == false);
+ assert_se(policy_check_hello(&p, 0, 1) == false);
+
+ policy_free(&p);
+
+ /* dbus1 test file: ownership */
+
+ assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0);
+ policy_dump(&p);
+
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false);
- ucred.uid = 1;
- assert_se(policy_check_hello(&p, &ucred) == false);
+ policy_free(&p);
+
+ /* dbus1 test file: many rules */
+
+ assert_se(test_policy_load(&p, "many-rules.conf") >= 0);
+ policy_dump(&p);
+ policy_free(&p);
+
+ /* dbus1 test file: generic test */
+
+ assert_se(test_policy_load(&p, "test.conf") >= 0);
+ policy_dump(&p);
- ucred.uid = 0;
- ucred.gid = 1;
- assert_se(policy_check_hello(&p, &ucred) == false);
+ assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true);
+ assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
+ assert_se(policy_check_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+ assert_se(policy_check_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+ assert_se(policy_check_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
+ assert_se(policy_check_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
+
+ assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false);
+ assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false);
+ assert_se(policy_check_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
+ assert_se(policy_check_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
+ assert_se(policy_check_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
+ assert_se(policy_check_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
+ assert_se(policy_check_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
policy_free(&p);
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 7070503d68..f400bccc0a 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -155,7 +155,7 @@ int main(int argc, char *argv[]) {
r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
@@ -186,7 +186,7 @@ int main(int argc, char *argv[]) {
p = get_current_dir_name();
if (!p) {
- log_error("Cannot determine current working directory: %m");
+ log_error_errno(errno, "Cannot determine current working directory: %m");
goto finish;
}
@@ -206,7 +206,7 @@ int main(int argc, char *argv[]) {
m = strappenda("/run/systemd/machines/", arg_machine);
r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL);
if (r < 0) {
- log_error("Failed to get machine path: %s", strerror(-r));
+ log_error_errno(r, "Failed to get machine path: %m");
goto finish;
}
@@ -246,8 +246,8 @@ int main(int argc, char *argv[]) {
} else
r = cg_get_root_path(&root);
if (r < 0) {
- log_error("Failed to get %s path: %s",
- arg_machine ? "machine" : "root", strerror(-r));
+ log_error_errno(r, "Failed to get %s path: %m",
+ arg_machine ? "machine" : "root");
goto finish;
}
@@ -257,7 +257,7 @@ int main(int argc, char *argv[]) {
}
if (r < 0) {
- log_error("Failed to list cgroup tree %s: %s", root, strerror(-r));
+ log_error_errno(r, "Failed to list cgroup tree %s: %m", root);
retval = EXIT_FAILURE;
} else
retval = EXIT_SUCCESS;
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
index e581fbc9b6..529e843030 100644
--- a/src/cgroups-agent/cgroups-agent.c
+++ b/src/cgroups-agent/cgroups-agent.c
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
/* If we couldn't connect we assume this was triggered
* while systemd got restarted/transitioned from
* initrd to the system, so let's ignore this */
- log_debug("Failed to get D-Bus connection: %s", strerror(-r));
+ log_debug_errno(r, "Failed to get D-Bus connection: %m");
return EXIT_FAILURE;
}
@@ -58,7 +58,7 @@ int main(int argc, char *argv[]) {
"Released",
"s", argv[1]);
if (r < 0) {
- log_debug("Failed to send signal message on private connection: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send signal message on private connection: %m");
return EXIT_FAILURE;
}
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 932a7ba7c6..3c7ad40605 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -748,7 +748,7 @@ int main(int argc, char *argv[]) {
if (r == -ETIMEDOUT)
continue;
if (r < 0) {
- log_error("Couldn't read key: %s", strerror(-r));
+ log_error_errno(r, "Couldn't read key: %m");
goto finish;
}
}
@@ -842,7 +842,7 @@ finish:
group_hashmap_free(b);
if (r < 0) {
- log_error("Exiting with failure: %s", strerror(-r));
+ log_error_errno(r, "Exiting with failure: %m");
return EXIT_FAILURE;
}
diff --git a/src/console/consoled-manager.c b/src/console/consoled-manager.c
index 1b856f2228..9dd62f04a0 100644
--- a/src/console/consoled-manager.c
+++ b/src/console/consoled-manager.c
@@ -141,16 +141,14 @@ static int manager_sysview_session_add(Manager *m, sysview_event *event) {
int r;
r = sysview_session_take_control(session);
- if (r < 0) {
- log_error("Cannot request session control on '%s': %s",
- sysview_session_get_name(session), strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot request session control on '%s': %m",
+ sysview_session_get_name(session));
r = session_new(&s, m, session);
if (r < 0) {
- log_error("Cannot create session on '%s': %s",
- sysview_session_get_name(session), strerror(-r));
+ log_error_errno(r, "Cannot create session on '%s': %m",
+ sysview_session_get_name(session));
sysview_session_release_control(session);
return r;
}
@@ -226,8 +224,8 @@ static int manager_sysview_session_control(Manager *m, sysview_event *event) {
return 0;
if (error < 0) {
- log_error("Cannot take session control on '%s': %s",
- sysview_session_get_name(session), strerror(-error));
+ log_error_errno(error, "Cannot take session control on '%s': %m",
+ sysview_session_get_name(session));
session_free(s);
sysview_session_set_userdata(session, NULL);
return -error;
diff --git a/src/console/consoled-session.c b/src/console/consoled-session.c
index 8bacacab35..927965e02c 100644
--- a/src/console/consoled-session.c
+++ b/src/console/consoled-session.c
@@ -106,8 +106,8 @@ static void session_grdev_fn(grdev_session *grdev, void *userdata, grdev_event *
r = display_new(&d, s, display);
if (r < 0) {
- log_error("Cannot create display '%s' on '%s': %s",
- grdev_display_get_name(display), sysview_session_get_name(s->sysview), strerror(-r));
+ log_error_errno(r, "Cannot create display '%s' on '%s': %m",
+ grdev_display_get_name(display), sysview_session_get_name(s->sysview));
break;
}
@@ -231,7 +231,7 @@ void session_dirty(Session *s) {
r = sd_event_source_set_enabled(s->redraw_src, SD_EVENT_ONESHOT);
if (r < 0)
- log_error("Cannot enable redraw-source: %s", strerror(-r));
+ log_error_errno(r, "Cannot enable redraw-source: %m");
}
void session_add_device(Session *s, sysview_device *device) {
diff --git a/src/console/consoled-terminal.c b/src/console/consoled-terminal.c
index d091579aa5..19d14016ad 100644
--- a/src/console/consoled-terminal.c
+++ b/src/console/consoled-terminal.c
@@ -52,7 +52,7 @@ static int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const v
case PTY_DATA:
r = term_screen_feed_text(t->screen, ptr, size);
if (r < 0)
- log_error("Cannot update screen state: %s", strerror(-r));
+ log_error_errno(r, "Cannot update screen state: %m");
workspace_dirty(t->workspace);
break;
@@ -128,12 +128,12 @@ void terminal_resize(Terminal *t) {
if (t->pty) {
r = pty_resize(t->pty, width, height);
if (r < 0)
- log_error("Cannot resize pty: %s", strerror(-r));
+ log_error_errno(r, "Cannot resize pty: %m");
}
r = term_screen_resize(t->screen, width, height);
if (r < 0)
- log_error("Cannot resize screen: %s", strerror(-r));
+ log_error_errno(r, "Cannot resize screen: %m");
}
void terminal_run(Terminal *t) {
@@ -151,7 +151,7 @@ void terminal_run(Terminal *t) {
term_screen_get_width(t->screen),
term_screen_get_height(t->screen));
if (pid < 0) {
- log_error("Cannot fork PTY: %s", strerror(-pid));
+ log_error_errno(pid, "Cannot fork PTY: %m");
return;
} else if (pid == 0) {
/* child */
@@ -165,7 +165,7 @@ void terminal_run(Terminal *t) {
setenv("COLORTERM", "systemd-console", 1);
execve(argv[0], argv, environ);
- log_error("Cannot exec %s (%d): %m", argv[0], -errno);
+ log_error_errno(errno, "Cannot exec %s (%d): %m", argv[0], -errno);
_exit(1);
}
}
@@ -189,8 +189,7 @@ static void terminal_feed_keyboard(Terminal *t, idev_data *data) {
kdata->codepoints,
kdata->mods);
if (r < 0)
- log_error("Cannot feed keyboard data to screen: %s",
- strerror(-r));
+ log_error_errno(r, "Cannot feed keyboard data to screen: %m");
}
}
diff --git a/src/console/consoled.c b/src/console/consoled.c
index b0c9eda1ac..6f65dcdcb9 100644
--- a/src/console/consoled.c
+++ b/src/console/consoled.c
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
r = manager_new(&m);
if (r < 0) {
- log_error("Could not create manager: %s", strerror(-r));
+ log_error_errno(r, "Could not create manager: %m");
goto out;
}
@@ -55,7 +55,7 @@ int main(int argc, char *argv[]) {
r = manager_run(m);
if (r < 0) {
- log_error("Cannot run manager: %s", strerror(-r));
+ log_error_errno(r, "Cannot run manager: %m");
goto out;
}
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index 4326d17360..5a18e263a8 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -41,7 +41,7 @@ int get_audit_fd(void) {
if (audit_fd < 0) {
if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
- log_error("Failed to connect to audit log: %m");
+ log_error_errno(errno, "Failed to connect to audit log: %m");
audit_fd = errno ? -errno : -EINVAL;
}
diff --git a/src/core/automount.c b/src/core/automount.c
index f72aca2957..f795487131 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -75,7 +75,7 @@ static void repeat_unmount(const char *path) {
continue;
if (errno != EINVAL)
- log_error("Failed to unmount: %m");
+ log_error_errno(errno, "Failed to unmount: %m");
break;
}
@@ -151,7 +151,7 @@ static int automount_verify(Automount *a) {
return 0;
if (path_equal(a->where, "/")) {
- log_error_unit(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing.");
+ log_unit_error(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing.");
return -EINVAL;
}
@@ -162,7 +162,7 @@ static int automount_verify(Automount *a) {
b = unit_has_name(UNIT(a), e);
if (!b) {
- log_error_unit(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
+ log_unit_error(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
return -EINVAL;
}
@@ -226,7 +226,7 @@ static void automount_set_state(Automount *a, AutomountState state) {
unmount_autofs(a);
if (state != old_state)
- log_debug_unit(UNIT(a)->id,
+ log_unit_debug(UNIT(a)->id,
"%s changed %s -> %s",
UNIT(a)->id,
automount_state_to_string(old_state),
@@ -300,10 +300,8 @@ static int open_dev_autofs(Manager *m) {
label_fix("/dev/autofs", false, false);
m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
- if (m->dev_autofs_fd < 0) {
- log_error("Failed to open /dev/autofs: %m");
- return -errno;
- }
+ if (m->dev_autofs_fd < 0)
+ return log_error_errno(errno, "Failed to open /dev/autofs: %m");
init_autofs_dev_ioctl(&param);
if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
@@ -422,9 +420,9 @@ int automount_send_ready(Automount *a, int status) {
return ioctl_fd;
if (status)
- log_debug_unit(UNIT(a)->id, "Sending failure: %s", strerror(-status));
+ log_unit_debug_errno(UNIT(a)->id, status, "Sending failure: %m");
else
- log_debug_unit(UNIT(a)->id, "Sending success.");
+ log_unit_debug(UNIT(a)->id, "Sending success.");
r = 0;
@@ -536,7 +534,7 @@ fail:
if (mounted)
repeat_unmount(a->where);
- log_error_unit(UNIT(a)->id,
+ log_unit_error(UNIT(a)->id,
"Failed to initialize automounter: %s", strerror(-r));
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
@@ -551,7 +549,7 @@ static void automount_enter_runnning(Automount *a) {
/* We don't take mount requests anymore if we are supposed to
* shut down anyway */
if (unit_stop_pending(UNIT(a))) {
- log_debug_unit(UNIT(a)->id,
+ log_unit_debug(UNIT(a)->id,
"Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
automount_send_ready(a, -EHOSTDOWN);
return;
@@ -561,19 +559,19 @@ static void automount_enter_runnning(Automount *a) {
/* Before we do anything, let's see if somebody is playing games with us? */
if (lstat(a->where, &st) < 0) {
- log_warning_unit(UNIT(a)->id,
+ log_unit_warning(UNIT(a)->id,
"%s failed to stat automount point: %m", UNIT(a)->id);
goto fail;
}
if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
- log_info_unit(UNIT(a)->id,
+ log_unit_info(UNIT(a)->id,
"%s's automount point already active?", UNIT(a)->id);
else {
r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
JOB_REPLACE, true, &error, NULL);
if (r < 0) {
- log_warning_unit(UNIT(a)->id,
+ log_unit_warning(UNIT(a)->id,
"%s failed to queue mount startup job: %s",
UNIT(a)->id, bus_error_message(&error, r));
goto fail;
@@ -594,7 +592,7 @@ static int automount_start(Unit *u) {
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
if (path_is_mount_point(a->where, false)) {
- log_error_unit(u->id,
+ log_unit_error(u->id,
"Path %s is already a mount point, refusing start for %s",
a->where, u->id);
return -EEXIST;
@@ -659,7 +657,7 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
state = automount_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
a->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -667,7 +665,7 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
f = automount_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != AUTOMOUNT_SUCCESS)
a->result = f;
@@ -675,14 +673,14 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
unsigned d;
if (safe_atou(value, &d) < 0)
- log_debug_unit(u->id, "Failed to parse dev-id value %s", value);
+ log_unit_debug(u->id, "Failed to parse dev-id value %s", value);
else
a->dev_id = (unsigned) d;
} else if (streq(key, "token")) {
unsigned token;
if (safe_atou(value, &token) < 0)
- log_debug_unit(u->id, "Failed to parse token value %s", value);
+ log_unit_debug(u->id, "Failed to parse token value %s", value);
else {
if (!a->tokens)
if (!(a->tokens = set_new(NULL)))
@@ -696,13 +694,13 @@ static int automount_deserialize_item(Unit *u, const char *key, const char *valu
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse pipe-fd value %s", value);
+ log_unit_debug(u->id, "Failed to parse pipe-fd value %s", value);
else {
safe_close(a->pipe_fd);
a->pipe_fd = fdset_remove(fds, fd);
}
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -738,13 +736,16 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
assert(fd == a->pipe_fd);
if (events != EPOLLIN) {
- log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe.");
+ log_unit_error(UNIT(a)->id, "Got invalid poll event on pipe.");
goto fail;
}
l = loop_read(a->pipe_fd, &packet, sizeof(packet), true);
if (l != sizeof(packet)) {
- log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
+ if (l < 0)
+ log_unit_error_errno(UNIT(a)->id, l, "Invalid read from pipe: %m");
+ else
+ log_unit_error(UNIT(a)->id, "Invalid read from pipe: short read");
goto fail;
}
@@ -756,21 +757,21 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
_cleanup_free_ char *p = NULL;
get_process_comm(packet.v5_packet.pid, &p);
- log_info_unit(UNIT(a)->id,
+ log_unit_info(UNIT(a)->id,
"Got automount request for %s, triggered by "PID_FMT" (%s)",
a->where, packet.v5_packet.pid, strna(p));
} else
- log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where);
+ log_unit_debug(UNIT(a)->id, "Got direct mount request on %s", a->where);
r = set_ensure_allocated(&a->tokens, NULL);
if (r < 0) {
- log_error_unit(UNIT(a)->id, "Failed to allocate token set.");
+ log_unit_error(UNIT(a)->id, "Failed to allocate token set.");
goto fail;
}
r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
if (r < 0) {
- log_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r));
+ log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m");
goto fail;
}
@@ -778,7 +779,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
break;
default:
- log_error_unit(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
+ log_unit_error(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
break;
}
diff --git a/src/core/build.h b/src/core/build.h
index d5e55506cf..24873ab9d7 100644
--- a/src/core/build.h
+++ b/src/core/build.h
@@ -154,4 +154,4 @@
_BLKID_FEATURE_ " " \
_ELFUTILS_FEATURE_ " " \
_KMOD_FEATURE_ " " \
- _IDN_FEATURE_ " "
+ _IDN_FEATURE_
diff --git a/src/core/busname.c b/src/core/busname.c
index 68cb6ca7b7..99641ec418 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -19,6 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/mman.h>
+
#include "special.h"
#include "bus-kernel.h"
#include "bus-internal.h"
@@ -26,6 +28,7 @@
#include "service.h"
#include "dbus-busname.h"
#include "busname.h"
+#include "kdbus.h"
static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
[BUSNAME_DEAD] = UNIT_INACTIVE,
@@ -197,13 +200,13 @@ static int busname_verify(BusName *n) {
return 0;
if (!service_name_is_valid(n->name)) {
- log_error_unit(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
+ log_unit_error(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
return -EINVAL;
}
e = strappenda(n->name, ".busname");
if (!unit_has_name(UNIT(n), e)) {
- log_error_unit(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
+ log_unit_error(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
return -EINVAL;
}
@@ -265,7 +268,7 @@ static void busname_unwatch_fd(BusName *n) {
r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_OFF);
if (r < 0)
- log_debug_unit(UNIT(n)->id, "Failed to disable event source.");
+ log_unit_debug(UNIT(n)->id, "Failed to disable event source.");
}
static int busname_watch_fd(BusName *n) {
@@ -281,7 +284,7 @@ static int busname_watch_fd(BusName *n) {
else
r = sd_event_add_io(UNIT(n)->manager->event, &n->starter_event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "Failed to watch starter fd: %s", strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "Failed to watch starter fd: %m");
busname_unwatch_fd(n);
return r;
}
@@ -300,11 +303,8 @@ static int busname_open_fd(BusName *n) {
mode = UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user";
n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
- if (n->starter_fd < 0) {
- log_warning_unit(UNIT(n)->id, "Failed to open %s: %s",
- path ?: "kdbus", strerror(-n->starter_fd));
- return n->starter_fd;
- }
+ if (n->starter_fd < 0)
+ return log_unit_warning_errno(UNIT(n)->id, n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
return 0;
}
@@ -328,7 +328,7 @@ static void busname_set_state(BusName *n, BusNameState state) {
busname_close_fd(n);
if (state != old_state)
- log_debug_unit(UNIT(n)->id, "%s changed %s -> %s",
+ log_unit_debug(UNIT(n)->id, "%s changed %s -> %s",
UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
@@ -407,7 +407,7 @@ static int busname_make_starter(BusName *n, pid_t *_pid) {
fail_child:
log_open();
- log_error("Failed to create starter connection at step %s: %s", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD), strerror(-r));
+ log_error_errno(r, "Failed to create starter connection at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD));
_exit(ret);
}
@@ -451,14 +451,14 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
n->control_pid,
false);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "%s failed to kill control process: %s", UNIT(n)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "%s failed to kill control process: %m", UNIT(n)->id);
goto fail;
}
if (r > 0) {
r = busname_arm_timer(n);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "%s failed to arm timer: %s", UNIT(n)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "%s failed to arm timer: %m", UNIT(n)->id);
goto fail;
}
@@ -482,7 +482,7 @@ static void busname_enter_listening(BusName *n) {
if (n->activating) {
r = busname_watch_fd(n);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "%s failed to watch names: %s", UNIT(n)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "%s failed to watch names: %m", UNIT(n)->id);
goto fail;
}
@@ -513,7 +513,7 @@ static void busname_enter_making(BusName *n) {
r = busname_make_starter(n, &n->control_pid);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "%s failed to fork 'making' task: %s", UNIT(n)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "%s failed to fork 'making' task: %m", UNIT(n)->id);
goto fail;
}
@@ -524,7 +524,7 @@ static void busname_enter_making(BusName *n) {
r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, NULL, n->policy_world);
if (r < 0) {
- log_warning_unit(UNIT(n)->id, "%s failed to make starter: %s", UNIT(n)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(n)->id, r, "%s failed to make starter: %m", UNIT(n)->id);
goto fail;
}
@@ -553,7 +553,7 @@ static void busname_enter_running(BusName *n) {
* shut down anyway */
if (unit_stop_pending(UNIT(n))) {
- log_debug_unit(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
+ log_unit_debug(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
/* Flush all queued activation reqeuest by closing and reopening the connection */
bus_kernel_drop_one(n->starter_fd);
@@ -580,7 +580,7 @@ static void busname_enter_running(BusName *n) {
return;
fail:
- log_warning_unit(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
+ log_unit_warning(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
}
@@ -604,7 +604,7 @@ static int busname_start(Unit *u) {
service = SERVICE(UNIT_DEREF(n->service));
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_error_unit(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
+ log_unit_error(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
return -ENOENT;
}
}
@@ -678,7 +678,7 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
state = busname_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
n->deserialized_state = state;
@@ -687,7 +687,7 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
f = busname_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != BUSNAME_SUCCESS)
n->result = f;
@@ -695,20 +695,20 @@ static int busname_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
else
n->control_pid = pid;
} else if (streq(key, "starter-fd")) {
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse starter fd value %s", value);
+ log_unit_debug(u->id, "Failed to parse starter fd value %s", value);
else {
safe_close(n->starter_fd);
n->starter_fd = fdset_remove(fds, fd);
}
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -725,6 +725,88 @@ _pure_ static const char *busname_sub_state_to_string(Unit *u) {
return busname_state_to_string(BUSNAME(u)->state);
}
+static int busname_peek_message(BusName *n) {
+ struct kdbus_cmd_recv cmd_recv = {
+ .flags = KDBUS_RECV_PEEK,
+ };
+ struct kdbus_cmd_free cmd_free = {};
+ const char *comm = NULL;
+ struct kdbus_item *d;
+ struct kdbus_msg *k;
+ size_t start, ps, sz, delta;
+ void *p = NULL;
+ pid_t pid = 0;
+ int r;
+
+ /* Generate a friendly debug log message about which process
+ * caused triggering of this bus name. This simply peeks the
+ * metadata of the first queued message and logs it. */
+
+ assert(n);
+
+ /* Let's shortcut things a bit, if debug logging is turned off
+ * anyway. */
+
+ if (log_get_max_level() < LOG_DEBUG)
+ return 0;
+
+ r = ioctl(n->starter_fd, KDBUS_CMD_MSG_RECV, &cmd_recv);
+ if (r < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ return 0;
+
+ log_unit_error(UNIT(n)->id, "%s: Failed to query activation message: %m", UNIT(n)->id);
+ return -errno;
+ }
+
+ /* We map as late as possible, and unmap imemdiately after
+ * use. On 32bit address space is scarce and we want to be
+ * able to handle a lot of activator connections at the same
+ * time, and hence shouldn't keep the mmap()s around for
+ * longer than necessary. */
+
+ ps = page_size();
+ start = (cmd_recv.offset / ps) * ps;
+ delta = cmd_recv.offset - start;
+ sz = PAGE_ALIGN(delta + cmd_recv.msg_size);
+
+ p = mmap(NULL, sz, PROT_READ, MAP_SHARED, n->starter_fd, start);
+ if (p == MAP_FAILED) {
+ log_unit_error(UNIT(n)->id, "%s: Failed to map activation message: %m", UNIT(n)->id);
+ r = -errno;
+ goto finish;
+ }
+
+ k = (struct kdbus_msg *) ((uint8_t *) p + delta);
+ KDBUS_ITEM_FOREACH(d, k, items) {
+ switch (d->type) {
+
+ case KDBUS_ITEM_PIDS:
+ pid = d->pids.pid;
+ break;
+
+ case KDBUS_ITEM_PID_COMM:
+ comm = d->str;
+ break;
+ }
+ }
+
+ if (pid > 0)
+ log_unit_debug(UNIT(n)->id, "%s: Activation triggered by process " PID_FMT " (%s)", UNIT(n)->id, pid, strna(comm));
+
+ r = 0;
+
+finish:
+ if (p)
+ (void) munmap(p, sz);
+
+ cmd_free.offset = cmd_recv.offset;
+ if (ioctl(n->starter_fd, KDBUS_CMD_FREE, &cmd_free) < 0)
+ log_unit_warning(UNIT(n)->id, "Failed to free peeked message, ignoring: %m");
+
+ return r;
+}
+
static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
BusName *n = userdata;
@@ -734,14 +816,15 @@ static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents
if (n->state != BUSNAME_LISTENING)
return 0;
- log_debug_unit(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
+ log_unit_debug(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
if (revents != EPOLLIN) {
- log_error_unit(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
+ log_unit_error(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
UNIT(n)->id, revents);
goto fail;
}
+ busname_peek_message(n);
busname_enter_running(n);
return 0;
fail:
@@ -773,8 +856,9 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown sigchld code");
- log_full_unit(f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- u->id, "%s control process exited, code=%s status=%i",
+ log_unit_full(u->id,
+ f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+ "%s control process exited, code=%s status=%i",
u->id, sigchld_code_to_string(code), status);
if (f != BUSNAME_SUCCESS)
@@ -811,17 +895,17 @@ static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *us
switch (n->state) {
case BUSNAME_MAKING:
- log_warning_unit(UNIT(n)->id, "%s making timed out. Terminating.", UNIT(n)->id);
+ log_unit_warning(UNIT(n)->id, "%s making timed out. Terminating.", UNIT(n)->id);
busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_TIMEOUT);
break;
case BUSNAME_SIGTERM:
- log_warning_unit(UNIT(n)->id, "%s stopping timed out. Killing.", UNIT(n)->id);
+ log_unit_warning(UNIT(n)->id, "%s stopping timed out. Killing.", UNIT(n)->id);
busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_FAILURE_TIMEOUT);
break;
case BUSNAME_SIGKILL:
- log_warning_unit(UNIT(n)->id, "%s still around after SIGKILL. Ignoring.", UNIT(n)->id);
+ log_unit_warning(UNIT(n)->id, "%s still around after SIGKILL. Ignoring.", UNIT(n)->id);
busname_enter_dead(n, BUSNAME_FAILURE_TIMEOUT);
break;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index e604c3cbc6..35b862d5c2 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -105,7 +105,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sBlockIOWeight=%lu\n"
"%sStartupBlockIOWeight=%lu\n"
"%sMemoryLimit=%" PRIu64 "\n"
- "%sDevicePolicy=%s\n",
+ "%sDevicePolicy=%s\n"
+ "%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
@@ -115,7 +116,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
prefix, c->memory_limit,
- prefix, cgroup_device_policy_to_string(c->device_policy));
+ prefix, cgroup_device_policy_to_string(c->device_policy),
+ prefix, yes_no(c->delegate));
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f,
@@ -151,10 +153,8 @@ static int lookup_blkio_device(const char *p, dev_t *dev) {
assert(dev);
r = stat(p, &st);
- if (r < 0) {
- log_warning("Couldn't stat device %s: %m", p);
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Couldn't stat device %s: %m", p);
if (S_ISBLK(st.st_mode))
*dev = st.st_rdev;
@@ -216,10 +216,8 @@ static int whitelist_major(const char *path, const char *name, char type, const
assert(type == 'b' || type == 'c');
f = fopen("/proc/devices", "re");
- if (!f) {
- log_warning("Cannot open /proc/devices to resolve %s (%c): %m", name, type);
- return -errno;
- }
+ if (!f)
+ return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type);
FOREACH_LINE(line, f, goto fail) {
char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
@@ -278,7 +276,7 @@ static int whitelist_major(const char *path, const char *name, char type, const
return 0;
fail:
- log_warning("Failed to read /proc/devices: %m");
+ log_warning_errno(errno, "Failed to read /proc/devices: %m");
return -errno;
}
@@ -461,7 +459,8 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
c->memory_limit != (uint64_t) -1)
mask |= CGROUP_MEMORY;
- if (c->device_allow || c->device_policy != CGROUP_AUTO)
+ if (c->device_allow ||
+ c->device_policy != CGROUP_AUTO)
mask |= CGROUP_DEVICE;
return mask;
@@ -474,6 +473,19 @@ CGroupControllerMask unit_get_cgroup_mask(Unit *u) {
if (!c)
return 0;
+ /* If delegation is turned on, then turn on all cgroups,
+ * unless the process we fork into it is known to drop
+ * privileges anyway, and shouldn't get access to the
+ * controllers anyway. */
+
+ if (c->delegate) {
+ ExecContext *e;
+
+ e = unit_get_exec_context(u);
+ if (!e || exec_context_maintains_privileges(e))
+ return _CGROUP_CONTROLLER_MASK_ALL;
+ }
+
return cgroup_context_get_mask(c);
}
@@ -593,40 +605,66 @@ static const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
}
static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
- _cleanup_free_ char *path = NULL;
+ CGroupContext *c;
int r;
assert(u);
- path = unit_default_cgroup_path(u);
- if (!path)
- return log_oom();
+ c = unit_get_cgroup_context(u);
+ if (!c)
+ return 0;
- r = hashmap_put(u->manager->cgroup_unit, path, u);
- if (r < 0) {
- log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
- return r;
- }
- if (r > 0) {
- u->cgroup_path = path;
- path = NULL;
+ if (!u->cgroup_path) {
+ _cleanup_free_ char *path = NULL;
+
+ path = unit_default_cgroup_path(u);
+ if (!path)
+ return log_oom();
+
+ r = hashmap_put(u->manager->cgroup_unit, path, u);
+ if (r < 0) {
+ log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
+ return r;
+ }
+ if (r > 0) {
+ u->cgroup_path = path;
+ path = NULL;
+ }
}
/* First, create our own group */
r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path);
- if (r < 0) {
- log_error("Failed to create cgroup %s: %s", u->cgroup_path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create cgroup %s: %m", u->cgroup_path);
/* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = mask;
- /* Then, possibly move things over */
- r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
+ if (u->type != UNIT_SLICE && !c->delegate) {
+
+ /* Then, possibly move things over, but not if
+ * subgroups may contain processes, which is the case
+ * for slice and delegation units. */
+ r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
+ if (r < 0)
+ log_warning_errno(r, "Failed to migrate cgroup from to %s: %m", u->cgroup_path);
+ }
+
+ return 0;
+}
+
+int unit_attach_pids_to_cgroup(Unit *u) {
+ int r;
+ assert(u);
+
+ r = unit_realize_cgroup(u);
if (r < 0)
- log_warning("Failed to migrate cgroup from to %s: %s", u->cgroup_path, strerror(-r));
+ return r;
+
+ r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->pids, migrate_callback, u);
+ if (r < 0)
+ return r;
return 0;
}
@@ -699,7 +737,7 @@ unsigned manager_dispatch_cgroup_queue(Manager *m) {
r = unit_realize_cgroup_now(i, state);
if (r < 0)
- log_warning("Failed to realize cgroups for queued unit %s: %s", i->id, strerror(-r));
+ log_warning_errno(r, "Failed to realize cgroups for queued unit %s: %m", i->id);
n++;
}
@@ -772,7 +810,7 @@ int unit_realize_cgroup(Unit *u) {
return unit_realize_cgroup_now(u, manager_state(u->manager));
}
-void unit_destroy_cgroup(Unit *u) {
+void unit_destroy_cgroup_if_empty(Unit *u) {
int r;
assert(u);
@@ -781,8 +819,10 @@ void unit_destroy_cgroup(Unit *u) {
return;
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
- if (r < 0)
- log_debug("Failed to destroy cgroup %s: %s", u->cgroup_path, strerror(-r));
+ if (r < 0) {
+ log_debug_errno(r, "Failed to destroy cgroup %s: %m", u->cgroup_path);
+ return;
+ }
hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
@@ -790,7 +830,6 @@ void unit_destroy_cgroup(Unit *u) {
u->cgroup_path = NULL;
u->cgroup_realized = false;
u->cgroup_realized_mask = 0;
-
}
pid_t unit_search_main_pid(Unit *u) {
@@ -841,10 +880,8 @@ int manager_setup_cgroup(Manager *m) {
m->cgroup_root = NULL;
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root);
- if (r < 0) {
- log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
/* LEGACY: Already in /system.slice? If so, let's cut this
* off. This is to support live upgrades from older systemd
@@ -867,10 +904,8 @@ int manager_setup_cgroup(Manager *m) {
/* 2. Show data */
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
- if (r < 0) {
- log_error("Cannot find cgroup mount point: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot find cgroup mount point: %m");
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
if (!m->test_run) {
@@ -879,7 +914,7 @@ int manager_setup_cgroup(Manager *m) {
if (m->running_as == SYSTEMD_SYSTEM) {
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
if (r < 0)
- log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
+ log_warning_errno(r, "Failed to install release agent, ignoring: %m");
else if (r > 0)
log_debug("Installed release agent.");
else
@@ -888,19 +923,15 @@ int manager_setup_cgroup(Manager *m) {
/* 4. Make sure we are in the root cgroup */
r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
- if (r < 0) {
- log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create root cgroup hierarchy: %m");
/* 5. And pin it, so that it cannot be unmounted */
safe_close(m->pin_cgroupfs_fd);
m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
- if (m->pin_cgroupfs_fd < 0) {
- log_error("Failed to open pin file: %m");
- return -errno;
- }
+ if (m->pin_cgroupfs_fd < 0)
+ return log_error_errno(errno, "Failed to open pin file: %m");
/* 6. Always enable hierarchial support if it exists... */
cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index d299872b1f..7150e5e7e2 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -83,6 +83,8 @@ struct CGroupContext {
CGroupDevicePolicy device_policy;
LIST_HEAD(CGroupDeviceAllow, device_allow);
+
+ bool delegate;
};
#include "unit.h"
@@ -107,7 +109,8 @@ CGroupControllerMask unit_get_target_mask(Unit *u);
void unit_update_cgroup_members_masks(Unit *u);
int unit_realize_cgroup(Unit *u);
-void unit_destroy_cgroup(Unit *u);
+void unit_destroy_cgroup_if_empty(Unit *u);
+int unit_attach_pids_to_cgroup(Unit *u);
int manager_setup_cgroup(Manager *m);
void manager_shutdown_cgroup(Manager *m, bool delete);
diff --git a/src/core/condition.c b/src/core/condition.c
deleted file mode 100644
index ec78169fc3..0000000000
--- a/src/core/condition.c
+++ /dev/null
@@ -1,264 +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 <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/capability.h>
-#include <sys/statvfs.h>
-#include <fnmatch.h>
-
-#include "sd-id128.h"
-#include "util.h"
-#include "condition.h"
-#include "virt.h"
-#include "path-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "smack-util.h"
-#include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
-
-static bool condition_test_security(Condition *c) {
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_SECURITY);
-
- if (streq(c->parameter, "selinux"))
- return mac_selinux_use() == !c->negate;
- if (streq(c->parameter, "smack"))
- return mac_smack_use() == !c->negate;
- if (streq(c->parameter, "apparmor"))
- return mac_apparmor_use() == !c->negate;
- if (streq(c->parameter, "ima"))
- return use_ima() == !c->negate;
-
- return c->negate;
-}
-
-static bool condition_test_capability(Condition *c) {
- _cleanup_fclose_ FILE *f = NULL;
- cap_value_t value;
- char line[LINE_MAX];
- unsigned long long capabilities = -1;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_CAPABILITY);
-
- /* If it's an invalid capability, we don't have it */
-
- if (cap_from_name(c->parameter, &value) < 0)
- return c->negate;
-
- /* If it's a valid capability we default to assume
- * that we have it */
-
- f = fopen("/proc/self/status", "re");
- if (!f)
- return !c->negate;
-
- while (fgets(line, sizeof(line), f)) {
- truncate_nl(line);
-
- if (startswith(line, "CapBnd:")) {
- (void) sscanf(line+7, "%llx", &capabilities);
- break;
- }
- }
-
- return !!(capabilities & (1ULL << value)) == !c->negate;
-}
-
-static bool condition_test_needs_update(Condition *c) {
- const char *p;
- struct stat usr, other;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_NEEDS_UPDATE);
-
- /* If the file system is read-only we shouldn't suggest an update */
- if (path_is_read_only_fs(c->parameter) > 0)
- return c->negate;
-
- /* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools then too
- * few. */
-
- if (!path_is_absolute(c->parameter))
- return !c->negate;
-
- p = strappenda(c->parameter, "/.updated");
- if (lstat(p, &other) < 0)
- return !c->negate;
-
- if (lstat("/usr/", &usr) < 0)
- return !c->negate;
-
- return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
- (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
-}
-
-static bool condition_test_first_boot(Condition *c) {
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_FIRST_BOOT);
-
- r = parse_boolean(c->parameter);
- if (r < 0)
- return c->negate;
-
- return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
-}
-
-static bool condition_test(Condition *c) {
- assert(c);
-
- switch(c->type) {
-
- case CONDITION_PATH_EXISTS:
- return (access(c->parameter, F_OK) >= 0) == !c->negate;
-
- case CONDITION_PATH_EXISTS_GLOB:
- return (glob_exists(c->parameter) > 0) == !c->negate;
-
- case CONDITION_PATH_IS_DIRECTORY: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
- return S_ISDIR(st.st_mode) == !c->negate;
- }
-
- case CONDITION_PATH_IS_SYMBOLIC_LINK: {
- struct stat st;
-
- if (lstat(c->parameter, &st) < 0)
- return c->negate;
- return S_ISLNK(st.st_mode) == !c->negate;
- }
-
- case CONDITION_PATH_IS_MOUNT_POINT:
- return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
-
- case CONDITION_PATH_IS_READ_WRITE:
- return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
-
- case CONDITION_DIRECTORY_NOT_EMPTY: {
- int k;
-
- k = dir_is_empty(c->parameter);
- return !(k == -ENOENT || k > 0) == !c->negate;
- }
-
- case CONDITION_FILE_NOT_EMPTY: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
-
- return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
- }
-
- case CONDITION_FILE_IS_EXECUTABLE: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
-
- return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
- }
-
- case CONDITION_KERNEL_COMMAND_LINE:
- return condition_test_kernel_command_line(c);
-
- case CONDITION_VIRTUALIZATION:
- return condition_test_virtualization(c);
-
- case CONDITION_SECURITY:
- return condition_test_security(c);
-
- case CONDITION_CAPABILITY:
- return condition_test_capability(c);
-
- case CONDITION_HOST:
- return condition_test_host(c);
-
- case CONDITION_AC_POWER:
- return condition_test_ac_power(c);
-
- case CONDITION_ARCHITECTURE:
- return condition_test_architecture(c);
-
- case CONDITION_NEEDS_UPDATE:
- return condition_test_needs_update(c);
-
- case CONDITION_FIRST_BOOT:
- return condition_test_first_boot(c);
-
- case CONDITION_NULL:
- return !c->negate;
-
- default:
- assert_not_reached("Invalid condition type.");
- }
-}
-
-bool condition_test_list(const char *unit, Condition *first) {
- Condition *c;
- int triggered = -1;
-
- /* If the condition list is empty, then it is true */
- if (!first)
- return true;
-
- /* Otherwise, if all of the non-trigger conditions apply and
- * if any of the trigger conditions apply (unless there are
- * none) we return true */
- LIST_FOREACH(conditions, c, first) {
- bool b;
-
- b = condition_test(c);
- if (unit)
- log_debug_unit(unit,
- "%s=%s%s%s %s for %s.",
- condition_type_to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- b ? "succeeded" : "failed",
- unit);
- c->state = b ? 1 : -1;
-
- if (!c->trigger && !b)
- return false;
-
- if (c->trigger && triggered <= 0)
- triggered = b;
- }
-
- return triggered != 0;
-}
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 900566c29b..db998345eb 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -153,6 +153,7 @@ static int property_get_ulong_as_u64(
const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0),
SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0),
@@ -170,6 +171,39 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_VTABLE_END
};
+static int bus_cgroup_set_transient_property(
+ Unit *u,
+ CGroupContext *c,
+ const char *name,
+ sd_bus_message *message,
+ UnitSetPropertiesMode mode,
+ sd_bus_error *error) {
+
+ int r;
+
+ assert(u);
+ assert(c);
+ assert(name);
+ assert(message);
+
+ if (streq(name, "Delegate")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->delegate = b;
+ unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
int bus_cgroup_set_property(
Unit *u,
CGroupContext *c,
@@ -632,6 +666,14 @@ int bus_cgroup_set_property(
}
return 1;
+
+ }
+
+ if (u->transient && u->load_state == UNIT_STUB) {
+ r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
+ if (r != 0)
+ return r;
+
}
return 0;
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 9276da4cdc..bbcd6106ad 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -508,6 +508,24 @@ static int property_get_apparmor_profile(
return sd_bus_message_append(reply, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
}
+static int property_get_smack_process_label(
+ 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, "(bs)", c->smack_process_label_ignore, c->smack_process_label);
+}
+
static int property_get_personality(
sd_bus *bus,
const char *path,
@@ -636,6 +654,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("UtmpIdentifier", "s", NULL, offsetof(ExecContext, utmp_id), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NoNewPrivileges", "b", bus_property_get_bool, offsetof(ExecContext, no_new_privileges), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SystemCallFilter", "(bas)", property_get_syscall_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 09f5739315..8b5ea2566d 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -154,7 +154,7 @@ void bus_job_send_change_signal(Job *j) {
r = bus_foreach_bus(j->manager, j->clients, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
if (r < 0)
- log_debug("Failed to send job change signal for %u: %s", j->id, strerror(-r));
+ log_debug_errno(r, "Failed to send job change signal for %u: %m", j->id);
j->sent_dbus_new_signal = true;
}
@@ -198,5 +198,5 @@ void bus_job_send_removed_signal(Job *j) {
r = bus_foreach_bus(j->manager, j->clients, send_removed_signal, j);
if (r < 0)
- log_debug("Failed to send job remove signal for %u: %s", j->id, strerror(-r));
+ log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id);
}
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index c54abd3b4e..6181ba8248 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -39,7 +39,7 @@
#include "dbus-unit.h"
#include "dbus-snapshot.h"
#include "dbus-execute.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
static int property_get_version(
sd_bus *bus,
@@ -615,6 +615,92 @@ static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void
return bus_unit_method_set_properties(bus, message, u, error);
}
+static int transient_unit_from_message(
+ Manager *m,
+ sd_bus_message *message,
+ const char *name,
+ Unit **unit,
+ sd_bus_error *error) {
+
+ Unit *u;
+ int r;
+
+ assert(m);
+ assert(message);
+ assert(name);
+
+ r = manager_load_unit(m, name, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ if (u->load_state != UNIT_NOT_FOUND ||
+ set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
+
+ /* OK, the unit failed to load and is unreferenced, now let's
+ * fill in the transient data instead */
+ r = unit_make_transient(u);
+ if (r < 0)
+ return r;
+
+ /* Set our properties */
+ r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, error);
+ if (r < 0)
+ return r;
+
+ *unit = u;
+
+ return 0;
+}
+
+static int transient_aux_units_from_message(
+ Manager *m,
+ sd_bus_message *message,
+ sd_bus_error *error) {
+
+ Unit *u;
+ char *name = NULL;
+ int r;
+
+ assert(m);
+ assert(message);
+
+ r = sd_bus_message_enter_container(message, 'a', "(sa(sv))");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
+ if (r <= 0)
+ return r;
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ r = transient_unit_from_message(m, message, name, &u, error);
+ if (r < 0 && r != -EEXIST)
+ return r;
+
+ if (r != -EEXIST) {
+ r = unit_load(u);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *name, *smode;
Manager *m = userdata;
@@ -652,21 +738,11 @@ static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, voi
if (r < 0)
return r;
- r = manager_load_unit(m, name, NULL, error, &u);
+ r = transient_unit_from_message(m, message, name, &u, error);
if (r < 0)
return r;
- if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
-
- /* OK, the unit failed to load and is unreferenced, now let's
- * fill in the transient data instead */
- r = unit_make_transient(u);
- if (r < 0)
- return r;
-
- /* Set our properties */
- r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, error);
+ r = transient_aux_units_from_message(m, message, error);
if (r < 0)
return r;
@@ -1514,7 +1590,7 @@ static int reply_unit_file_changes_and_free(
if (n_changes > 0) {
r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
if (r < 0)
- log_debug("Failed to send UnitFilesChanged signal: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
}
r = sd_bus_message_new_method_return(message, &reply);
@@ -1884,8 +1960,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
+ SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
@@ -1998,7 +2074,7 @@ void bus_manager_send_finished(
total_usec
});
if (r < 0)
- log_debug("Failed to send finished signal: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send finished signal: %m");
}
static int send_reloading(sd_bus *bus, void *userdata) {
@@ -2025,6 +2101,6 @@ void bus_manager_send_reloading(Manager *m, bool active) {
r = bus_foreach_bus(m, NULL, send_reloading, INT_TO_PTR(active));
if (r < 0)
- log_debug("Failed to send reloading signal: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send reloading signal: %m");
}
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index a762223c81..60215a1935 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -28,7 +28,7 @@
#include "dbus.h"
#include "bus-util.h"
#include "bus-internal.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
Scope *s = userdata;
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index f1f8c54383..43e785246c 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -24,6 +24,8 @@
#include "dbus-unit.h"
#include "dbus-timer.h"
#include "bus-util.h"
+#include "errno-list.h"
+#include "strv.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
@@ -183,3 +185,144 @@ const sd_bus_vtable bus_timer_vtable[] = {
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
+
+static int bus_timer_set_transient_property(
+ Timer *t,
+ const char *name,
+ sd_bus_message *message,
+ UnitSetPropertiesMode mode,
+ sd_bus_error *error) {
+
+ int r;
+
+ assert(t);
+ assert(name);
+ assert(message);
+
+ if (STR_IN_SET(name,
+ "OnActiveSec",
+ "OnBootSec",
+ "OnStartupSec",
+ "OnUnitActiveSec",
+ "OnUnitInactiveSec")) {
+
+ TimerValue *v;
+ TimerBase b = _TIMER_BASE_INVALID;
+ usec_t u = 0;
+
+ b = timer_base_from_string(name);
+ if (b < 0)
+ return -EINVAL;
+
+ r = sd_bus_message_read(message, "t", &u);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ char time[FORMAT_TIMESPAN_MAX];
+
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+
+ v = new0(TimerValue, 1);
+ if (!v)
+ return -ENOMEM;
+
+ v->base = b;
+ v->value = u;
+
+ LIST_PREPEND(value, t->values, v);
+ }
+
+ return 1;
+
+ } else if (streq(name, "OnCalendar")) {
+
+ TimerValue *v;
+ CalendarSpec *c = NULL;
+ const char *str;
+
+ r = sd_bus_message_read(message, "s", &str);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ r = calendar_spec_from_string(str, &c);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
+
+ v = new0(TimerValue, 1);
+ if (!v) {
+ if (c)
+ calendar_spec_free(c);
+ return -ENOMEM;
+ }
+
+ v->base = TIMER_CALENDAR;
+ v->calendar_spec = c;
+
+ LIST_PREPEND(value, t->values, v);
+ }
+
+ return 1;
+
+ } else if (streq(name, "AccuracySec")) {
+
+ usec_t u = 0;
+
+ r = sd_bus_message_read(message, "t", &u);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ char time[FORMAT_TIMESPAN_MAX];
+
+ t->accuracy_usec = u;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ }
+
+ return 1;
+
+ } else if (streq(name, "WakeSystem")) {
+
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ t->wake_system = b;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
+ }
+
+ return 1;
+
+ }
+
+ return 0;
+}
+
+int bus_timer_set_property(
+ Unit *u,
+ const char *name,
+ sd_bus_message *message,
+ UnitSetPropertiesMode mode,
+ sd_bus_error *error) {
+
+ Timer *t = TIMER(u);
+ int r;
+
+ assert(t);
+ assert(name);
+ assert(message);
+
+ if (u->transient && u->load_state == UNIT_STUB) {
+ r = bus_timer_set_transient_property(t, name, message, mode, error);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
index cfff88e8b7..103172f055 100644
--- a/src/core/dbus-timer.h
+++ b/src/core/dbus-timer.h
@@ -22,5 +22,8 @@
***/
#include "sd-bus.h"
+#include "unit.h"
extern const sd_bus_vtable bus_timer_vtable[];
+
+int bus_timer_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 9b13c6ed1b..b968009938 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -26,7 +26,7 @@
#include "strv.h"
#include "path-util.h"
#include "fileio.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "dbus.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
@@ -169,6 +169,29 @@ static int property_get_sub_state(
return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u));
}
+static int property_get_unit_file_preset(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Unit *u = userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ r = unit_get_unit_file_preset(u);
+
+ return sd_bus_message_append(reply, "s",
+ r < 0 ? "":
+ r > 0 ? "enabled" : "disabled");
+}
+
static int property_get_unit_file_state(
sd_bus *bus,
const char *path,
@@ -315,23 +338,31 @@ static int property_get_conditions(
void *userdata,
sd_bus_error *error) {
- Unit *u = userdata;
- Condition *c;
+ const char *(*to_string)(ConditionType type) = NULL;
+ Condition **list = userdata, *c;
int r;
assert(bus);
assert(reply);
- assert(u);
+ assert(list);
+
+ to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
if (r < 0)
return r;
- LIST_FOREACH(conditions, c, u->conditions) {
+ LIST_FOREACH(conditions, c, *list) {
+ int tristate;
+
+ tristate =
+ c->result == CONDITION_UNTESTED ? 0 :
+ c->result == CONDITION_SUCCEEDED ? 1 : -1;
+
r = sd_bus_message_append(reply, "(sbbsi)",
- condition_type_to_string(c->type),
+ to_string(c->type),
c->trigger, c->negate,
- c->parameter, c->state);
+ c->parameter, tristate);
if (r < 0)
return r;
@@ -544,6 +575,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
+ SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -566,8 +598,11 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, 0, 0),
+ BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
+ 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),
@@ -682,7 +717,7 @@ void bus_unit_send_change_signal(Unit *u) {
r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
if (r < 0)
- log_debug("Failed to send unit change signal for %s: %s", u->id, strerror(-r));
+ log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
u->sent_dbus_new_signal = true;
}
@@ -728,7 +763,7 @@ void bus_unit_send_removed_signal(Unit *u) {
r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
if (r < 0)
- log_debug("Failed to send unit remove signal for %s: %s", u->id, strerror(-r));
+ log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
}
int bus_unit_queue_job(
@@ -859,20 +894,16 @@ static int bus_unit_set_transient_property(
}
return 1;
-
- } else if (streq(name, "Requires") ||
- streq(name, "RequiresOverridable") ||
- streq(name, "Requisite") ||
- streq(name, "RequisiteOverridable") ||
- streq(name, "Wants") ||
- streq(name, "BindsTo") ||
- streq(name, "Conflicts") ||
- streq(name, "Before") ||
- streq(name, "After") ||
- streq(name, "OnFailure") ||
- streq(name, "PropagatesReloadTo") ||
- streq(name, "ReloadPropagatedFrom") ||
- streq(name, "PartOf")) {
+ } else if (STR_IN_SET(name,
+ "Requires", "RequiresOverridable",
+ "Requisite", "RequisiteOverridable",
+ "Wants",
+ "BindsTo",
+ "Conflicts",
+ "Before", "After",
+ "OnFailure",
+ "PropagatesReloadTo", "ReloadPropagatedFrom",
+ "PartOf")) {
UnitDependency d;
const char *other;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 185057b624..260775cd85 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -39,7 +39,7 @@
#include "dbus.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "strxcpyx.h"
#include "bus-internal.h"
#include "selinux-access.h"
@@ -64,7 +64,7 @@ int bus_send_queued_message(Manager *m) {
r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
if (r < 0)
- log_warning("Failed to send queued message: %s", strerror(-r));
+ log_warning_errno(r, "Failed to send queued message: %m");
m->queued_message = sd_bus_message_unref(m->queued_message);
m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
@@ -95,7 +95,7 @@ static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *use
r = sd_bus_send(m->system_bus, message, NULL);
if (r < 0)
- log_warning("Failed to forward Released message: %s", strerror(-r));
+ log_warning_errno(r, "Failed to forward Released message: %m");
}
return 0;
@@ -202,10 +202,8 @@ failed:
}
r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
- if (r < 0) {
- log_error("Failed to respond with to bus activation request: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to respond with to bus activation request: %m");
return 0;
}
@@ -537,77 +535,55 @@ static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
#ifdef HAVE_SELINUX
r = sd_bus_add_filter(bus, NULL, mac_selinux_filter, m);
- if (r < 0) {
- log_error("Failed to add SELinux access filter: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add SELinux access filter: %m");
#endif
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
- if (r < 0) {
- log_error("Failed to register Manager vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register Manager vtable: %m");
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
- if (r < 0) {
- log_error("Failed to register Job vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register Job vtable: %m");
r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
- if (r < 0) {
- log_error("Failed to add job enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add job enumerator: %m");
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
- if (r < 0) {
- log_error("Failed to register Unit vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register Unit vtable: %m");
r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
- if (r < 0) {
- log_error("Failed to add job enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add job enumerator: %m");
for (t = 0; t < _UNIT_TYPE_MAX; t++) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
- if (r < 0) {
- log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register type specific vtable for %s: %m", unit_vtable[t]->bus_interface);
if (unit_vtable[t]->cgroup_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
- if (r < 0) {
- log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", unit_vtable[t]->bus_interface);
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
- if (r < 0) {
- log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register control group vtable for %s: %m", unit_vtable[t]->bus_interface);
}
if (unit_vtable[t]->exec_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
- if (r < 0) {
- log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register execute vtable for %s: %m", unit_vtable[t]->bus_interface);
}
if (unit_vtable[t]->kill_context_offset > 0) {
r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
- if (r < 0) {
- log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register kill vtable for %s: %m", unit_vtable[t]->bus_interface);
}
}
@@ -630,10 +606,8 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
"member='Disconnected'",
signal_disconnected, m);
- if (r < 0) {
- log_error("Failed to register match for Disconnected message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register match for Disconnected message: %m");
return 0;
}
@@ -650,7 +624,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (nfd < 0) {
- log_warning("Failed to accept private connection, ignoring: %m");
+ log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
return 0;
}
@@ -667,13 +641,13 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = sd_bus_new(&bus);
if (r < 0) {
- log_warning("Failed to allocate new private connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to allocate new private connection bus: %m");
return 0;
}
r = sd_bus_set_fd(bus, nfd, nfd);
if (r < 0) {
- log_warning("Failed to set fd on new connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to set fd on new connection bus: %m");
return 0;
}
@@ -681,7 +655,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = bus_check_peercred(bus);
if (r < 0) {
- log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r));
+ log_warning_errno(r, "Incoming private connection from unprivileged client, refusing: %m");
return 0;
}
@@ -689,19 +663,19 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = sd_bus_set_server(bus, 1, id);
if (r < 0) {
- log_warning("Failed to enable server support for new connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to enable server support for new connection bus: %m");
return 0;
}
r = sd_bus_start(bus);
if (r < 0) {
- log_warning("Failed to start new connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to start new connection bus: %m");
return 0;
}
r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) {
- log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r));
+ log_warning_errno(r, "Failed to attach new connection bus to event loop: %m");
return 0;
}
@@ -719,7 +693,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
signal_agent_released, m);
if (r < 0) {
- log_warning("Failed to register Released match on new connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
return 0;
}
}
@@ -730,13 +704,13 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = bus_setup_api_vtables(m, bus);
if (r < 0) {
- log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to set up API vtables on new connection bus: %m");
return 0;
}
r = set_put(m->private_buses, bus);
if (r < 0) {
- log_warning("Failed to add new conenction bus to set: %s", strerror(-r));
+ log_warning_errno(r, "Failed to add new conenction bus to set: %m");
return 0;
}
@@ -756,10 +730,8 @@ static int bus_list_names(Manager *m, sd_bus *bus) {
assert(bus);
r = sd_bus_list_names(bus, &names, NULL);
- if (r < 0) {
- log_error("Failed to get initial list of names: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get initial list of names: %m");
/* This is a bit hacky, we say the owner of the name is the
* name itself, because we don't want the extra traffic to
@@ -776,6 +748,14 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
+ /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
+ r = sd_bus_negotiate_creds(bus, 1,
+ SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
+ SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable credential passing, ignoring: %m");
+
r = bus_setup_api_vtables(m, bus);
if (r < 0)
return r;
@@ -790,7 +770,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
"member='NameOwnerChanged'",
signal_name_owner_changed, m);
if (r < 0)
- log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
r = sd_bus_add_match(
bus,
@@ -802,7 +782,7 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
"member='ActivationRequest'",
signal_activation_request, m);
if (r < 0)
- log_warning("Failed to subscribe to activation signal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to subscribe to activation signal: %m");
/* Allow replacing of our name, to ease implementation of
* reexecution, where we keep the old connection open until
@@ -810,10 +790,8 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
* to allow clients to synchronously wait for reexecution to
* finish */
r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
bus_list_names(m, bus);
@@ -844,7 +822,7 @@ static int bus_init_api(Manager *m) {
r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) {
- log_error("Failed to attach API bus to event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to attach API bus to event loop: %m");
return 0;
}
@@ -855,7 +833,7 @@ static int bus_init_api(Manager *m) {
r = bus_setup_api(m, bus);
if (r < 0) {
- log_error("Failed to set up API bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to set up API bus: %m");
return 0;
}
@@ -886,7 +864,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
signal_agent_released, m);
if (r < 0)
- log_warning("Failed to register Released match on system bus: %s", strerror(-r));
+ log_warning_errno(r, "Failed to register Released match on system bus: %m");
log_debug("Successfully connected to system bus.");
return 0;
@@ -917,13 +895,13 @@ static int bus_init_system(Manager *m) {
r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) {
- log_error("Failed to attach system bus to event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to attach system bus to event loop: %m");
return 0;
}
r = bus_setup_system(m, bus);
if (r < 0) {
- log_error("Failed to set up system bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to set up system bus: %m");
return 0;
}
@@ -974,35 +952,26 @@ static int bus_init_private(Manager *m) {
left = strpcpy(&p, left, "/systemd/private");
salen = sizeof(sa.un) - left;
-
- mkdir_parents_label(sa.un.sun_path, 0755);
}
- unlink(sa.un.sun_path);
+ (void) mkdir_parents_label(sa.un.sun_path, 0755);
+ (void) unlink(sa.un.sun_path);
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0) {
- log_error("Failed to allocate private socket: %m");
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate private socket: %m");
r = bind(fd, &sa.sa, salen);
- if (r < 0) {
- log_error("Failed to bind private socket: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to bind private socket: %m");
r = listen(fd, SOMAXCONN);
- if (r < 0) {
- log_error("Failed to make private socket listening: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to make private socket listening: %m");
r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
- if (r < 0) {
- log_error("Failed to allocate event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event source: %m");
m->private_listen_fd = fd;
m->private_listen_event_source = s;
@@ -1175,6 +1144,7 @@ void bus_track_serialize(sd_bus_track *t, FILE *f) {
int bus_track_deserialize_item(char ***l, const char *line) {
const char *e;
+ int r;
assert(l);
assert(line);
@@ -1183,7 +1153,11 @@ int bus_track_deserialize_item(char ***l, const char *line) {
if (!e)
return 0;
- return strv_extend(l, e);
+ r = strv_extend(l, e);
+ if (r < 0)
+ return r;
+
+ return 1;
}
int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
diff --git a/src/core/device.c b/src/core/device.c
index 11c4261081..b254e45b33 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -98,7 +98,7 @@ static void device_set_state(Device *d, DeviceState state) {
d->state = state;
if (state != old_state)
- log_debug_unit(UNIT(d)->id,
+ log_unit_debug(UNIT(d)->id,
"%s changed %s -> %s", UNIT(d)->id,
device_state_to_string(old_state),
device_state_to_string(state));
@@ -249,7 +249,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
return r;
}
if (!isempty(state))
- log_warning_unit(u->id, "Property %s on %s has trailing garbage, ignoring.",
+ log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.",
property, strna(udev_device_get_syspath(dev)));
return 0;
@@ -334,7 +334,7 @@ static int device_update_unit(Manager *m, struct udev_device *dev, const char *p
return 0;
fail:
- log_warning("Failed to load device unit: %s", strerror(-r));
+ log_warning_errno(r, "Failed to load device unit: %m");
if (delete && u)
unit_free(u);
@@ -628,7 +628,7 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
if (!ratelimit_test(&limit))
- log_error("Failed to get udev event: %m");
+ log_error_errno(errno, "Failed to get udev event: %m");
if (!(revents & EPOLLIN))
return 0;
}
@@ -650,20 +650,20 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (streq(action, "remove") || !device_is_ready(dev)) {
r = device_process_removed_device(m, dev);
if (r < 0)
- log_error("Failed to process device remove event: %s", strerror(-r));
+ log_error_errno(r, "Failed to process device remove event: %m");
r = swap_process_removed_device(m, dev);
if (r < 0)
- log_error("Failed to process swap device remove event: %s", strerror(-r));
+ log_error_errno(r, "Failed to process swap device remove event: %m");
} else {
r = device_process_new_device(m, dev);
if (r < 0)
- log_error("Failed to process device new event: %s", strerror(-r));
+ log_error_errno(r, "Failed to process device new event: %m");
r = swap_process_new_device(m, dev);
if (r < 0)
- log_error("Failed to process swap device new event: %s", strerror(-r));
+ log_error_errno(r, "Failed to process swap device new event: %m");
manager_dispatch_load_queue(m);
diff --git a/src/core/execute.c b/src/core/execute.c
index c41aec222d..5e4135e030 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -83,8 +83,10 @@
#include "af-list.h"
#include "mkdir.h"
#include "apparmor-util.h"
+#include "smack-util.h"
#include "bus-kernel.h"
#include "label.h"
+#include "cap-list.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
@@ -425,12 +427,13 @@ static int setup_output(const ExecContext *context, int fileno, int socket_fd, c
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
r = connect_logger_as(context, o, ident, unit_id, fileno);
if (r < 0) {
- log_struct_unit(LOG_CRIT, unit_id,
- "MESSAGE=Failed to connect std%s of %s to the journal socket: %s",
- fileno == STDOUT_FILENO ? "out" : "err",
- unit_id, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_unit_struct(unit_id,
+ LOG_CRIT,
+ LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
+ fileno == STDOUT_FILENO ? "stdout" : "stderr",
+ unit_id, strerror(-r)),
+ LOG_ERRNO(-r),
+ NULL);
r = open_null_as(O_WRONLY, fileno);
}
return r;
@@ -821,7 +824,7 @@ static int setup_pam(
* If this fails, ignore the error - but expect sd-pam threads
* to fail to exit normally */
if (setresuid(uid, uid, uid) < 0)
- log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
+ log_error_errno(r, "Error: Failed to setresuid() in sd-pam: %m");
/* Wait until our parent died. This will only work if
* the above setresuid() succeeds, otherwise the kernel
@@ -883,7 +886,7 @@ fail:
log_error("PAM failed: %s", pam_strerror(handle, pam_code));
err = -EPERM; /* PAM errors do not map to errno */
} else {
- log_error("PAM failed: %m");
+ log_error_errno(errno, "PAM failed: %m");
err = -errno;
}
@@ -1236,11 +1239,12 @@ static int exec_child(ExecCommand *command,
int *error) {
_cleanup_strv_free_ char **our_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;
unsigned n_dont_close = 0;
int dont_close[n_fds + 4];
- uid_t uid = (uid_t) -1;
- gid_t gid = (gid_t) -1;
+ uid_t uid = UID_INVALID;
+ gid_t gid = GID_INVALID;
int i, err;
assert(command);
@@ -1347,7 +1351,7 @@ static int exec_child(ExecCommand *command,
}
if (params->cgroup_path) {
- err = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0);
+ err = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
if (err < 0) {
*error = EXIT_CGROUP;
return err;
@@ -1434,7 +1438,7 @@ static int exec_child(ExecCommand *command,
#ifdef ENABLE_KDBUS
if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
- uid_t ep_uid = (uid == (uid_t) -1) ? 0 : uid;
+ uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid;
err = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint);
if (err < 0) {
@@ -1444,8 +1448,10 @@ static int exec_child(ExecCommand *command,
}
#endif
-#ifdef HAVE_PAM
- if (params->cgroup_path && context->user && context->pam_name) {
+ /* If delegation is enabled we'll pass ownership of the cgroup
+ * (but only in systemd's own controller hierarchy!) to the
+ * user of the new process. */
+ if (params->cgroup_path && context->user && params->cgroup_delegate) {
err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
if (err < 0) {
*error = EXIT_CGROUP;
@@ -1459,7 +1465,6 @@ static int exec_child(ExecCommand *command,
return err;
}
}
-#endif
if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
char **rt;
@@ -1547,7 +1552,7 @@ static int exec_child(ExecCommand *command,
context->mount_flags);
if (err == -EPERM)
- log_warning_unit(params->unit_id, "Failed to set up file system namespace due to lack of privileges. Execution sandbox will not be in effect: %s", strerror(-err));
+ log_unit_warning_errno(params->unit_id, err, "Failed to set up file system namespace due to lack of privileges. Execution sandbox will not be in effect: %m");
else if (err < 0) {
*error = EXIT_NAMESPACE;
return err;
@@ -1581,6 +1586,16 @@ static int exec_child(ExecCommand *command,
}
}
+#ifdef HAVE_SELINUX
+ if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
+ err = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
+ if (err < 0) {
+ *error = EXIT_SELINUX_CONTEXT;
+ return err;
+ }
+ }
+#endif
+
/* We repeat the fd closing here, to make sure that
* nothing is leaked from the PAM modules. Note that
* we are more aggressive this time since socket_fd
@@ -1617,6 +1632,16 @@ static int exec_child(ExecCommand *command,
}
}
+#ifdef HAVE_SMACK
+ if (context->smack_process_label) {
+ err = mac_smack_apply_pid(0, context->smack_process_label);
+ if (err < 0) {
+ *error = EXIT_SMACK_PROCESS_LABEL;
+ return err;
+ }
+ }
+#endif
+
if (context->user) {
err = enforce_user(context, uid);
if (err < 0) {
@@ -1670,24 +1695,10 @@ static int exec_child(ExecCommand *command,
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
- if (context->selinux_context) {
- err = setexeccon(context->selinux_context);
- if (err < 0 && !context->selinux_context_ignore) {
- *error = EXIT_SELINUX_CONTEXT;
- return err;
- }
- }
-
- if (params->selinux_context_net && socket_fd >= 0) {
- _cleanup_free_ char *label = NULL;
-
- err = mac_selinux_get_child_mls_label(socket_fd, command->path, &label);
- if (err < 0) {
- *error = EXIT_SELINUX_CONTEXT;
- return err;
- }
+ char *exec_context = mac_selinux_context_net ?: context->selinux_context;
- err = setexeccon(label);
+ if (exec_context) {
+ err = setexeccon(exec_context);
if (err < 0) {
*error = EXIT_SELINUX_CONTEXT;
return err;
@@ -1739,10 +1750,10 @@ static int exec_child(ExecCommand *command,
line = exec_command_line(final_argv);
if (line) {
log_open();
- log_struct_unit(LOG_DEBUG,
- params->unit_id,
+ log_unit_struct(params->unit_id,
+ LOG_DEBUG,
"EXECUTABLE=%s", command->path,
- "MESSAGE=Executing: %s", line,
+ LOG_MESSAGE("Executing: %s", line),
NULL);
log_close();
}
@@ -1787,11 +1798,11 @@ int exec_spawn(ExecCommand *command,
err = exec_context_load_environment(context, params->unit_id, &files_env);
if (err < 0) {
- log_struct_unit(LOG_ERR,
- params->unit_id,
- "MESSAGE=Failed to load environment files: %s", strerror(-err),
- "ERRNO=%d", -err,
- NULL);
+ log_unit_struct(params->unit_id,
+ LOG_ERR,
+ LOG_MESSAGE("Failed to load environment files: %s", strerror(-err)),
+ LOG_ERRNO(-err),
+ NULL);
return err;
}
@@ -1801,10 +1812,10 @@ int exec_spawn(ExecCommand *command,
if (!line)
return log_oom();
- log_struct_unit(LOG_DEBUG,
- params->unit_id,
+ log_unit_struct(params->unit_id,
+ LOG_DEBUG,
"EXECUTABLE=%s", command->path,
- "MESSAGE=About to execute: %s", line,
+ LOG_MESSAGE("About to execute: %s", line),
NULL);
free(line);
@@ -1826,12 +1837,13 @@ int exec_spawn(ExecCommand *command,
&r);
if (r != 0) {
log_open();
- log_struct(LOG_ERR, MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
+ log_struct(LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
"EXECUTABLE=%s", command->path,
- "MESSAGE=Failed at step %s spawning %s: %s",
- exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
- command->path, strerror(-err),
- "ERRNO=%d", -err,
+ LOG_MESSAGE("Failed at step %s spawning %s: %s",
+ exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
+ command->path, strerror(-err)),
+ LOG_ERRNO(-err),
NULL);
log_close();
}
@@ -1839,10 +1851,10 @@ int exec_spawn(ExecCommand *command,
_exit(r);
}
- log_struct_unit(LOG_DEBUG,
- params->unit_id,
- "MESSAGE=Forked %s as "PID_FMT,
- command->path, pid,
+ log_unit_struct(params->unit_id,
+ LOG_DEBUG,
+ LOG_MESSAGE("Forked %s as "PID_FMT,
+ command->path, pid),
NULL);
/* We add the new process to the cgroup both in the child (so
@@ -2285,13 +2297,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf(f, "%sCapabilityBoundingSet:", prefix);
for (l = 0; l <= cap_last_cap(); l++)
- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
- _cleanup_cap_free_charp_ char *t;
-
- t = cap_to_name(l);
- if (t)
- fprintf(f, " %s", t);
- }
+ if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
+ fprintf(f, " %s", strna(capability_to_name(l)));
fputs("\n", f);
}
@@ -2402,6 +2409,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
}
+bool exec_context_maintains_privileges(ExecContext *c) {
+ assert(c);
+
+ /* Returns true if the process forked off would run run under
+ * an unchanged UID or as root. */
+
+ if (!c->user)
+ return true;
+
+ if (streq(c->user, "root") || streq(c->user, "0"))
+ return true;
+
+ return false;
+}
+
void exec_status_start(ExecStatus *s, pid_t pid) {
assert(s);
@@ -2744,7 +2766,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
return r;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse netns socket value %s", value);
+ log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
else {
safe_close((*rt)->netns_storage_socket[0]);
(*rt)->netns_storage_socket[0] = fdset_remove(fds, fd);
@@ -2757,7 +2779,7 @@ int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, co
return r;
if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse netns socket value %s", value);
+ log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
else {
safe_close((*rt)->netns_storage_socket[1]);
(*rt)->netns_storage_socket[1] = fdset_remove(fds, fd);
@@ -2790,7 +2812,7 @@ void exec_runtime_destroy(ExecRuntime *rt) {
r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
if (r < 0) {
- log_warning("Failed to nuke %s: %s", rt->tmp_dir, strerror(-r));
+ log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir);
free(rt->tmp_dir);
}
@@ -2802,7 +2824,7 @@ void exec_runtime_destroy(ExecRuntime *rt) {
r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
if (r < 0) {
- log_warning("Failed to nuke %s: %s", rt->var_tmp_dir, strerror(-r));
+ log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir);
free(rt->var_tmp_dir);
}
diff --git a/src/core/execute.h b/src/core/execute.h
index c45dde53a6..5ed750534d 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -142,6 +142,9 @@ struct ExecContext {
bool apparmor_profile_ignore;
char *apparmor_profile;
+ bool smack_process_label_ignore;
+ char *smack_process_label;
+
char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
unsigned long mount_flags;
@@ -207,6 +210,7 @@ struct ExecParameters {
bool selinux_context_net;
CGroupControllerMask cgroup_supported;
const char *cgroup_path;
+ bool cgroup_delegate;
const char *runtime_prefix;
const char *unit_id;
usec_t watchdog_usec;
@@ -244,6 +248,7 @@ int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_r
int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l);
bool exec_context_may_touch_console(ExecContext *c);
+bool exec_context_maintains_privileges(ExecContext *c);
void exec_status_start(ExecStatus *s, pid_t pid);
void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 57baa79275..6664e8952c 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -64,7 +64,7 @@ int hostname_setup(void) {
if (r == -ENOENT)
enoent = true;
else
- log_warning("Failed to read configured hostname: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read configured hostname: %m");
hn = NULL;
} else
@@ -82,10 +82,8 @@ int hostname_setup(void) {
hn = "localhost";
}
- if (sethostname_idempotent(hn) < 0) {
- log_warning("Failed to set hostname to <%s>: %m", hn);
- return -errno;
- }
+ if (sethostname_idempotent(hn) < 0)
+ return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn);
log_info("Set hostname to <%s>.", hn);
return 0;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 7bffd8d9dd..8e4fed17e7 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -24,83 +24,54 @@
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
+#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/mman.h>
+#include <fcntl.h>
#include "ima-setup.h"
-#include "mount-setup.h"
-#include "macro.h"
+#include "copy.h"
#include "util.h"
#include "log.h"
-#include "label.h"
#define IMA_SECFS_DIR "/sys/kernel/security/ima"
#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
#define IMA_POLICY_PATH "/etc/ima/ima-policy"
int ima_setup(void) {
+ int r = 0;
#ifdef HAVE_IMA
- struct stat st;
- ssize_t policy_size = 0, written = 0;
- char *policy;
_cleanup_close_ int policyfd = -1, imafd = -1;
- int result = 0;
-
- if (stat(IMA_POLICY_PATH, &st) < 0)
- return 0;
- policy_size = st.st_size;
- if (stat(IMA_SECFS_DIR, &st) < 0) {
+ if (access(IMA_SECFS_DIR, F_OK) < 0) {
log_debug("IMA support is disabled in the kernel, ignoring.");
return 0;
}
- if (stat(IMA_SECFS_POLICY, &st) < 0) {
- log_error("Another IMA custom policy has already been loaded, "
- "ignoring.");
+ policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
+ if (policyfd < 0) {
+ log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+ "Failed to open the IMA custom policy file "IMA_POLICY_PATH", ignoring: %m");
return 0;
}
- policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
- if (policyfd < 0) {
- log_error("Failed to open the IMA custom policy file %s (%m), "
- "ignoring.", IMA_POLICY_PATH);
+ if (access(IMA_SECFS_POLICY, F_OK) < 0) {
+ log_warning("Another IMA custom policy has already been loaded, ignoring.");
return 0;
}
imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
if (imafd < 0) {
- log_error("Failed to open the IMA kernel interface %s (%m), "
- "ignoring.", IMA_SECFS_POLICY);
- goto out;
- }
-
- policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
- if (policy == MAP_FAILED) {
- log_error("mmap() failed (%m), freezing");
- result = -errno;
- goto out;
+ log_error_errno(errno, "Failed to open the IMA kernel interface "IMA_SECFS_POLICY", ignoring: %m");
+ return 0;
}
- written = loop_write(imafd, policy, (size_t)policy_size, false);
- if (written != policy_size) {
- log_error("Failed to load the IMA custom policy file %s (%m), "
- "ignoring.", IMA_POLICY_PATH);
- goto out_mmap;
- }
+ r = copy_bytes(policyfd, imafd, -1);
+ if (r < 0)
+ log_error_errno(r, "Failed to load the IMA custom policy file "IMA_POLICY_PATH": %m");
+ else
+ log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH".");
- log_info("Successfully loaded the IMA custom policy %s.",
- IMA_POLICY_PATH);
-out_mmap:
- munmap(policy, policy_size);
-out:
- if (result)
- return result;
#endif /* HAVE_IMA */
-
- return 0;
+ return r;
}
diff --git a/src/core/job.c b/src/core/job.c
index eaa4bb17fc..78bc1083de 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -160,15 +160,15 @@ Job* job_install(Job *j) {
uj = *pj;
if (uj) {
- if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
+ if (job_type_is_conflicting(uj->type, j->type))
job_finish_and_invalidate(uj, JOB_CANCELED, false);
else {
/* not conflicting, i.e. mergeable */
- if (j->type == JOB_NOP || uj->state == JOB_WAITING ||
+ if (uj->state == JOB_WAITING ||
(job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
job_merge_into_installed(uj, j);
- log_debug_unit(uj->unit->id,
+ log_unit_debug(uj->unit->id,
"Merged into installed job %s/%s as %u",
uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
return uj;
@@ -178,7 +178,7 @@ Job* job_install(Job *j) {
/* XXX It should be safer to queue j to run after uj finishes, but it is
* not currently possible to have more than one installed job per unit. */
job_merge_into_installed(uj, j);
- log_debug_unit(uj->unit->id,
+ log_unit_debug(uj->unit->id,
"Merged into running job, re-running: %s/%s as %u",
uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
uj->state = JOB_WAITING;
@@ -192,7 +192,7 @@ Job* job_install(Job *j) {
*pj = j;
j->installed = true;
j->manager->n_installed_jobs ++;
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Installed new job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
return j;
@@ -211,14 +211,14 @@ int job_install_deserialized(Job *j) {
pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
if (*pj) {
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Unit %s already has a job installed. Not installing deserialized job.",
j->unit->id);
return -EEXIST;
}
*pj = j;
j->installed = true;
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Reinstalled deserialized job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
return 0;
@@ -352,6 +352,9 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) {
return
b == UNIT_ACTIVATING;
+ case JOB_NOP:
+ return true;
+
default:
assert_not_reached("Invalid job type");
}
@@ -454,7 +457,7 @@ static bool job_is_runnable(Job *j) {
}
static void job_change_type(Job *j, JobType newtype) {
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Converting job %s/%s -> %s/%s",
j->unit->id, job_type_to_string(j->type),
j->unit->id, job_type_to_string(newtype));
@@ -542,6 +545,8 @@ int job_run_and_invalidate(Job *j) {
r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
else if (r == -ENOEXEC)
r = job_finish_and_invalidate(j, JOB_INVALID, true);
+ else if (r == -EPROTO)
+ r = job_finish_and_invalidate(j, JOB_ASSERT, true);
else if (r == -EAGAIN) {
j->state = JOB_WAITING;
m->n_running_jobs--;
@@ -655,6 +660,11 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
break;
+ case JOB_ASSERT:
+ manager_flip_auto_status(u->manager, true);
+ unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format);
+ break;
+
default:
;
}
@@ -720,28 +730,28 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
sd_id128_t mid;
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- u->id,
- MESSAGE_ID(mid),
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
+ log_unit_struct(u->id,
+ result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(mid),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
} else if (t == JOB_STOP)
- log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- u->id,
- MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
+ log_unit_struct(u->id,
+ result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
else if (t == JOB_RELOAD)
- log_struct_unit(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- u->id,
- MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
+ log_unit_struct(u->id,
+ result == JOB_DONE ? LOG_INFO : LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
+ LOG_MESSAGE("%s", buf),
+ "RESULT=%s", job_result_to_string(result),
+ NULL);
}
int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
@@ -762,7 +772,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
if (j->state == JOB_RUNNING)
j->manager->n_running_jobs--;
- log_debug_unit(u->id, "Job %s/%s finished, result=%s",
+ log_unit_debug(u->id, "Job %s/%s finished, result=%s",
u->id, job_type_to_string(t), job_result_to_string(result));
job_print_status_message(u, t, result);
@@ -827,15 +837,15 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
* this context. And JOB_FAILURE is already handled by the
* unit itself. */
if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
- log_struct_unit(LOG_NOTICE,
- u->id,
- "JOB_TYPE=%s", job_type_to_string(t),
- "JOB_RESULT=%s", job_result_to_string(result),
- "Job %s/%s failed with result '%s'.",
- u->id,
- job_type_to_string(t),
- job_result_to_string(result),
- NULL);
+ log_unit_struct(u->id,
+ LOG_NOTICE,
+ "JOB_TYPE=%s", job_type_to_string(t),
+ "JOB_RESULT=%s", job_result_to_string(result),
+ LOG_MESSAGE("Job %s/%s failed with result '%s'.",
+ u->id,
+ job_type_to_string(t),
+ job_result_to_string(result)),
+ NULL);
unit_start_on_failure(u);
}
@@ -863,7 +873,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
assert(j);
assert(s == j->timer_event_source);
- log_warning_unit(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
+ log_unit_warning(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
u = j->unit;
job_finish_and_invalidate(j, JOB_TIMEOUT, true);
@@ -1087,7 +1097,7 @@ int job_coldplug(Job *j) {
j->begin_usec + j->unit->job_timeout, 0,
job_dispatch_timer, j);
if (r < 0)
- log_debug("Failed to restart timeout for job: %s", strerror(-r));
+ log_debug_errno(r, "Failed to restart timeout for job: %m");
return r;
}
@@ -1189,6 +1199,7 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = {
[JOB_DEPENDENCY] = "dependency",
[JOB_SKIPPED] = "skipped",
[JOB_INVALID] = "invalid",
+ [JOB_ASSERT] = "assert",
};
DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
index 1e7c61b04f..223ff9cba7 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -49,9 +49,11 @@ enum JobType {
_JOB_TYPE_MAX_MERGING,
/* JOB_NOP can enter into a transaction, but as it won't pull in
- * any dependencies, it won't have to merge with anything.
- * job_install() avoids the problem of merging JOB_NOP too (it's
- * special-cased, only merges with other JOB_NOPs). */
+ * any dependencies and it uses the special 'nop_job' slot in Unit,
+ * it won't have to merge with anything (except possibly into another
+ * JOB_NOP, previously installed). JOB_NOP is special-cased in
+ * job_type_is_*() functions so that the transaction can be
+ * activated. */
JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */
_JOB_TYPE_MAX_IN_TRANSACTION,
@@ -99,6 +101,7 @@ enum JobResult {
JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */
JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE */
JOB_INVALID, /* JOB_RELOAD of inactive unit */
+ JOB_ASSERT, /* Couldn't start a unit, because an assert didn't hold */
_JOB_RESULT_MAX,
_JOB_RESULT_INVALID = -1
};
@@ -190,11 +193,15 @@ _pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) {
}
_pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) {
- return !job_type_is_mergeable(a, b);
+ return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b);
}
_pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
/* Checks whether operation a is a "superset" of b in its actions */
+ if (b == JOB_NOP)
+ return true;
+ if (a == JOB_NOP)
+ return false;
return a == job_type_lookup_merge(a, b);
}
diff --git a/src/core/killall.c b/src/core/killall.c
index a6ff50a5a4..5a50ae6f04 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -102,7 +102,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
if (errno == ECHILD)
break;
- log_error("waitpid() failed: %m");
+ log_error_errno(errno, "waitpid() failed: %m");
return;
}
@@ -136,7 +136,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
if (k != SIGCHLD) {
if (k < 0 && errno != EAGAIN) {
- log_error("sigtimedwait() failed: %m");
+ log_error_errno(errno, "sigtimedwait() failed: %m");
return;
}
@@ -178,7 +178,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
if (pids)
set_put(pids, ULONG_TO_PTR(pid));
} else if (errno != ENOENT)
- log_warning("Could not kill %d: %m", pid);
+ log_warning_errno(errno, "Could not kill %d: %m", pid);
if (send_sighup) {
/* Optionally, also send a SIGHUP signal, but
@@ -212,12 +212,12 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
- log_warning("kill(-1, SIGSTOP) failed: %m");
+ log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
killall(sig, pids, send_sighup);
if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
- log_warning("kill(-1, SIGCONT) failed: %m");
+ log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
if (wait_for_exit)
wait_for_children(pids, &mask);
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 2f3f608830..c0a05b97aa 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -23,13 +23,17 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
+
+#ifdef HAVE_KMOD
#include <libkmod.h>
+#endif
#include "macro.h"
#include "execute.h"
#include "capability.h"
#include "kmod-setup.h"
+#ifdef HAVE_KMOD
static void systemd_kmod_log(
void *data,
int priority,
@@ -40,20 +44,17 @@ static void systemd_kmod_log(
/* library logging is enabled at debug only */
DISABLE_WARNING_FORMAT_NONLITERAL;
- log_metav(LOG_DEBUG, file, line, fn, format, args);
+ log_internalv(LOG_DEBUG, 0, file, line, fn, format, args);
REENABLE_WARNING;
}
static bool cmdline_check_kdbus(void) {
- _cleanup_free_ char *line = NULL;
-
- if (proc_cmdline(&line) <= 0)
- return false;
-
- return strstr(line, "kdbus") != NULL;
+ return get_proc_cmdline_key("kdbus", NULL) > 0;
}
+#endif
int kmod_setup(void) {
+#ifdef HAVE_KMOD
static const struct {
const char *module;
@@ -62,16 +63,16 @@ int kmod_setup(void) {
bool (*condition_fn)(void);
} kmod_table[] = {
/* auto-loading on use doesn't work before udev is up */
- { "autofs4", "/sys/class/misc/autofs", true, NULL },
+ { "autofs4", "/sys/class/misc/autofs", true, NULL },
/* early configure of ::1 on the loopback device */
- { "ipv6", "/sys/module/ipv6", true, NULL },
+ { "ipv6", "/sys/module/ipv6", true, NULL },
/* this should never be a module */
- { "unix", "/proc/net/unix", true, NULL },
+ { "unix", "/proc/net/unix", true, NULL },
/* IPC is needed before we bring up any other services */
- { "kdbus", "/sys/bus/kdbus", false, cmdline_check_kdbus },
+ { "kdbus", "/sys/fs/kdbus", false, cmdline_check_kdbus },
};
struct kmod_ctx *ctx = NULL;
unsigned int i;
@@ -123,5 +124,6 @@ int kmod_setup(void) {
if (ctx)
kmod_unref(ctx);
+#endif
return 0;
}
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index ffc68b4d73..8afaf45fe6 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -58,22 +58,18 @@ static int iterate_dir(
if (errno == ENOENT)
return 0;
- log_error("Failed to open directory %s: %m", path);
+ log_error_errno(errno, "Failed to open directory %s: %m", path);
return -errno;
}
for (;;) {
struct dirent *de;
_cleanup_free_ char *f = NULL;
- int k;
errno = 0;
de = readdir(d);
- if (!de && errno != 0) {
- k = errno;
- log_error("Failed to read directory %s: %s", path, strerror(k));
- return -k;
- }
+ if (!de && errno != 0)
+ return log_error_errno(errno, "Failed to read directory %s: %m", path);
if (!de)
break;
@@ -87,7 +83,7 @@ static int iterate_dir(
r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
if (r < 0)
- log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
+ log_error_errno(r, "Cannot add dependency %s to %s, ignoring: %m", de->d_name, u->id);
}
return 0;
@@ -155,7 +151,7 @@ char **unit_find_dropin_paths(Unit *u) {
r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
if (r < 0) {
- log_error("Failed to get list of configuration files: %s", strerror(-r));
+ log_error_errno(r, "Failed to get list of configuration files: %m");
strv_free(configs);
return NULL;
}
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index ca0139479b..e0ffaa605a 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -54,10 +54,10 @@ m4_ifdef(`HAVE_SECCOMP',
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
-`$1.SystemCallFilter, config_parse_warn_compat, 0, 0
-$1.SystemCallArchitectures, config_parse_warn_compat, 0, 0
-$1.SystemCallErrorNumber, config_parse_warn_compat, 0, 0
-$1.RestrictAddressFamilies, config_parse_warn_compat, 0, 0')
+`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 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)
@@ -88,15 +88,18 @@ $1.RuntimeDirectoryMode, config_parse_mode, 0,
$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
m4_ifdef(`HAVE_PAM',
`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)',
-`$1.PAMName, config_parse_warn_compat, 0, 0')
+`$1.PAMName, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
$1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe)
$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id)
m4_ifdef(`HAVE_SELINUX',
`$1.SELinuxContext, config_parse_exec_selinux_context, 0, offsetof($1, exec_context)',
-`$1.SELinuxContext, config_parse_warn_compat, 0, 0')
+`$1.SELinuxContext, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
m4_ifdef(`HAVE_APPARMOR',
-`$1.AppArmorProfile, config_parse_exec_apparmor_profile,0, offsetof($1, exec_context)',
-`$1.AppArmorProfile, config_parse_warn_compat, 0, 0')'
+`$1.AppArmorProfile, config_parse_exec_apparmor_profile, 0, offsetof($1, exec_context)',
+`$1.AppArmorProfile, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
+m4_ifdef(`HAVE_SMACK',
+`$1.SmackProcessLabel, config_parse_exec_smack_process_label, 0, offsetof($1, exec_context)',
+`$1.SmackProcessLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')'
)m4_dnl
m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
@@ -119,7 +122,8 @@ $1.BlockIOWeight, config_parse_blockio_weight, 0,
$1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight)
$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
-$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)'
+$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
+$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
)m4_dnl
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
@@ -154,25 +158,44 @@ Unit.IgnoreOnSnapshot, config_parse_bool, 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)
-Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0
-Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0
-Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0
-Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0
-Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0
-Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, 0
-Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0
-Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, 0
-Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0
-Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, 0
-Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, 0
-Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0
-Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, 0
-Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0
-Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0
-Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0
-Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0
-Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, 0
-Unit.ConditionNull, config_parse_unit_condition_null, 0, 0
+Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions)
+Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions)
+Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions)
+Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, conditions)
+Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
+Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions)
+Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
+Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions)
+Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions)
+Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions)
+Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions)
+Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)
+Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
+Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
+Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions)
+Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, conditions)
+Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions)
+Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, conditions)
+Unit.ConditionNull, config_parse_unit_condition_null, 0, offsetof(Unit, conditions)
+Unit.AssertPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, asserts)
+Unit.AssertPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, asserts)
+Unit.AssertPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, asserts)
+Unit.AssertPathIsSymbolicLink, config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, asserts)
+Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
+Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts)
+Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
+Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts)
+Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts)
+Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts)
+Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts)
+Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts)
+Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts)
+Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts)
+Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts)
+Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, asserts)
+Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts)
+Unit.AssertACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, asserts)
+Unit.AssertNull, config_parse_unit_condition_null, 0, offsetof(Unit, asserts)
m4_dnl
Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)
Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command)
@@ -200,16 +223,14 @@ Service.GuessMainPID, config_parse_bool, 0,
Service.RestartPreventExitStatus, config_parse_set_status, 0, offsetof(Service, restart_prevent_status)
Service.RestartForceExitStatus, config_parse_set_status, 0, offsetof(Service, restart_force_status)
Service.SuccessExitStatus, config_parse_set_status, 0, offsetof(Service, success_status)
-m4_ifdef(`HAVE_SYSV_COMPAT',
-`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)',
-`Service.SysVStartPriority, config_parse_warn_compat, 0, 0')
+Service.SysVStartPriority, config_parse_warn_compat, DISABLED_LEGACY, 0
Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking)
Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name)
Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
Service.Sockets, config_parse_service_sockets, 0, 0
m4_ifdef(`ENABLE_KDBUS',
`Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)',
-`Service.BusPolicy, config_parse_warn_compat, 0, 0')
+`Service.BusPolicy, config_parse_warn_compat, DISABLED_EXPERIMENTAL, 0')
EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
@@ -264,12 +285,12 @@ m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in)
Socket.SmackLabelIPOut, config_parse_string, 0, offsetof(Socket, smack_ip_out)',
-`Socket.SmackLabel, config_parse_warn_compat, 0, 0
-Socket.SmackLabelIPIn, config_parse_warn_compat, 0, 0
-Socket.SmackLabelIPOut, config_parse_warn_compat, 0, 0')
+`Socket.SmackLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+Socket.SmackLabelIPIn, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+Socket.SmackLabelIPOut, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
m4_ifdef(`HAVE_SELINUX',
`Socket.SELinuxContextFromNet, config_parse_bool, 0, offsetof(Socket, selinux_context_from_net)',
-`Socket.SELinuxContextFromNet, config_parse_warn_compat, 0, 0')
+`Socket.SELinuxContextFromNet, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index e193a67dcd..259323bd5c 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -59,12 +59,12 @@
#include "bus-error.h"
#include "errno-list.h"
#include "af-list.h"
+#include "cap-list.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
-#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
int config_parse_warn_compat(
const char *unit,
const char *filename,
@@ -76,13 +76,25 @@ int config_parse_warn_compat(
const char *rvalue,
void *data,
void *userdata) {
+ Disabled reason = ltype;
+
+ switch(reason) {
+ case DISABLED_CONFIGURATION:
+ log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
+ "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
+ break;
+ case DISABLED_LEGACY:
+ log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ "Support for option %s= has been removed and it is ignored", lvalue);
+ break;
+ case DISABLED_EXPERIMENTAL:
+ log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ "Support for option %s= has not yet been enabled and it is ignored", lvalue);
+ break;
+ };
- log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
- "Support for option %s= has been disabled at compile time and is ignored",
- lvalue);
return 0;
}
-#endif
int config_parse_unit_deps(const char *unit,
const char *filename,
@@ -1029,17 +1041,15 @@ int config_parse_bounding_set(const char *unit,
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
_cleanup_free_ char *t = NULL;
- int r;
- cap_value_t cap;
+ int cap;
t = strndup(word, l);
if (!t)
return log_oom();
- r = cap_from_name(t, &cap);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse capability in bounding set, ignoring: %s", t);
+ cap = capability_from_name(t);
+ if (cap < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
continue;
}
@@ -1313,6 +1323,56 @@ int config_parse_exec_apparmor_profile(
return 0;
}
+int config_parse_exec_smack_process_label(
+ 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) {
+
+ ExecContext *c = data;
+ Unit *u = userdata;
+ bool ignore;
+ char *k;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ free(c->smack_process_label);
+ c->smack_process_label = NULL;
+ c->smack_process_label_ignore = false;
+ return 0;
+ }
+
+ if (rvalue[0] == '-') {
+ ignore = true;
+ rvalue++;
+ } else
+ ignore = false;
+
+ r = unit_name_printf(u, rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ return 0;
+ }
+
+ free(c->smack_process_label);
+ c->smack_process_label = k;
+ c->smack_process_label_ignore = ignore;
+
+ return 0;
+}
+
int config_parse_timer(const char *unit,
const char *filename,
unsigned line,
@@ -1955,22 +2015,23 @@ int config_parse_ip_tos(const char *unit,
return 0;
}
-int config_parse_unit_condition_path(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_condition_path(
+ 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) {
- ConditionType cond = ltype;
- Unit *u = data;
- bool trigger, negate;
- Condition *c;
_cleanup_free_ char *p = NULL;
+ Condition **list = data, *c;
+ ConditionType t = ltype;
+ bool trigger, negate;
+ Unit *u = userdata;
int r;
assert(filename);
@@ -1980,8 +2041,8 @@ int config_parse_unit_condition_path(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- condition_free_list(u->conditions);
- u->conditions = NULL;
+ condition_free_list(*list);
+ *list = NULL;
return 0;
}
@@ -1994,45 +2055,41 @@ int config_parse_unit_condition_path(const char *unit,
rvalue++;
r = unit_full_printf(u, rvalue, &p);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
- if (!p) {
- p = strdup(rvalue);
- if (!p)
- return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
}
if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path in condition not absolute, ignoring: %s", p);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
return 0;
}
- c = condition_new(cond, p, trigger, negate);
+ c = condition_new(t, p, trigger, negate);
if (!c)
return log_oom();
- LIST_PREPEND(conditions, u->conditions, c);
+ LIST_PREPEND(conditions, *list, c);
return 0;
}
-int config_parse_unit_condition_string(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_condition_string(
+ 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) {
- ConditionType cond = ltype;
- Unit *u = data;
- bool trigger, negate;
- Condition *c;
_cleanup_free_ char *s = NULL;
+ Condition **list = data, *c;
+ ConditionType t = ltype;
+ bool trigger, negate;
+ Unit *u = userdata;
int r;
assert(filename);
@@ -2042,8 +2099,8 @@ int config_parse_unit_condition_string(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- condition_free_list(u->conditions);
- u->conditions = NULL;
+ condition_free_list(*list);
+ *list = NULL;
return 0;
}
@@ -2056,36 +2113,32 @@ int config_parse_unit_condition_string(const char *unit,
rvalue++;
r = unit_full_printf(u, rvalue, &s);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
- if (!s) {
- s = strdup(rvalue);
- if (!s)
- return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
}
- c = condition_new(cond, s, trigger, negate);
+ c = condition_new(t, s, trigger, negate);
if (!c)
return log_oom();
- LIST_PREPEND(conditions, u->conditions, c);
+ LIST_PREPEND(conditions, *list, c);
return 0;
}
-int config_parse_unit_condition_null(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_condition_null(
+ 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) {
- Unit *u = data;
- Condition *c;
+ Condition **list = data, *c;
bool trigger, negate;
int b;
@@ -2096,8 +2149,8 @@ int config_parse_unit_condition_null(const char *unit,
if (isempty(rvalue)) {
/* Empty assignment resets the list */
- condition_free_list(u->conditions);
- u->conditions = NULL;
+ condition_free_list(*list);
+ *list = NULL;
return 0;
}
@@ -2111,9 +2164,7 @@ int config_parse_unit_condition_null(const char *unit,
b = parse_boolean(rvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b,
- "Failed to parse boolean value in condition, ignoring: %s",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
return 0;
}
@@ -2124,7 +2175,7 @@ int config_parse_unit_condition_null(const char *unit,
if (!c)
return log_oom();
- LIST_PREPEND(conditions, u->conditions, c);
+ LIST_PREPEND(conditions, *list, c);
return 0;
}
@@ -2446,7 +2497,6 @@ int config_parse_address_families(
void *userdata) {
ExecContext *c = data;
- Unit *u = userdata;
bool invert = false;
const char *word, *state;
size_t l;
@@ -2455,7 +2505,6 @@ int config_parse_address_families(
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(u);
if (isempty(rvalue)) {
/* Empty assignment resets the list */
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 65100c9bd7..21e0871e8b 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -94,6 +94,7 @@ int config_parse_job_mode_isolate(const char *unit, const char *filename, unsign
int config_parse_exec_selinux_context(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_personality(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_apparmor_profile(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_smack_process_label(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_address_families(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_runtime_directory(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_set_status(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);
@@ -106,3 +107,9 @@ int config_parse_protect_system(const char* unit, const char *filename, unsigned
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
extern const char load_fragment_gperf_nulstr[];
+
+typedef enum Disabled {
+ DISABLED_CONFIGURATION,
+ DISABLED_LEGACY,
+ DISABLED_EXPERIMENTAL,
+} Disabled;
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index 5177dbfd08..e993c57321 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -56,7 +56,7 @@ int locale_setup(char ***environment) {
NULL);
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read /proc/cmdline: %m");
}
/* Hmm, nothing set on the kernel cmd line? Then let's
@@ -80,7 +80,7 @@ int locale_setup(char ***environment) {
NULL);
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read /etc/locale.conf: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read /etc/locale.conf: %m");
}
add = NULL;
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 6ac1fffd75..98fc04dd2e 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -92,16 +92,10 @@ int loopback_setup(void) {
r = start_loopback(rtnl);
if (r == -EPERM) {
- if (check_loopback() < 0) {
- log_warning("Failed to configure loopback device: %s",
- strerror(EPERM));
- return -EPERM;
- }
- } else if (r < 0) {
- log_warning("Failed to configure loopback device: %s",
- strerror(-r));
- return r;
- }
+ if (check_loopback() < 0)
+ return log_warning_errno(EPERM, "Failed to configure loopback device: %m");
+ } else if (r < 0)
+ return log_warning_errno(r, "Failed to configure loopback device: %m");
return 0;
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index efb074fcbd..d91a02cf15 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -141,10 +141,8 @@ static int generate(char id[34], const char *root) {
/* If that didn't work, generate a random machine id */
r = sd_id128_randomize(&buf);
- if (r < 0) {
- log_error("Failed to open /dev/urandom: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open /dev/urandom: %m");
for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
q[0] = hexchar(*p >> 4);
@@ -159,10 +157,120 @@ static int generate(char id[34], const char *root) {
return 0;
}
+static int get_valid_machine_id(int fd, char id[34]) {
+ char id_to_validate[34];
+
+ assert(fd >= 0);
+ assert(id);
+
+ if (loop_read(fd, id_to_validate, 33, false) == 33 && id_to_validate[32] == '\n') {
+ id_to_validate[32] = 0;
+
+ if (id128_is_valid(id_to_validate)) {
+ memcpy(id, id_to_validate, 32);
+ id[32] = '\n';
+ id[33] = 0;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int write_machine_id(int fd, char id[34]) {
+ assert(fd >= 0);
+ assert(id);
+ lseek(fd, 0, SEEK_SET);
+
+ if (loop_write(fd, id, 33, false) == 0)
+ return 0;
+
+ return -errno;
+}
+
+int machine_id_commit(const char *root) {
+ _cleanup_close_ int fd = -1, initial_mntns_fd = -1;
+ const char *etc_machine_id;
+ char id[34]; /* 32 + \n + \0 */
+ int r;
+
+ if (isempty(root))
+ etc_machine_id = "/etc/machine-id";
+ else {
+ char *x;
+
+ x = strappenda(root, "/etc/machine-id");
+ etc_machine_id = path_kill_slashes(x);
+ }
+
+ r = path_is_mount_point(etc_machine_id, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine wether %s is a mount point: %m", etc_machine_id);
+ if (r == 0) {
+ log_debug("%s is is not a mount point. Nothing to do.", etc_machine_id);
+ return 0;
+ }
+
+ /* Read existing machine-id */
+ fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
+
+ r = get_valid_machine_id(fd, id);
+ if (r < 0)
+ return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
+
+ r = is_fd_on_temporary_fs(fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
+ if (r == 0) {
+ log_error("%s is not on a temporary file system.", etc_machine_id);
+ return -EROFS;
+ }
+
+ fd = safe_close(fd);
+
+ /* Store current mount namespace */
+ r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Can't fetch current mount namespace: %m");
+
+ /* Switch to a new mount namespace, isolate ourself and unmount etc_machine_id in our new namespace */
+ if (unshare(CLONE_NEWNS) < 0)
+ return log_error_errno(errno, "Failed to enter new namespace: %m");
+
+ if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
+ return log_error_errno(errno, "Couldn't make-rslave / mountpoint in our private namespace: %m");
+
+ if (umount(etc_machine_id) < 0)
+ return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id);
+
+ /* Update a persistent version of etc_machine_id */
+ fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
+ if (fd < 0)
+ return log_error_errno(errno, "Cannot open for writing %s. This is mandatory to get a persistent machine-id: %m", etc_machine_id);
+
+ r = write_machine_id(fd, id);
+ if (r < 0)
+ return log_error_errno(r, "Cannot write %s: %m", etc_machine_id);
+
+ fd = safe_close(fd);
+
+ /* Return to initial namespace and proceed a lazy tmpfs unmount */
+ r = namespace_enter(-1, initial_mntns_fd, -1, -1);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to switch back to initial mount namespace: %m.\nWe'll keep transient %s file until next reboot.", etc_machine_id);
+
+ if (umount2(etc_machine_id, MNT_DETACH) < 0)
+ return log_warning_errno(errno, "Failed to unmount transient %s file: %m.\nWe keep that mount until next reboot.", etc_machine_id);
+
+ return 0;
+}
+
int machine_id_setup(const char *root) {
const char *etc_machine_id, *run_machine_id;
_cleanup_close_ int fd = -1;
- bool writable = false;
+ bool writable = true;
struct stat st;
char id[34]; /* 32 + \n + \0 */
int r;
@@ -171,11 +279,13 @@ int machine_id_setup(const char *root) {
etc_machine_id = "/etc/machine-id";
run_machine_id = "/run/machine-id";
} else {
- etc_machine_id = strappenda(root, "/etc/machine-id");
- path_kill_slashes((char*) etc_machine_id);
+ char *x;
+
+ x = strappenda(root, "/etc/machine-id");
+ etc_machine_id = path_kill_slashes(x);
- run_machine_id = strappenda(root, "/run/machine-id");
- path_kill_slashes((char*) run_machine_id);
+ x = strappenda(root, "/run/machine-id");
+ run_machine_id = path_kill_slashes(x);
}
RUN_WITH_UMASK(0000) {
@@ -186,12 +296,19 @@ int machine_id_setup(const char *root) {
mkdir_parents(etc_machine_id, 0755);
fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd >= 0)
- writable = true;
- else {
+ if (fd < 0) {
+ int old_errno = errno;
+
fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
- log_error("Cannot open %s: %m", etc_machine_id);
+ if (old_errno == EROFS && errno == ENOENT)
+ log_error("System cannot boot: Missing /etc/machine-id and /etc is mounted read-only.\n"
+ "Booting up is supported only when:\n"
+ "1) /etc/machine-id exists and is populated.\n"
+ "2) /etc/machine-id exists and is empty.\n"
+ "3) /etc/machine-id is missing and /etc is writable.\n");
+ else
+ log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
return -errno;
}
@@ -199,18 +316,11 @@ int machine_id_setup(const char *root) {
}
}
- if (fstat(fd, &st) < 0) {
- log_error("fstat() failed: %m");
- return -errno;
- }
-
- if (S_ISREG(st.st_mode))
- if (loop_read(fd, id, 33, false) == 33 && id[32] == '\n') {
- id[32] = 0;
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "fstat() failed: %m");
- if (id128_is_valid(id))
- return 0;
- }
+ if (S_ISREG(st.st_mode) && get_valid_machine_id(fd, id) == 0)
+ return 0;
/* Hmm, so, the id currently stored is not useful, then let's
* generate one */
@@ -219,12 +329,9 @@ int machine_id_setup(const char *root) {
if (r < 0)
return r;
- if (S_ISREG(st.st_mode) && writable) {
- lseek(fd, 0, SEEK_SET);
-
- if (loop_write(fd, id, 33, false) == 33)
+ if (S_ISREG(st.st_mode) && writable)
+ if (write_machine_id(fd, id) == 0)
return 0;
- }
fd = safe_close(fd);
@@ -235,7 +342,7 @@ int machine_id_setup(const char *root) {
r = write_string_file(run_machine_id, id);
}
if (r < 0) {
- log_error("Cannot write %s: %s", run_machine_id, strerror(-r));
+ log_error_errno(r, "Cannot write %s: %m", run_machine_id);
unlink(run_machine_id);
return r;
}
@@ -243,7 +350,7 @@ int machine_id_setup(const char *root) {
/* And now, let's mount it over */
r = mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL);
if (r < 0) {
- log_error("Failed to mount %s: %m", etc_machine_id);
+ log_error_errno(errno, "Failed to mount %s: %m", etc_machine_id);
unlink_noerrno(run_machine_id);
return -errno;
}
@@ -252,7 +359,7 @@ int machine_id_setup(const char *root) {
/* Mark the mount read-only */
if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
- log_warning("Failed to make transient %s read-only: %m", etc_machine_id);
+ log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
return 0;
}
diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h
index b0583eefc8..f7707c3bf9 100644
--- a/src/core/machine-id-setup.h
+++ b/src/core/machine-id-setup.h
@@ -21,4 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+int machine_id_commit(const char *root);
int machine_id_setup(const char *root);
diff --git a/src/core/main.c b/src/core/main.c
index d48604e673..140f2195ac 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -75,9 +75,7 @@
#include "selinux-setup.h"
#include "ima-setup.h"
#include "smack-setup.h"
-#ifdef HAVE_KMOD
#include "kmod-setup.h"
-#endif
static enum {
ACTION_RUN,
@@ -133,7 +131,7 @@ noreturn static void crash(int sig) {
/* Pass this on immediately, if this is not PID 1 */
raise(sig);
else if (!arg_dump_core)
- log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
+ log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
else {
struct sigaction sa = {
.sa_handler = nop_handler,
@@ -146,7 +144,7 @@ noreturn static void crash(int sig) {
pid = fork();
if (pid < 0)
- log_error("Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
+ log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
else if (pid == 0) {
struct rlimit rl = {};
@@ -177,11 +175,11 @@ noreturn static void crash(int sig) {
/* Order things nicely. */
r = wait_for_terminate(pid, &status);
if (r < 0)
- log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
+ log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
else if (status.si_code != CLD_DUMPED)
- log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
+ log_emergency("Caught <%s>, core dump failed.", signal_to_string(sig));
else
- log_error("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid);
+ log_emergency("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid);
}
}
@@ -203,19 +201,19 @@ noreturn static void crash(int sig) {
pid = fork();
if (pid < 0)
- log_error("Failed to fork off crash shell: %m");
+ log_emergency_errno(errno, "Failed to fork off crash shell: %m");
else if (pid == 0) {
make_console_stdio();
execl("/bin/sh", "/bin/sh", NULL);
- log_error("execl() failed: %m");
+ log_emergency_errno(errno, "execl() failed: %m");
_exit(1);
}
log_info("Successfully spawned crash shell as pid "PID_FMT".", pid);
}
- log_info("Freezing execution.");
+ log_emergency("Freezing execution.");
freeze();
}
@@ -233,18 +231,14 @@ static int console_setup(void) {
int r;
tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (tty_fd < 0) {
- log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
- return tty_fd;
- }
+ if (tty_fd < 0)
+ return log_error_errno(tty_fd, "Failed to open /dev/console: %m");
/* We don't want to force text mode. plymouth may be showing
* pictures already from initrd. */
r = reset_terminal_fd(tty_fd, false);
- if (r < 0) {
- log_error("Failed to reset /dev/console: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to reset /dev/console: %m");
return 0;
}
@@ -356,7 +350,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
if (env)
arg_default_environment = env;
else
- log_warning("Setting environment variable '%s' failed, ignoring: %s", value, strerror(ENOMEM));
+ log_warning_errno(ENOMEM, "Setting environment variable '%s' failed, ignoring: %m", value);
} else
log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
@@ -470,7 +464,7 @@ static int config_parse_cpu_affinity2(
if (c) {
if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_warning_unit(unit, "Failed to set CPU affinity: %m");
+ log_unit_warning(unit, "Failed to set CPU affinity: %m");
CPU_FREE(c);
}
@@ -673,13 +667,12 @@ static int parse_config_file(void) {
{}
};
- const char *fn;
+ const char *fn, *conf_dirs_nulstr;
fn = arg_running_as == SYSTEMD_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
- config_parse(NULL, fn, NULL,
- "Manager\0",
- config_item_table_lookup, items,
- false, false, true, NULL);
+ conf_dirs_nulstr = arg_running_as == SYSTEMD_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
+ config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
+ config_item_table_lookup, items, false, NULL);
return 0;
}
@@ -808,10 +801,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_UNIT:
r = set_default_unit(optarg);
- if (r < 0) {
- log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default unit %s: %m", optarg);
break;
@@ -892,10 +883,8 @@ static int parse_argv(int argc, char *argv[]) {
fd_cloexec(fd, true);
f = fdopen(fd, "r");
- if (!f) {
- log_error("Failed to open serialization fd: %m");
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to open serialization fd: %m");
if (arg_serialization)
fclose(arg_serialization);
@@ -992,7 +981,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
r = manager_open_serialization(m, &f);
if (r < 0) {
- log_error("Failed to create serialization file: %s", strerror(-r));
+ log_error_errno(r, "Failed to create serialization file: %m");
goto fail;
}
@@ -1003,30 +992,30 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
fds = fdset_new();
if (!fds) {
r = -ENOMEM;
- log_error("Failed to allocate fd set: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate fd set: %m");
goto fail;
}
r = manager_serialize(m, f, fds, switching_root);
if (r < 0) {
- log_error("Failed to serialize state: %s", strerror(-r));
+ log_error_errno(r, "Failed to serialize state: %m");
goto fail;
}
if (fseeko(f, 0, SEEK_SET) < 0) {
- log_error("Failed to rewind serialization fd: %m");
+ log_error_errno(errno, "Failed to rewind serialization fd: %m");
goto fail;
}
r = fd_cloexec(fileno(f), false);
if (r < 0) {
- log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
+ log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
goto fail;
}
r = fdset_cloexec(fds, false);
if (r < 0) {
- log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
+ log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
goto fail;
}
@@ -1053,10 +1042,8 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
/* Save the original RLIMIT_NOFILE so that we can reset it
* later when transitioning from the initrd to the main
* systemd or suchlike. */
- if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0) {
- log_error("Reading RLIMIT_NOFILE failed: %m");
- return -errno;
- }
+ if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0)
+ return log_error_errno(errno, "Reading RLIMIT_NOFILE failed: %m");
/* Make sure forked processes get the default kernel setting */
if (!arg_default_rlimit[RLIMIT_NOFILE]) {
@@ -1072,10 +1059,8 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
/* Bump up the resource limit for ourselves substantially */
nl.rlim_cur = nl.rlim_max = 64*1024;
r = setrlimit_closest(RLIMIT_NOFILE, &nl);
- if (r < 0) {
- log_error("Setting RLIMIT_NOFILE failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Setting RLIMIT_NOFILE failed: %m");
return 0;
}
@@ -1156,20 +1141,20 @@ static int enforce_syscall_archs(Set *archs) {
if (r == -EEXIST)
continue;
if (r < 0) {
- log_error("Failed to add architecture to seccomp: %s", strerror(-r));
+ log_error_errno(r, "Failed to add architecture to seccomp: %m");
goto finish;
}
}
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
if (r < 0) {
- log_error("Failed to unset NO_NEW_PRIVS: %s", strerror(-r));
+ log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m");
goto finish;
}
r = seccomp_load(seccomp);
if (r < 0)
- log_error("Failed to add install architecture seccomp: %s", strerror(-r));
+ log_error_errno(r, "Failed to add install architecture seccomp: %m");
finish:
seccomp_release(seccomp);
@@ -1195,7 +1180,7 @@ static int status_welcome(void) {
}
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read os-release file: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read os-release file: %m");
return status_printf(NULL, false, false,
"\nWelcome to \x1B[%sm%s\x1B[0m!\n",
@@ -1235,6 +1220,7 @@ int main(int argc, char *argv[]) {
bool empty_etc = false;
char *switch_root_dir = NULL, *switch_root_init = NULL;
static struct rlimit saved_rlimit_nofile = { 0, 0 };
+ const char *error_message = NULL;
#ifdef HAVE_SYSV_COMPAT
if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
@@ -1243,7 +1229,7 @@ int main(int argc, char *argv[]) {
errno = -ENOENT;
execv(SYSTEMCTL_BINARY_PATH, argv);
- log_error("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
+ log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
return 1;
}
#endif
@@ -1293,17 +1279,23 @@ int main(int argc, char *argv[]) {
if (!skip_setup) {
mount_setup_early();
dual_timestamp_get(&security_start_timestamp);
- if (mac_selinux_setup(&loaded_policy) < 0)
+ if (mac_selinux_setup(&loaded_policy) < 0) {
+ error_message = "Failed to load SELinux policy";
goto finish;
- if (ima_setup() < 0)
+ } else if (ima_setup() < 0) {
+ error_message = "Failed to load IMA policy";
goto finish;
- if (mac_smack_setup(&loaded_policy) < 0)
+ } else if (mac_smack_setup(&loaded_policy) < 0) {
+ error_message = "Failed to load SMACK policy";
goto finish;
+ }
dual_timestamp_get(&security_finish_timestamp);
}
- if (mac_selinux_init(NULL) < 0)
+ if (mac_selinux_init(NULL) < 0) {
+ error_message = "Failed to initialize SELinux policy";
goto finish;
+ }
if (!skip_setup) {
if (clock_is_localtime() > 0) {
@@ -1319,7 +1311,7 @@ int main(int argc, char *argv[]) {
*/
r = clock_set_timezone(&min);
if (r < 0)
- log_error("Failed to apply local time delta, ignoring: %s", strerror(-r));
+ log_error_errno(r, "Failed to apply local time delta, ignoring: %m");
else
log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
} else if (!in_initrd()) {
@@ -1378,20 +1370,30 @@ int main(int argc, char *argv[]) {
/* Initialize default unit */
r = set_default_unit(SPECIAL_DEFAULT_TARGET);
if (r < 0) {
- log_error("Failed to set default unit %s: %s", SPECIAL_DEFAULT_TARGET, strerror(-r));
+ log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
+ error_message = "Failed to set default unit";
goto finish;
}
r = initialize_join_controllers();
- if (r < 0)
+ if (r < 0) {
+ error_message = "Failed to initalize cgroup controllers";
goto finish;
+ }
/* Mount /proc, /sys and friends, so that /proc/cmdline and
* /proc/$PID/fd is available. */
if (getpid() == 1) {
+
+ /* Load the kernel modules early, so that we kdbus.ko is loaded before kdbusfs shall be mounted */
+ if (!skip_setup)
+ kmod_setup();
+
r = mount_setup(loaded_policy);
- if (r < 0)
+ if (r < 0) {
+ error_message = "Failed to mount API filesystems";
goto finish;
+ }
}
/* Reset all signal handlers. */
@@ -1399,19 +1401,25 @@ int main(int argc, char *argv[]) {
ignore_signals(SIGNALS_IGNORE, -1);
- if (parse_config_file() < 0)
+ if (parse_config_file() < 0) {
+ error_message = "Failed to parse config file";
goto finish;
+ }
- if (arg_running_as == SYSTEMD_SYSTEM)
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- goto finish;
+ if (arg_running_as == SYSTEMD_SYSTEM) {
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+ }
/* Note that this also parses bits from the kernel command
* line, including "debug". */
log_parse_environment();
- if (parse_argv(argc, argv) < 0)
+ if (parse_argv(argc, argv) < 0) {
+ error_message = "Failed to parse commandline arguments";
goto finish;
+ }
if (arg_action == ACTION_TEST &&
geteuid() == 0) {
@@ -1467,7 +1475,8 @@ int main(int argc, char *argv[]) {
/* Remember open file descriptors for later deserialization */
r = fdset_new_fill(&fds);
if (r < 0) {
- log_error("Failed to allocate fd set: %s", strerror(-r));
+ log_emergency_errno(r, "Failed to allocate fd set: %m");
+ error_message = "Failed to allocate fd set";
goto finish;
} else
fdset_cloexec(fds, true);
@@ -1551,9 +1560,6 @@ int main(int argc, char *argv[]) {
if (arg_show_status > 0 || plymouth_running())
status_welcome();
-#ifdef HAVE_KMOD
- kmod_setup();
-#endif
hostname_setup();
machine_id_setup(NULL);
loopback_setup();
@@ -1567,31 +1573,35 @@ int main(int argc, char *argv[]) {
if (arg_timer_slack_nsec != NSEC_INFINITY)
if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
- log_error("Failed to adjust timer slack: %m");
+ log_error_errno(errno, "Failed to adjust timer slack: %m");
if (arg_capability_bounding_set_drop) {
r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
if (r < 0) {
- log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r));
+ log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
+ error_message = "Failed to drop capability bounding set of usermode helpers";
goto finish;
}
r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
if (r < 0) {
- log_error("Failed to drop capability bounding set: %s", strerror(-r));
+ log_emergency_errno(r, "Failed to drop capability bounding set: %m");
+ error_message = "Failed to drop capability bounding set";
goto finish;
}
}
if (arg_syscall_archs) {
r = enforce_syscall_archs(arg_syscall_archs);
- if (r < 0)
+ if (r < 0) {
+ error_message = "Failed to set syscall architectures";
goto finish;
+ }
}
if (arg_running_as == SYSTEMD_USER) {
/* Become reaper of our children */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
- log_warning("Failed to make us a subreaper: %m");
+ log_warning_errno(errno, "Failed to make us a subreaper: %m");
if (errno == EINVAL)
log_info("Perhaps the kernel version is too old (< 3.4?)");
}
@@ -1603,7 +1613,7 @@ int main(int argc, char *argv[]) {
if (empty_etc) {
r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0);
if (r < 0)
- log_warning("Failed to populate /etc with preset unit settings, ignoring: %s", strerror(-r));
+ log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
else
log_info("Populated /etc with preset unit settings.");
}
@@ -1611,7 +1621,8 @@ int main(int argc, char *argv[]) {
r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m);
if (r < 0) {
- log_error("Failed to allocate manager object: %s", strerror(-r));
+ log_emergency_errno(r, "Failed to allocate manager object: %m");
+ error_message = "Failed to allocate manager object";
goto finish;
}
@@ -1648,7 +1659,7 @@ int main(int argc, char *argv[]) {
r = manager_startup(m, arg_serialization, fds);
if (r < 0)
- log_error("Failed to fully start up daemon: %s", strerror(-r));
+ log_error_errno(r, "Failed to fully start up daemon: %m");
/* This will close all file descriptors that were opened, but
* not claimed by any unit. */
@@ -1671,7 +1682,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error("Failed to load default target: %s", bus_error_message(&error, r));
else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND)
- log_error("Failed to load default target: %s", strerror(-target->load_error));
+ log_error_errno(target->load_error, "Failed to load default target: %m");
else if (target->load_state == UNIT_MASKED)
log_error("Default target masked.");
@@ -1680,13 +1691,16 @@ int main(int argc, char *argv[]) {
r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target);
if (r < 0) {
- log_error("Failed to load rescue target: %s", bus_error_message(&error, r));
+ log_emergency("Failed to load rescue target: %s", bus_error_message(&error, r));
+ error_message = "Failed to load rescue target";
goto finish;
} else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) {
- log_error("Failed to load rescue target: %s", strerror(-target->load_error));
+ log_emergency_errno(target->load_error, "Failed to load rescue target: %m");
+ error_message = "Failed to load rescue target";
goto finish;
} else if (target->load_state == UNIT_MASKED) {
- log_error("Rescue target masked.");
+ log_emergency("Rescue target masked.");
+ error_message = "Rescue target masked";
goto finish;
}
}
@@ -1704,11 +1718,13 @@ int main(int argc, char *argv[]) {
r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job);
if (r < 0) {
- log_error("Failed to start default target: %s", bus_error_message(&error, r));
+ log_emergency("Failed to start default target: %s", bus_error_message(&error, r));
+ error_message = "Failed to start default target";
goto finish;
}
} else if (r < 0) {
- log_error("Failed to isolate default target: %s", bus_error_message(&error, r));
+ log_emergency("Failed to isolate default target: %s", bus_error_message(&error, r));
+ error_message = "Failed to isolate default target";
goto finish;
}
@@ -1730,7 +1746,8 @@ int main(int argc, char *argv[]) {
for (;;) {
r = manager_loop(m);
if (r < 0) {
- log_error("Failed to run mainloop: %s", strerror(-r));
+ log_emergency_errno(r, "Failed to run main loop: %m");
+ error_message = "Failed to run main loop";
goto finish;
}
@@ -1745,13 +1762,15 @@ int main(int argc, char *argv[]) {
log_info("Reloading.");
r = manager_reload(m);
if (r < 0)
- log_error("Failed to reload: %s", strerror(-r));
+ log_error_errno(r, "Failed to reload: %m");
break;
case MANAGER_REEXECUTE:
- if (prepare_reexecute(m, &arg_serialization, &fds, false) < 0)
+ if (prepare_reexecute(m, &arg_serialization, &fds, false) < 0) {
+ error_message = "Failed to prepare for reexection";
goto finish;
+ }
reexecute = true;
log_notice("Reexecuting.");
@@ -1764,8 +1783,10 @@ int main(int argc, char *argv[]) {
m->switch_root = m->switch_root_init = NULL;
if (!switch_root_init)
- if (prepare_reexecute(m, &arg_serialization, &fds, true) < 0)
+ if (prepare_reexecute(m, &arg_serialization, &fds, true) < 0) {
+ error_message = "Failed to prepare for reexection";
goto finish;
+ }
reexecute = true;
log_notice("Switching root.");
@@ -1797,10 +1818,7 @@ int main(int argc, char *argv[]) {
finish:
pager_close();
- if (m) {
- manager_free(m);
- m = NULL;
- }
+ m = manager_free(m);
for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) {
free(arg_default_rlimit[j]);
@@ -1845,7 +1863,7 @@ finish:
/* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE);
if (r < 0)
- log_error("Failed to switch root, trying to continue: %s", strerror(-r));
+ log_error_errno(r, "Failed to switch root, trying to continue: %m");
}
args_size = MAX(6, argc+1);
@@ -1914,7 +1932,7 @@ finish:
if (switch_root_init) {
args[0] = switch_root_init;
execv(args[0], (char* const*) args);
- log_warning("Failed to execute configured init, trying fallback: %m");
+ log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
}
args[0] = "/sbin/init";
@@ -1926,9 +1944,9 @@ finish:
args[0] = "/bin/sh";
args[1] = NULL;
execv(args[0], (char* const*) args);
- log_error("Failed to execute /bin/sh, giving up: %m");
+ log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
} else
- log_warning("Failed to execute /sbin/init, giving up: %m");
+ log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m");
}
if (arg_serialization) {
@@ -2009,12 +2027,17 @@ finish:
cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
- log_error("Failed to execute shutdown binary, %s: %m",
+ log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",
getpid() == 1 ? "freezing" : "quitting");
}
- if (getpid() == 1)
+ if (getpid() == 1) {
+ if (error_message)
+ manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
+ ANSI_HIGHLIGHT_RED_ON "!!!!!!" ANSI_HIGHLIGHT_OFF,
+ "%s, freezing.", error_message);
freeze();
+ }
return retval;
}
diff --git a/src/core/manager.c b/src/core/manager.c
index d427d88d4e..6382400af4 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -69,7 +69,7 @@
#include "audit-fd.h"
#include "boot-timestamps.h"
#include "env-util.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
#include "dbus.h"
@@ -79,9 +79,6 @@
#include "bus-kernel.h"
#include "time-util.h"
-/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
-#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
-
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
@@ -241,7 +238,7 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source,
if (m->have_ask_password < 0)
/* Log error but continue. Negative have_ask_password
* is treated as unknown status. */
- log_error("Failed to list /run/systemd/ask-password: %s", strerror(m->have_ask_password));
+ log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
return 0;
}
@@ -265,13 +262,11 @@ static int manager_check_ask_password(Manager *m) {
mkdir_p_label("/run/systemd/ask-password", 0755);
m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->ask_password_inotify_fd < 0) {
- log_error("inotify_init1() failed: %m");
- return -errno;
- }
+ if (m->ask_password_inotify_fd < 0)
+ return log_error_errno(errno, "inotify_init1() failed: %m");
if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
- log_error("Failed to add watch on /run/systemd/ask-password: %m");
+ log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
manager_close_ask_password(m);
return -errno;
}
@@ -280,7 +275,7 @@ static int manager_check_ask_password(Manager *m) {
m->ask_password_inotify_fd, EPOLLIN,
manager_dispatch_ask_password_fd, m);
if (r < 0) {
- log_error("Failed to add event source for /run/systemd/ask-password: %m");
+ log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
manager_close_ask_password(m);
return -errno;
}
@@ -305,10 +300,8 @@ static int manager_watch_idle_pipe(Manager *m) {
return 0;
r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
- if (r < 0) {
- log_error("Failed to watch idle pipe: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch idle pipe: %m");
return 0;
}
@@ -339,22 +332,18 @@ static int manager_setup_time_change(Manager *m) {
* CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
- if (m->time_change_fd < 0) {
- log_error("Failed to create timerfd: %m");
- return -errno;
- }
+ if (m->time_change_fd < 0)
+ return log_error_errno(errno, "Failed to create timerfd: %m");
if (timerfd_settime(m->time_change_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
- log_debug("Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
+ log_debug_errno(errno, "Failed to set up TFD_TIMER_CANCEL_ON_SET, ignoring: %m");
m->time_change_fd = safe_close(m->time_change_fd);
return 0;
}
r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m);
- if (r < 0) {
- log_error("Failed to create time change event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create time change event source: %m");
log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
@@ -370,17 +359,17 @@ static int enable_special_signals(Manager *m) {
* this will fail with EPERM (older) or EINVAL (newer), so
* ignore that. */
if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
- log_warning("Failed to enable ctrl-alt-del handling: %m");
+ log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0) {
/* Support systems without virtual console */
if (fd != -ENOENT)
- log_warning("Failed to open /dev/tty0: %m");
+ log_warning_errno(errno, "Failed to open /dev/tty0: %m");
} else {
/* Enable that we get SIGWINCH on kbrequest */
if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
- log_warning("Failed to enable kbrequest handling: %m");
+ log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
}
return 0;
@@ -396,9 +385,6 @@ static int manager_setup_signals(Manager *m) {
assert(m);
- if (m->test_run)
- return 0;
-
assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
/* We make liberal use of realtime signals here. On
@@ -554,7 +540,7 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = -1;
+ m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->ask_password_inotify_fd = -1;
@@ -657,10 +643,8 @@ static int manager_setup_notify(Manager *m) {
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0) {
- log_error("Failed to allocate notification socket: %m");
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate notification socket: %m");
if (m->running_as == SYSTEMD_SYSTEM)
m->notify_socket = strdup("/run/systemd/notify");
@@ -669,7 +653,7 @@ static int manager_setup_notify(Manager *m) {
e = getenv("XDG_RUNTIME_DIR");
if (!e) {
- log_error("XDG_RUNTIME_DIR is not set: %m");
+ log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
return -EINVAL;
}
@@ -678,32 +662,17 @@ static int manager_setup_notify(Manager *m) {
if (!m->notify_socket)
return log_oom();
+ (void) mkdir_parents_label(m->notify_socket, 0755);
+ (void) unlink(m->notify_socket);
+
strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- log_error("bind(%s) failed: %m", sa.un.sun_path);
- if (errno == EADDRINUSE) {
- log_notice("Removing %s socket and trying again.", m->notify_socket);
- r = unlink(m->notify_socket);
- if (r < 0) {
- log_error("Failed to remove %s: %m", m->notify_socket);
- return -EADDRINUSE;
- }
-
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- log_error("bind(%s) failed: %m", sa.un.sun_path);
- return -errno;
- }
- } else
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0) {
- log_error("SO_PASSCRED failed: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "SO_PASSCRED failed: %m");
m->notify_fd = fd;
fd = -1;
@@ -713,18 +682,14 @@ static int manager_setup_notify(Manager *m) {
if (!m->notify_event_source) {
r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
- if (r < 0) {
- log_error("Failed to allocate notify event source: %s", strerror(-r));
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate notify event source: %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);
- if (r < 0) {
- log_error("Failed to set priority of notify event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of notify event source: %m");
}
return 0;
@@ -739,20 +704,17 @@ static int manager_setup_kdbus(Manager *m) {
if (m->test_run || m->kdbus_fd >= 0)
return 0;
- m->kdbus_fd = bus_kernel_create_bus(m->running_as == SYSTEMD_SYSTEM ? "system" : "user", m->running_as == SYSTEMD_SYSTEM, &p);
- if (m->kdbus_fd < 0) {
- log_debug("Failed to set up kdbus: %s", strerror(-m->kdbus_fd));
- return m->kdbus_fd;
- }
+ if (getpid() == 1)
+ bus_kernel_fix_attach_mask();
- log_debug("Successfully set up kdbus on %s", p);
+ m->kdbus_fd = bus_kernel_create_bus(
+ m->running_as == SYSTEMD_SYSTEM ? "system" : "user",
+ m->running_as == SYSTEMD_SYSTEM, &p);
- /* Create the namespace directory here, so that the contents
- * of that directory is not visible to non-root users. This is
- * necessary to ensure that users cannot get access to busses
- * of virtualized users when no UID namespacing is used. */
- if (m->running_as == SYSTEMD_SYSTEM)
- mkdir_p_label("/dev/kdbus/domain", 0700);
+ if (m->kdbus_fd < 0)
+ return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
+
+ log_debug("Successfully set up kdbus on %s", p);
#endif
return 0;
@@ -878,7 +840,7 @@ static unsigned manager_dispatch_gc_queue(Manager *m) {
if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
- log_debug_unit(u->id, "Collecting %s", u->id);
+ log_unit_debug(u->id, "Collecting %s", u->id);
u->gc_marker = gc_marker + GC_OFFSET_BAD;
unit_add_to_cleanup_queue(u);
}
@@ -913,11 +875,12 @@ static void manager_clear_jobs_and_units(Manager *m) {
m->n_running_jobs = 0;
}
-void manager_free(Manager *m) {
+Manager* manager_free(Manager *m) {
UnitType c;
int i;
- assert(m);
+ if (!m)
+ return NULL;
manager_clear_jobs_and_units(m);
@@ -979,6 +942,7 @@ void manager_free(Manager *m) {
hashmap_free(m->units_requiring_mounts_for);
free(m);
+ return NULL;
}
int manager_enumerate(Manager *m) {
@@ -1048,7 +1012,7 @@ static void manager_build_unit_path_cache(Manager *m) {
d = opendir(*i);
if (!d) {
if (errno != ENOENT)
- log_error("Failed to open directory %s: %m", *i);
+ log_error_errno(errno, "Failed to open directory %s: %m", *i);
continue;
}
@@ -1076,7 +1040,7 @@ static void manager_build_unit_path_cache(Manager *m) {
return;
fail:
- log_error("Failed to build unit path cache: %s", strerror(-r));
+ log_error_errno(r, "Failed to build unit path cache: %m");
set_free_free(m->unit_path_cache);
m->unit_path_cache = NULL;
@@ -1189,17 +1153,13 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
assert(unit);
assert(mode < _JOB_MODE_MAX);
- if (mode == JOB_ISOLATE && type != JOB_START) {
- sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
- return -EINVAL;
- }
+ if (mode == JOB_ISOLATE && type != JOB_START)
+ return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
- if (mode == JOB_ISOLATE && !unit->allow_isolate) {
- sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
- return -EPERM;
- }
+ if (mode == JOB_ISOLATE && !unit->allow_isolate)
+ return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
- log_debug_unit(unit->id,
+ log_unit_debug(unit->id,
"Trying to enqueue job %s/%s/%s", unit->id,
job_type_to_string(type), job_mode_to_string(mode));
@@ -1225,7 +1185,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
if (r < 0)
goto tr_abort;
- log_debug_unit(unit->id,
+ log_unit_debug(unit->id,
"Enqueued job %s/%s as %u", unit->id,
job_type_to_string(type), (unsigned) tr->anchor_job->id);
@@ -1495,7 +1455,7 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
return;
}
- log_debug_unit(u->id, "Got notification message for unit %s", u->id);
+ log_unit_debug(u->id, "Got notification message for unit %s", u->id);
if (UNIT_VTABLE(u)->notify_message)
UNIT_VTABLE(u)->notify_message(u, pid, tags);
@@ -1591,7 +1551,7 @@ static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
assert(u);
assert(si);
- log_debug_unit(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
+ log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
@@ -1663,11 +1623,11 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
- log_debug_unit(name, "Activating special unit %s", name);
+ log_unit_debug(name, "Activating special unit %s", name);
r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
if (r < 0)
- log_error_unit(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
+ log_unit_error(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
return r;
}
@@ -1902,8 +1862,8 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint
assert(m->time_change_fd == fd);
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
- "MESSAGE=Time has been changed",
+ LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+ LOG_MESSAGE("Time has been changed"),
NULL);
/* Restart the watch */
@@ -2008,10 +1968,8 @@ int manager_loop(Manager *m) {
wait_usec = USEC_INFINITY;
r = sd_event_run(m->event, wait_usec);
- if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
}
return m->exit_code;
@@ -2070,6 +2028,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
#ifdef HAVE_AUDIT
_cleanup_free_ char *p = NULL;
+ const char *msg;
int audit_fd;
audit_fd = get_audit_fd();
@@ -2089,18 +2048,19 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
p = unit_name_to_prefix_and_instance(u->id);
if (!p) {
- log_error_unit(u->id,
- "Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
+ log_oom();
return;
}
- if (audit_log_user_comm_message(audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
- if (errno == EPERM) {
+ msg = strappenda("unit=", p);
+
+ if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", NULL, NULL, NULL, success) < 0) {
+ if (errno == EPERM)
/* We aren't allowed to send audit messages?
* Then let's not retry again. */
close_audit_fd();
- } else
- log_warning("Failed to send audit message: %m");
+ else
+ log_warning_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -2133,14 +2093,14 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
* message then wait for plymouth */
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
- log_error("socket() failed: %m");
+ log_error_errno(errno, "socket() failed: %m");
return;
}
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
- log_error("connect() failed: %m");
+ log_error_errno(errno, "connect() failed: %m");
return;
}
@@ -2152,7 +2112,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
errno = 0;
if (write(fd, message, n + 1) != n + 1)
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
- log_error("Failed to write Plymouth message: %m");
+ log_error_errno(errno, "Failed to write Plymouth message: %m");
}
void manager_dispatch_bus_name_owner_changed(
@@ -2329,7 +2289,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
uint32_t id;
if (safe_atou32(l+15, &id) < 0)
- log_warning("Failed to parse current job id value %s", l+15);
+ log_debug("Failed to parse current job id value %s", l+15);
else
m->current_job_id = MAX(m->current_job_id, id);
@@ -2337,7 +2297,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
uint32_t n;
if (safe_atou32(l+17, &n) < 0)
- log_warning("Failed to parse installed jobs counter %s", l+17);
+ log_debug("Failed to parse installed jobs counter %s", l+17);
else
m->n_installed_jobs += n;
@@ -2345,7 +2305,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
uint32_t n;
if (safe_atou32(l+14, &n) < 0)
- log_warning("Failed to parse failed jobs counter %s", l+14);
+ log_debug("Failed to parse failed jobs counter %s", l+14);
else
m->n_failed_jobs += n;
@@ -2354,7 +2314,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
b = parse_boolean(l+10);
if (b < 0)
- log_warning("Failed to parse taint /usr flag %s", l+10);
+ log_debug("Failed to parse taint /usr flag %s", l+10);
else
m->taint_usr = m->taint_usr || b;
@@ -2405,7 +2365,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int fd;
if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_warning("Failed to parse notify fd: %s", l + 10);
+ log_debug("Failed to parse notify fd: %s", l + 10);
else {
m->notify_event_source = sd_event_source_unref(m->notify_event_source);
safe_close(m->notify_fd);
@@ -2428,14 +2388,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int fd;
if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_warning("Failed to parse kdbus fd: %s", l + 9);
+ log_debug("Failed to parse kdbus fd: %s", l + 9);
else {
safe_close(m->kdbus_fd);
m->kdbus_fd = fdset_remove(fds, fd);
}
- } else if (bus_track_deserialize_item(&m->deserialized_subscribed, l) == 0)
- log_warning("Unknown serialization item '%s'", l);
+ } else {
+ int k;
+
+ k = bus_track_deserialize_item(&m->deserialized_subscribed, l);
+ if (k < 0)
+ log_debug_errno(k, "Failed to deserialize bus tracker object: %m");
+ else if (k == 0)
+ log_debug("Unknown serialization item '%s'", l);
+ }
}
for (;;) {
@@ -2584,45 +2551,13 @@ bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
return unit_inactive_or_pending(u);
}
-void manager_check_finished(Manager *m) {
+static void manager_notify_finished(Manager *m) {
char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
- Unit *u = NULL;
- Iterator i;
-
- assert(m);
-
- if (m->n_running_jobs == 0)
- m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source);
-
- if (hashmap_size(m->jobs) > 0) {
-
- if (m->jobs_in_progress_event_source)
- sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
- return;
- }
-
- manager_flip_auto_status(m, false);
-
- /* Notify Type=idle units that we are done now */
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
- manager_close_idle_pipe(m);
-
- /* Turn off confirm spawn now */
- m->confirm_spawn = false;
-
- /* No need to update ask password status when we're going non-interactive */
- manager_close_ask_password(m);
-
- /* This is no longer the first boot */
- manager_set_first_boot(m, false);
-
- if (dual_timestamp_is_set(&m->finish_timestamp))
+ if (m->test_run)
return;
- dual_timestamp_get(&m->finish_timestamp);
-
if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
@@ -2641,28 +2576,28 @@ void manager_check_finished(Manager *m) {
initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC="USEC_FMT, kernel_usec,
"INITRD_USEC="USEC_FMT, initrd_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
- "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
- format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC),
- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
+ LOG_MESSAGE("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
+ format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
+ format_timespan(initrd, sizeof(initrd), initrd_usec, USEC_PER_MSEC),
+ format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
NULL);
} else {
kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic;
initrd_usec = 0;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"KERNEL_USEC="USEC_FMT, kernel_usec,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
- "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
- format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
+ LOG_MESSAGE("Startup finished in %s (kernel) + %s (userspace) = %s.",
+ format_timespan(kernel, sizeof(kernel), kernel_usec, USEC_PER_MSEC),
+ format_timespan(userspace, sizeof(userspace), userspace_usec, USEC_PER_MSEC),
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
NULL);
}
} else {
@@ -2670,17 +2605,13 @@ void manager_check_finished(Manager *m) {
total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
+ LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
"USERSPACE_USEC="USEC_FMT, userspace_usec,
- "MESSAGE=Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC),
+ LOG_MESSAGE("Startup finished in %s.",
+ format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
NULL);
}
- SET_FOREACH(u, m->startup_units, i)
- if (u->cgroup_path)
- cgroup_context_apply(unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path, manager_state(m));
-
bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
sd_notifyf(false,
@@ -2689,6 +2620,50 @@ void manager_check_finished(Manager *m) {
format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
}
+void manager_check_finished(Manager *m) {
+ Unit *u = NULL;
+ Iterator i;
+
+ assert(m);
+
+ if (m->n_running_jobs == 0)
+ m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source);
+
+ if (hashmap_size(m->jobs) > 0) {
+
+ if (m->jobs_in_progress_event_source)
+ sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
+
+ return;
+ }
+
+ manager_flip_auto_status(m, false);
+
+ /* Notify Type=idle units that we are done now */
+ m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
+ manager_close_idle_pipe(m);
+
+ /* Turn off confirm spawn now */
+ m->confirm_spawn = false;
+
+ /* No need to update ask password status when we're going non-interactive */
+ manager_close_ask_password(m);
+
+ /* This is no longer the first boot */
+ manager_set_first_boot(m, false);
+
+ if (dual_timestamp_is_set(&m->finish_timestamp))
+ return;
+
+ dual_timestamp_get(&m->finish_timestamp);
+
+ manager_notify_finished(m);
+
+ SET_FOREACH(u, m->startup_units, i)
+ if (u->cgroup_path)
+ cgroup_context_apply(unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path, manager_state(m));
+}
+
static int create_generator_dir(Manager *m, char **generator, const char *name) {
char *p;
int r;
@@ -2709,8 +2684,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
r = mkdir_p_label(p, 0755);
if (r < 0) {
- log_error("Failed to create generator directory %s: %s",
- p, strerror(-r));
+ log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
@@ -2726,8 +2700,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
r = mkdir_p_label(p, 0755);
if (r < 0) {
- log_error("Failed to create generator directory %s: %s",
- p, strerror(-r));
+ log_error_errno(r, "Failed to create generator directory %s: %m", p);
free(p);
return r;
}
@@ -2739,7 +2712,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
return log_oom();
if (!mkdtemp(p)) {
- log_error("Failed to create generator directory %s: %m",
+ log_error_errno(errno, "Failed to create generator directory %s: %m",
p);
free(p);
return -errno;
@@ -2782,7 +2755,7 @@ void manager_run_generators(Manager *m) {
if (errno == ENOENT)
return;
- log_error("Failed to enumerate generator directory %s: %m",
+ log_error_errno(errno, "Failed to enumerate generator directory %s: %m",
generator_path);
return;
}
@@ -2972,12 +2945,14 @@ void manager_set_first_boot(Manager *m, bool b) {
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
va_list ap;
- if (!manager_get_show_status(m, type))
+ /* If m is NULL, assume we're after shutdown and let the messages through. */
+
+ if (m && !manager_get_show_status(m, type))
return;
/* XXX We should totally drop the check for ephemeral here
* and thus effectively make 'Type=idle' pointless. */
- if (type == STATUS_TYPE_EPHEMERAL && m->n_on_console > 0)
+ if (type == STATUS_TYPE_EPHEMERAL && m && m->n_on_console > 0)
return;
va_start(ap, format);
diff --git a/src/core/manager.h b/src/core/manager.h
index ab7254849c..ab75f902e5 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -182,6 +182,8 @@ struct Manager {
/* Data specific to the mount subsystem */
FILE *proc_self_mountinfo;
sd_event_source *mount_event_source;
+ int utab_inotify_fd;
+ sd_event_source *mount_utab_event_source;
/* Data specific to the swap filesystem */
FILE *proc_swaps;
@@ -296,7 +298,7 @@ struct Manager {
};
int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
-void manager_free(Manager *m);
+Manager* manager_free(Manager *m);
int manager_enumerate(Manager *m);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index cda25ede13..342f5520c9 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -72,41 +72,45 @@ typedef struct MountPoint {
#endif
static const MountPoint mount_table[] = {
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_NONE },
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_NONE },
#ifdef HAVE_SMACK
- { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- mac_smack_use, MNT_FATAL },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- mac_smack_use, MNT_FATAL },
+ { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ mac_smack_use, MNT_FATAL },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ mac_smack_use, MNT_FATAL },
#endif
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
- NULL, MNT_IN_CONTAINER },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
+ NULL, MNT_IN_CONTAINER },
#ifdef HAVE_SMACK
- { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- mac_smack_use, MNT_FATAL },
+ { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ mac_smack_use, MNT_FATAL },
#endif
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_NONE },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_NONE },
#ifdef ENABLE_EFI
- { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- is_efi_boot, MNT_NONE },
+ { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ is_efi_boot, MNT_NONE },
+#endif
+#ifdef ENABLE_KDBUS
+ { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_IN_CONTAINER },
#endif
};
@@ -231,7 +235,7 @@ int mount_cgroup_controllers(char ***join_controllers) {
f = fopen("/proc/cgroups", "re");
if (!f) {
- log_error("Failed to enumerate cgroup controllers: %m");
+ log_error_errno(errno, "Failed to enumerate cgroup controllers: %m");
return 0;
}
@@ -336,10 +340,8 @@ int mount_cgroup_controllers(char ***join_controllers) {
return log_oom();
r = symlink(options, t);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create symlink %s: %m", t);
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
}
}
}
@@ -376,16 +378,20 @@ static int nftw_cb(
#endif
int mount_setup(bool loaded_policy) {
- int r;
unsigned i;
+ int r = 0;
for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
- r = mount_one(mount_table + i, true);
+ int j;
- if (r < 0)
- return r;
+ j = mount_one(mount_table + i, loaded_policy);
+ if (r == 0)
+ r = j;
}
+ if (r < 0)
+ return r;
+
#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
/* Nodes in devtmpfs and /run need to be manually updated for
* the appropriate labels, after mounting. The other virtual
@@ -420,7 +426,7 @@ int mount_setup(bool loaded_policy) {
* propagation mode to private if needed. */
if (detect_container(NULL) <= 0)
if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
- log_warning("Failed to set up the root directory for shared mount propagation: %m");
+ log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");
/* Create a few directories we always want around, Note that
* sd_booted() checks for /run/systemd/system, so this mkdir
diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h
index 4b521ad0e1..b32fbc5a52 100644
--- a/src/core/mount-setup.h
+++ b/src/core/mount-setup.h
@@ -24,7 +24,6 @@
#include <stdbool.h>
int mount_setup_early(void);
-
int mount_setup(bool loaded_policy);
int mount_cgroup_controllers(char ***join_controllers);
diff --git a/src/core/mount.c b/src/core/mount.c
index 01243c381a..e271d437cb 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -24,6 +24,8 @@
#include <mntent.h>
#include <sys/epoll.h>
#include <signal.h>
+#include <libmount.h>
+#include <sys/inotify.h>
#include "manager.h"
#include "unit.h"
@@ -39,10 +41,13 @@
#include "unit-name.h"
#include "dbus-mount.h"
#include "special.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "exit-status.h"
#include "def.h"
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
+
static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
[MOUNT_DEAD] = UNIT_INACTIVE,
[MOUNT_MOUNTING] = UNIT_ACTIVATING,
@@ -62,19 +67,23 @@ static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static bool mount_is_network(MountParameters *p) {
- assert(p);
-
- if (mount_test_option(p->options, "_netdev"))
+static bool mount_needs_network(const char *options, const char *fstype) {
+ if (mount_test_option(options, "_netdev"))
return true;
- if (p->fstype && fstype_is_network(p->fstype))
+ if (fstype && fstype_is_network(fstype))
return true;
return false;
}
-static bool mount_is_bind(MountParameters *p) {
+static bool mount_is_network(const MountParameters *p) {
+ assert(p);
+
+ return mount_needs_network(p->options, p->fstype);
+}
+
+static bool mount_is_bind(const MountParameters *p) {
assert(p);
if (mount_test_option(p->options, "bind"))
@@ -92,13 +101,13 @@ static bool mount_is_bind(MountParameters *p) {
return false;
}
-static bool mount_is_auto(MountParameters *p) {
+static bool mount_is_auto(const MountParameters *p) {
assert(p);
return !mount_test_option(p->options, "noauto");
}
-static bool needs_quota(MountParameters *p) {
+static bool needs_quota(const MountParameters *p) {
assert(p);
if (mount_is_network(p))
@@ -437,22 +446,22 @@ static int mount_verify(Mount *m) {
b = unit_has_name(UNIT(m), e);
if (!b) {
- log_error_unit(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id);
+ log_unit_error(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id);
return -EINVAL;
}
if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
- log_error_unit(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where);
+ log_unit_error(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where);
return -EINVAL;
}
if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
- log_error_unit(UNIT(m)->id, "%s's What setting is missing. Refusing.", UNIT(m)->id);
+ log_unit_error(UNIT(m)->id, "%s's What setting is missing. Refusing.", UNIT(m)->id);
return -EBADMSG;
}
if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error_unit(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id);
+ log_unit_error(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id);
return -EINVAL;
}
@@ -597,7 +606,7 @@ static void mount_set_state(Mount *m, MountState state) {
}
if (state != old_state)
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"%s changed %s -> %s",
UNIT(m)->id,
mount_state_to_string(old_state),
@@ -715,6 +724,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(m)->cgroup_path;
+ exec_params.cgroup_delegate = m->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
exec_params.unit_id = UNIT(m)->id;
@@ -803,7 +813,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
return;
fail:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
@@ -813,31 +823,38 @@ fail:
}
void warn_if_dir_nonempty(const char *unit, const char* where) {
+ int r;
+
assert(unit);
assert(where);
- if (dir_is_empty(where) > 0)
+ r = dir_is_empty(where);
+ if (r > 0)
return;
-
- log_struct_unit(LOG_NOTICE,
- unit,
- "MESSAGE=%s: Directory %s to mount over is not empty, mounting anyway.",
- unit, where,
- "WHERE=%s", where,
- MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- NULL);
+ else if (r == 0)
+ log_unit_struct(unit,
+ LOG_NOTICE,
+ LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
+ LOG_MESSAGE("%s: Directory %s to mount over is not empty, mounting anyway.",
+ unit, where),
+ "WHERE=%s", where,
+ NULL);
+ else
+ log_unit_warning(unit,
+ "MESSAGE=Failed to check directory %s: %s",
+ where, strerror(-r));
}
static int fail_if_symlink(const char *unit, const char* where) {
assert(where);
if (is_symlink(where) > 0) {
- log_struct_unit(LOG_WARNING,
- unit,
- "MESSAGE=%s: Mount on symlink %s not allowed.",
- unit, where,
+ log_unit_struct(unit,
+ LOG_ERR,
+ LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
+ LOG_MESSAGE("%s: Mount on symlink %s not allowed.",
+ unit, where),
"WHERE=%s", where,
- MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
NULL);
return -ELOOP;
@@ -871,7 +888,7 @@ static void mount_enter_unmounting(Mount *m) {
return;
fail:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s failed to run 'umount' task: %s",
UNIT(m)->id, strerror(-r));
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
@@ -926,7 +943,7 @@ static void mount_enter_mounting(Mount *m) {
return;
fail:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s failed to run 'mount' task: %s",
UNIT(m)->id, strerror(-r));
mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
@@ -974,7 +991,7 @@ static void mount_enter_remounting(Mount *m) {
return;
fail:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s failed to run 'remount' task: %s",
UNIT(m)->id, strerror(-r));
m->reload_result = MOUNT_FAILURE_RESOURCES;
@@ -1078,7 +1095,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
MountState state;
if ((state = mount_state_from_string(value)) < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
m->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -1086,7 +1103,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
f = mount_result_from_string(value);
if (f < 0)
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"Failed to parse result value %s", value);
else if (f != MOUNT_SUCCESS)
m->result = f;
@@ -1096,7 +1113,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
f = mount_result_from_string(value);
if (f < 0)
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"Failed to parse reload result value %s", value);
else if (f != MOUNT_SUCCESS)
m->reload_result = f;
@@ -1105,7 +1122,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"Failed to parse control-pid value %s", value);
else
m->control_pid = pid;
@@ -1113,14 +1130,14 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
MountExecCommand id;
if ((id = mount_exec_command_from_string(value)) < 0)
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"Failed to parse exec-command value %s", value);
else {
m->control_command_id = id;
m->control_command = m->exec_command + id;
}
} else
- log_debug_unit(UNIT(m)->id,
+ log_unit_debug(UNIT(m)->id,
"Unknown serialization key '%s'", key);
return 0;
@@ -1179,7 +1196,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
- log_full_unit(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, u->id,
+ log_unit_full(u->id,
+ f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
"%s mount process exited, code=%s status=%i",
u->id, sigchld_code_to_string(code), status);
@@ -1247,31 +1265,31 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_MOUNTING:
case MOUNT_MOUNTING_DONE:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s mounting timed out. Stopping.", UNIT(m)->id);
mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_REMOUNTING:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s remounting timed out. Stopping.", UNIT(m)->id);
m->reload_result = MOUNT_FAILURE_TIMEOUT;
mount_enter_mounted(m, MOUNT_SUCCESS);
break;
case MOUNT_UNMOUNTING:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s unmounting timed out. Stopping.", UNIT(m)->id);
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
break;
case MOUNT_MOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s mounting timed out. Killing.", UNIT(m)->id);
mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s mounting timed out. Skipping SIGKILL. Ignoring.",
UNIT(m)->id);
@@ -1284,11 +1302,11 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_REMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s remounting timed out. Killing.", UNIT(m)->id);
mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s remounting timed out. Skipping SIGKILL. Ignoring.",
UNIT(m)->id);
@@ -1301,11 +1319,11 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_UNMOUNTING_SIGTERM:
if (m->kill_context.send_sigkill) {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s unmounting timed out. Killing.", UNIT(m)->id);
mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s unmounting timed out. Skipping SIGKILL. Ignoring.",
UNIT(m)->id);
@@ -1319,7 +1337,7 @@ static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case MOUNT_MOUNTING_SIGKILL:
case MOUNT_REMOUNTING_SIGKILL:
case MOUNT_UNMOUNTING_SIGKILL:
- log_warning_unit(UNIT(m)->id,
+ log_unit_warning(UNIT(m)->id,
"%s mount process still around after SIGKILL. Ignoring.",
UNIT(m)->id);
@@ -1401,8 +1419,7 @@ static int mount_add_one(
if (m->running_as == SYSTEMD_SYSTEM) {
const char* target;
- target = fstype_is_network(fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
-
+ target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
if (r < 0)
goto fail;
@@ -1427,6 +1444,15 @@ static int mount_add_one(
}
}
+ if (m->running_as == SYSTEMD_SYSTEM &&
+ mount_needs_network(options, fstype)) {
+ /* _netdev option may have shown up late, or on a
+ * remount. Add remote-fs dependencies, even though
+ * local-fs ones may already be there. */
+ unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true);
+ load_extras = true;
+ }
+
if (u->load_state == UNIT_NOT_FOUND) {
u->load_state = UNIT_LOADED;
u->load_error = 0;
@@ -1492,55 +1518,46 @@ fail:
}
static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
+ _cleanup_(mnt_free_tablep) struct libmnt_table *tb = NULL;
+ _cleanup_(mnt_free_iterp) struct libmnt_iter *itr = NULL;
+ struct libmnt_fs *fs;
int r = 0;
- unsigned i;
assert(m);
- rewind(m->proc_self_mountinfo);
+ tb = mnt_new_table();
+ itr = mnt_new_iter(MNT_ITER_FORWARD);
+ if (!tb || !itr)
+ return log_oom();
+
+ r = mnt_table_parse_mtab(tb, NULL);
+ if (r < 0)
+ return r;
- for (i = 1;; i++) {
- _cleanup_free_ char *device = NULL, *path = NULL, *options = NULL, *options2 = NULL, *fstype = NULL, *d = NULL, *p = NULL, *o = NULL;
+ r = 0;
+ for (;;) {
+ const char *device, *path, *options, *fstype;
+ _cleanup_free_ const char *d = NULL, *p = NULL;
int k;
- k = fscanf(m->proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%ms" /* (6) mount options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%ms " /* (9) file system type */
- "%ms" /* (10) mount source */
- "%ms" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path,
- &options,
- &fstype,
- &device,
- &options2);
-
- if (k == EOF)
+ k = mnt_table_next_fs(tb, itr, &fs);
+ if (k == 1)
break;
+ else if (k < 0)
+ return log_error_errno(k, "Failed to get next entry from /etc/fstab: %m");
- if (k != 5) {
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
- continue;
- }
-
- o = strjoin(options, ",", options2, NULL);
- if (!o)
- return log_oom();
+ device = mnt_fs_get_source(fs);
+ path = mnt_fs_get_target(fs);
+ options = mnt_fs_get_options(fs);
+ fstype = mnt_fs_get_fstype(fs);
d = cunescape(device);
p = cunescape(path);
if (!d || !p)
return log_oom();
- k = mount_add_one(m, d, p, o, fstype, set_flags);
- if (k < 0)
+ k = mount_add_one(m, d, p, options, fstype, set_flags);
+ if (r == 0 && k < 0)
r = k;
}
@@ -1551,11 +1568,13 @@ static void mount_shutdown(Manager *m) {
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
+ m->mount_utab_event_source = sd_event_source_unref(m->mount_utab_event_source);
if (m->proc_self_mountinfo) {
fclose(m->proc_self_mountinfo);
m->proc_self_mountinfo = NULL;
}
+ m->utab_inotify_fd = safe_close(m->utab_inotify_fd);
}
static int mount_get_timeout(Unit *u, uint64_t *timeout) {
@@ -1576,6 +1595,8 @@ static int mount_enumerate(Manager *m) {
int r;
assert(m);
+ mnt_init_debug(0);
+
if (!m->proc_self_mountinfo) {
m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
if (!m->proc_self_mountinfo)
@@ -1593,6 +1614,30 @@ static int mount_enumerate(Manager *m) {
goto fail;
}
+ if (m->utab_inotify_fd < 0) {
+ m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+ if (m->utab_inotify_fd < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ (void) mkdir_p_label("/run/mount", 0755);
+
+ r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO);
+ if (r < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
+ if (r < 0)
+ goto fail;
+
+ r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
+ if (r < 0)
+ goto fail;
+ }
+
r = mount_load_proc_self_mountinfo(m, false);
if (r < 0)
goto fail;
@@ -1610,15 +1655,52 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
int r;
assert(m);
- assert(revents & EPOLLPRI);
+ assert(revents & (EPOLLPRI | EPOLLIN));
/* The manager calls this for every fd event happening on the
* /proc/self/mountinfo file, which informs us about mounting
- * table changes */
+ * table changes, and for /run/mount events which we watch
+ * for mount options. */
+
+ if (fd == m->utab_inotify_fd) {
+ bool rescan = false;
+
+ /* FIXME: We *really* need to replace this with
+ * libmount's own API for this, we should not hardcode
+ * internal behaviour of libmount here. */
+
+ for (;;) {
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
+ struct inotify_event *e;
+ ssize_t l;
+
+ l = read(fd, buffer, sizeof(buffer));
+ if (l < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ break;
+
+ log_error_errno(errno, "Failed to read utab inotify: %m");
+ break;
+ }
+
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
+ /* Only care about changes to utab,
+ * but we have to monitor the
+ * directory to reliably get
+ * notifications about when utab is
+ * replaced using rename(2) */
+ if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
+ rescan = true;
+ }
+ }
+
+ if (!rescan)
+ return 0;
+ }
r = mount_load_proc_self_mountinfo(m, true);
if (r < 0) {
- log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r));
+ log_error_errno(r, "Failed to reread /proc/self/mountinfo: %m");
/* Reset flags, just in case, for later calls */
LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 4bc288de1d..4c411096a1 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -145,7 +145,7 @@ static int mount_dev(BindMount *m) {
"/dev/tty\0";
char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
- const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devkdbus = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
+ const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
_cleanup_umask_ mode_t u;
int r;
@@ -157,14 +157,14 @@ static int mount_dev(BindMount *m) {
return -errno;
dev = strappenda(temporary_mount, "/dev");
- mkdir(dev, 0755);
+ (void)mkdir(dev, 0755);
if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
r = -errno;
goto fail;
}
devpts = strappenda(temporary_mount, "/dev/pts");
- mkdir(devpts, 0755);
+ (void)mkdir(devpts, 0755);
if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
r = -errno;
goto fail;
@@ -174,7 +174,7 @@ static int mount_dev(BindMount *m) {
symlink("pts/ptmx", devptmx);
devshm = strappenda(temporary_mount, "/dev/shm");
- mkdir(devshm, 01777);
+ (void)mkdir(devshm, 01777);
r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
if (r < 0) {
r = -errno;
@@ -182,15 +182,11 @@ static int mount_dev(BindMount *m) {
}
devmqueue = strappenda(temporary_mount, "/dev/mqueue");
- mkdir(devmqueue, 0755);
+ (void)mkdir(devmqueue, 0755);
mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
- devkdbus = strappenda(temporary_mount, "/dev/kdbus");
- mkdir(devkdbus, 0755);
- mount("/dev/kdbus", devkdbus, NULL, MS_BIND, NULL);
-
devhugepages = strappenda(temporary_mount, "/dev/hugepages");
- mkdir(devhugepages, 0755);
+ (void)mkdir(devhugepages, 0755);
mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
devlog = strappenda(temporary_mount, "/dev/log");
@@ -254,9 +250,6 @@ fail:
if (devshm)
umount(devshm);
- if (devkdbus)
- umount(devkdbus);
-
if (devhugepages)
umount(devhugepages);
@@ -283,13 +276,11 @@ static int mount_kdbus(BindMount *m) {
u = umask(0000);
- if (!mkdtemp(temporary_mount)) {
- log_error("Failed create temp dir: %m");
- return -errno;
- }
+ if (!mkdtemp(temporary_mount))
+ return log_error_errno(errno, "Failed create temp dir: %m");
root = strappenda(temporary_mount, "/kdbus");
- mkdir(root, 0755);
+ (void)mkdir(root, 0755);
if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
r = -errno;
goto fail;
@@ -298,21 +289,21 @@ static int mount_kdbus(BindMount *m) {
/* create a new /dev/null dev node copy so we have some fodder to
* bind-mount the custom endpoint over. */
if (stat("/dev/null", &st) < 0) {
- log_error("Failed to stat /dev/null: %m");
+ log_error_errno(errno, "Failed to stat /dev/null: %m");
r = -errno;
goto fail;
}
busnode = strappenda(root, "/bus");
if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
- log_error("mknod() for %s failed: %m", busnode);
+ log_error_errno(errno, "mknod() for %s failed: %m", busnode);
r = -errno;
goto fail;
}
r = mount(m->path, busnode, "bind", MS_BIND, NULL);
if (r < 0) {
- log_error("bind mount of %s failed: %m", m->path);
+ log_error_errno(errno, "bind mount of %s failed: %m", m->path);
r = -errno;
goto fail;
}
@@ -324,7 +315,7 @@ static int mount_kdbus(BindMount *m) {
}
if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
- log_error("bind mount of %s failed: %m", basepath);
+ log_error_errno(errno, "bind mount of %s failed: %m", basepath);
r = -errno;
goto fail;
}
diff --git a/src/core/path.c b/src/core/path.c
index f54c77f6c3..656ed6941d 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -136,7 +136,7 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
}
if (!exists) {
- log_error("Failed to add watch on any of the components of %s: %m",
+ log_error_errno(errno, "Failed to add watch on any of the components of %s: %m",
s->path);
r = -errno; /* either EACCESS or ENOENT */
goto fail;
@@ -157,10 +157,9 @@ void path_spec_unwatch(PathSpec *s) {
}
int path_spec_fd_event(PathSpec *s, uint32_t revents) {
- _cleanup_free_ uint8_t *buf = NULL;
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
struct inotify_event *e;
- ssize_t k;
- int l;
+ ssize_t l;
int r = 0;
if (revents != EPOLLIN) {
@@ -168,37 +167,18 @@ int path_spec_fd_event(PathSpec *s, uint32_t revents) {
return -EINVAL;
}
- if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
- log_error("FIONREAD failed: %m");
- return -errno;
- }
-
- assert(l > 0);
+ l = read(s->inotify_fd, buffer, sizeof(buffer));
+ if (l < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
- buf = malloc(l);
- if (!buf)
- return log_oom();
-
- k = read(s->inotify_fd, buf, l);
- if (k < 0) {
- log_error("Failed to read inotify event: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to read inotify event: %m");
}
- e = (struct inotify_event*) buf;
-
- while (k > 0) {
- size_t step;
-
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
s->primary_wd == e->wd)
r = 1;
-
- step = sizeof(struct inotify_event) + e->len;
- assert(step <= (size_t) k);
-
- e = (struct inotify_event*) ((uint8_t*) e + step);
- k -= step;
}
return r;
@@ -250,7 +230,7 @@ static void path_spec_mkdir(PathSpec *s, mode_t mode) {
r = mkdir_p_label(s->path, mode);
if (r < 0)
- log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
+ log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
}
static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
@@ -320,7 +300,7 @@ static int path_verify(Path *p) {
return 0;
if (!p->specs) {
- log_error_unit(UNIT(p)->id,
+ log_unit_error(UNIT(p)->id,
"%s lacks path setting. Refusing.", UNIT(p)->id);
return -EINVAL;
}
@@ -562,8 +542,7 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
return;
fail:
- log_warning("%s failed to enter waiting state: %s",
- UNIT(p)->id, strerror(-r));
+ log_warning_errno(r, "%s failed to enter waiting state: %m", UNIT(p)->id);
path_enter_dead(p, PATH_FAILURE_RESOURCES);
}
@@ -724,7 +703,7 @@ static void path_trigger_notify(Unit *u, Unit *other) {
if (p->state == PATH_RUNNING &&
UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_debug_unit(UNIT(p)->id,
+ log_unit_debug(UNIT(p)->id,
"%s got notified about unit deactivation.",
UNIT(p)->id);
diff --git a/src/core/scope.c b/src/core/scope.c
index 0f7c1f97ce..e0da6e4db7 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -133,7 +133,7 @@ static int scope_verify(Scope *s) {
return 0;
if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
- log_error_unit(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
return -EINVAL;
}
@@ -264,7 +264,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
@@ -288,13 +288,7 @@ static int scope_start(Unit *u) {
if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
return -ENOENT;
- r = unit_realize_cgroup(u);
- if (r < 0) {
- log_error("Failed to realize cgroup: %s", strerror(-r));
- return r;
- }
-
- r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, UNIT(s)->pids);
+ r = unit_attach_pids_to_cgroup(u);
if (r < 0)
return r;
@@ -384,15 +378,14 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F
}
static bool scope_check_gc(Unit *u) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
+ assert(u);
/* Never clean up scopes that still have a process around,
* even if the scope is formally dead. */
if (u->cgroup_path) {
+ int r;
+
r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
if (r <= 0)
return true;
@@ -405,7 +398,7 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
Scope *s = SCOPE(u);
assert(u);
- log_debug_unit(u->id, "%s: cgroup is empty", u->id);
+ log_unit_debug(u->id, "%s: cgroup is empty", u->id);
if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
scope_enter_dead(s, SCOPE_SUCCESS);
@@ -437,17 +430,17 @@ static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *user
case SCOPE_STOP_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
}
break;
case SCOPE_STOP_SIGKILL:
- log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
break;
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index a4694b33f3..b45a4513e2 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -112,7 +112,7 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
#endif
va_start(ap, fmt);
- log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
+ log_internalv(LOG_AUTH | LOG_INFO, 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
va_end(ap);
return 0;
@@ -126,10 +126,8 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
static int access_init(void) {
int r = 0;
- if (avc_open(NULL, 0)) {
- log_error("avc_open() failed: %m");
- return -errno;
- }
+ if (avc_open(NULL, 0))
+ return log_error_errno(errno, "avc_open() failed: %m");
selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
@@ -207,7 +205,8 @@ int mac_selinux_generic_access_check(
message,
SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|
SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID|
- SD_BUS_CREDS_SELINUX_CONTEXT,
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUGMENT /* get more bits from /proc */,
&creds);
if (r < 0)
goto finish;
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index bccf0d2913..dd1e8bb9d0 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -40,7 +40,7 @@ int mac_selinux_unit_access_check_strv(char **units, sd_bus_message *message, Ma
#define mac_selinux_unit_access_check(unit, message, permission, error) \
({ \
Unit *_unit = (unit); \
- mac_selinux_generic_access_check((message), _unit->fragment_path ?: _unit->fragment_path, (permission), (error)); \
+ mac_selinux_generic_access_check((message), _unit->source_path ?: _unit->fragment_path, (permission), (error)); \
})
#else
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index 25e22b6c77..fba915d7da 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -113,7 +113,7 @@ int mac_selinux_setup(bool *loaded_policy) {
if (enforce > 0) {
if (!initialized) {
- log_error("Failed to load SELinux policy. Freezing.");
+ log_emergency("Failed to load SELinux policy.");
return -EIO;
}
diff --git a/src/core/service.c b/src/core/service.c
index f27e63eb9a..bfbe959edb 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -137,7 +137,7 @@ static void service_unwatch_pid_file(Service *s) {
if (!s->pid_file_pathspec)
return;
- log_debug_unit(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_debug(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
path_spec_unwatch(s->pid_file_pathspec);
path_spec_done(s->pid_file_pathspec);
free(s->pid_file_pathspec);
@@ -167,7 +167,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid_known = true;
if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
- log_warning_unit(UNIT(s)->id, "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", UNIT(s)->id, pid);
+ log_unit_warning(UNIT(s)->id, "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", UNIT(s)->id, pid);
s->main_pid_alien = true;
} else
s->main_pid_alien = false;
@@ -209,7 +209,7 @@ static void service_start_watchdog(Service *s) {
if (s->watchdog_event_source) {
r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to reset watchdog timer: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to reset watchdog timer: %m", UNIT(s)->id);
return;
}
@@ -222,7 +222,7 @@ static void service_start_watchdog(Service *s) {
s->watchdog_timestamp.monotonic + s->watchdog_usec, 0,
service_dispatch_watchdog, s);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to add watchdog timer: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to add watchdog timer: %m", UNIT(s)->id);
return;
}
@@ -232,7 +232,7 @@ static void service_start_watchdog(Service *s) {
}
if (r < 0)
- log_warning_unit(UNIT(s)->id, "%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to install watchdog timer: %m", UNIT(s)->id);
}
static void service_reset_watchdog(Service *s) {
@@ -316,45 +316,45 @@ static int service_verify(Service *s) {
return 0;
if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
- log_error_unit(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
- log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
- log_error_unit(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_error_unit(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) {
- log_error_unit(UNIT(s)->id, "%s has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) {
- log_error_unit(UNIT(s)->id, "%s has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->type == SERVICE_DBUS && !s->bus_name) {
- log_error_unit(UNIT(s)->id, "%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->bus_name && s->type != SERVICE_DBUS)
- log_warning_unit(UNIT(s)->id, "%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
if (s->exec_context.pam_name && !(s->kill_context.kill_mode == KILL_CONTROL_GROUP || s->kill_context.kill_mode == KILL_MIXED)) {
- log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.", UNIT(s)->id);
return -EINVAL;
}
@@ -546,13 +546,6 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
exec_command_dump_list(s->exec_command[c], f, prefix2);
}
-#ifdef HAVE_SYSV_COMPAT
- if (s->sysv_start_priority >= 0)
- fprintf(f,
- "%sSysVStartPriority: %i\n",
- prefix, s->sysv_start_priority);
-#endif
-
if (s->status_text)
fprintf(f, "%sStatus Text: %s\n",
prefix, s->status_text);
@@ -571,20 +564,20 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = read_one_line_file(s->pid_file, &k);
if (r < 0) {
if (may_warn)
- log_info_unit(UNIT(s)->id, "PID file %s not readable (yet?) after %s.", s->pid_file, service_state_to_string(s->state));
+ log_unit_info(UNIT(s)->id, "PID file %s not readable (yet?) after %s.", s->pid_file, service_state_to_string(s->state));
return r;
}
r = parse_pid(k, &pid);
if (r < 0) {
if (may_warn)
- log_info_unit(UNIT(s)->id, "Failed to read PID from file %s: %s", s->pid_file, strerror(-r));
+ log_unit_info_errno(UNIT(s)->id, r, "Failed to read PID from file %s: %m", s->pid_file);
return r;
}
if (!pid_is_alive(pid)) {
if (may_warn)
- log_info_unit(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file);
+ log_unit_info(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file);
return -ESRCH;
}
@@ -592,12 +585,12 @@ static int service_load_pid_file(Service *s, bool may_warn) {
if (pid == s->main_pid)
return 0;
- log_debug_unit(UNIT(s)->id, "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
+ log_unit_debug(UNIT(s)->id, "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
service_unwatch_main_pid(s);
s->main_pid_known = false;
} else
- log_debug_unit(UNIT(s)->id, "Main PID loaded: "PID_FMT, pid);
+ log_unit_debug(UNIT(s)->id, "Main PID loaded: "PID_FMT, pid);
r = service_set_main_pid(s, pid);
if (r < 0)
@@ -606,7 +599,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
r = unit_watch_pid(UNIT(s), pid);
if (r < 0) {
/* FIXME: we need to do something here */
- log_warning_unit(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
return r;
}
@@ -633,7 +626,7 @@ static int service_search_main_pid(Service *s) {
if (pid <= 0)
return -ENOENT;
- log_debug_unit(UNIT(s)->id, "Main PID guessed: "PID_FMT, pid);
+ log_unit_debug(UNIT(s)->id, "Main PID guessed: "PID_FMT, pid);
r = service_set_main_pid(s, pid);
if (r < 0)
return r;
@@ -641,7 +634,7 @@ static int service_search_main_pid(Service *s) {
r = unit_watch_pid(UNIT(s), pid);
if (r < 0) {
/* FIXME: we need to do something here */
- log_warning_unit(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
return r;
}
@@ -710,7 +703,7 @@ static void service_set_state(Service *s, ServiceState state) {
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
- unit_destroy_cgroup(UNIT(s));
+ unit_destroy_cgroup_if_empty(UNIT(s));
/* For remain_after_exit services, let's see if we can "release" the
* hold on the console, since unit_notify() only does that in case of
@@ -733,7 +726,7 @@ static void service_set_state(Service *s, ServiceState state) {
}
if (old_state != state)
- log_debug_unit(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state));
+ log_unit_debug(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state));
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
s->reload_result = SERVICE_SUCCESS;
@@ -1000,6 +993,7 @@ static int service_spawn(
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = path;
+ exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.unit_id = UNIT(s)->id;
exec_params.watchdog_usec = s->watchdog_usec;
@@ -1087,7 +1081,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
if (s->result != SERVICE_SUCCESS) {
- log_warning_unit(UNIT(s)->id, "%s failed.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s failed.", UNIT(s)->id);
failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
}
@@ -1129,7 +1123,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run install restart timer: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run install restart timer: %m", UNIT(s)->id);
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
@@ -1166,7 +1160,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-post' task: %m", UNIT(s)->id);
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
@@ -1212,7 +1206,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL ||
state == SERVICE_STOP_SIGABRT)
@@ -1267,7 +1261,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop' task: %m", UNIT(s)->id);
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
@@ -1329,7 +1323,7 @@ static void service_enter_start_post(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
@@ -1422,7 +1416,7 @@ static void service_enter_start(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start' task: %m", UNIT(s)->id);
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
}
@@ -1460,7 +1454,7 @@ static void service_enter_start_pre(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
}
@@ -1472,7 +1466,7 @@ static void service_enter_restart(Service *s) {
if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
/* Don't restart things if we are going down anyway */
- log_info_unit(UNIT(s)->id, "Stop job pending for unit, delaying automatic restart.");
+ log_unit_info(UNIT(s)->id, "Stop job pending for unit, delaying automatic restart.");
r = service_arm_timer(s, s->restart_usec);
if (r < 0)
@@ -1493,11 +1487,11 @@ static void service_enter_restart(Service *s) {
* it will be canceled as part of the service_stop() call that
* is executed as part of JOB_RESTART. */
- log_debug_unit(UNIT(s)->id, "%s scheduled restart job.", UNIT(s)->id);
+ log_unit_debug(UNIT(s)->id, "%s scheduled restart job.", UNIT(s)->id);
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to schedule restart job: %s", UNIT(s)->id, bus_error_message(&error, -r));
+ log_unit_warning(UNIT(s)->id, "%s failed to schedule restart job: %s", UNIT(s)->id, bus_error_message(&error, -r));
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
}
@@ -1540,7 +1534,7 @@ static void service_enter_reload(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'reload' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'reload' task: %m", UNIT(s)->id);
s->reload_result = SERVICE_FAILURE_RESOURCES;
service_enter_running(s, SERVICE_SUCCESS);
}
@@ -1573,7 +1567,7 @@ static void service_run_next_control(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run next control task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next control task: %m", UNIT(s)->id);
if (s->state == SERVICE_START_PRE)
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
@@ -1617,7 +1611,7 @@ static void service_run_next_main(Service *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run next main task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next main task: %m", UNIT(s)->id);
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
@@ -1627,7 +1621,7 @@ static int service_start_limit_test(Service *s) {
if (ratelimit_test(&s->start_limit))
return 0;
- log_warning_unit(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id);
return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg);
}
@@ -1835,7 +1829,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
state = service_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -1843,7 +1837,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
f = service_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != SERVICE_SUCCESS)
s->result = f;
@@ -1852,7 +1846,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
f = service_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse reload result value %s", value);
+ log_unit_debug(u->id, "Failed to parse reload result value %s", value);
else if (f != SERVICE_SUCCESS)
s->reload_result = f;
@@ -1860,14 +1854,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
else
s->control_pid = pid;
} else if (streq(key, "main-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse main-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse main-pid value %s", value);
else {
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
@@ -1877,7 +1871,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
b = parse_boolean(value);
if (b < 0)
- log_debug_unit(u->id, "Failed to parse main-pid-known value %s", value);
+ log_unit_debug(u->id, "Failed to parse main-pid-known value %s", value);
else
s->main_pid_known = b;
} else if (streq(key, "status-text")) {
@@ -1896,7 +1890,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
id = service_exec_command_from_string(value);
if (id < 0)
- log_debug_unit(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command[id];
@@ -1905,7 +1899,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse socket-fd value %s", value);
+ log_unit_debug(u->id, "Failed to parse socket-fd value %s", value);
else {
asynchronous_close(s->socket_fd);
s->socket_fd = fdset_remove(fds, fd);
@@ -1914,7 +1908,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
int fd;
if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse endpoint-fd value %s", value);
+ log_unit_debug(u->id, "Failed to parse endpoint-fd value %s", value);
else {
safe_close(s->bus_endpoint_fd);
s->bus_endpoint_fd = fdset_remove(fds, fd);
@@ -1923,21 +1917,21 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse main-exec-status-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse main-exec-status-pid value %s", value);
else
s->main_exec_status.pid = pid;
} else if (streq(key, "main-exec-status-code")) {
int i;
if (safe_atoi(value, &i) < 0)
- log_debug_unit(u->id, "Failed to parse main-exec-status-code value %s", value);
+ log_unit_debug(u->id, "Failed to parse main-exec-status-code value %s", value);
else
s->main_exec_status.code = i;
} else if (streq(key, "main-exec-status-status")) {
int i;
if (safe_atoi(value, &i) < 0)
- log_debug_unit(u->id, "Failed to parse main-exec-status-status value %s", value);
+ log_unit_debug(u->id, "Failed to parse main-exec-status-status value %s", value);
else
s->main_exec_status.status = i;
} else if (streq(key, "main-exec-status-start"))
@@ -1951,11 +1945,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
b = parse_boolean(value);
if (b < 0)
- log_debug_unit(u->id, "Failed to parse forbid-restart value %s", value);
+ log_unit_debug(u->id, "Failed to parse forbid-restart value %s", value);
else
s->forbid_restart = b;
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -2018,19 +2012,19 @@ static int service_retry_pid_file(Service *s) {
static int service_watch_pid_file(Service *s) {
int r;
- log_debug_unit(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_debug(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io);
if (r < 0)
goto fail;
/* the pidfile might have appeared just before we set the watch */
- log_debug_unit(UNIT(s)->id, "Trying to read %s's PID file %s in case it changed", UNIT(s)->id, s->pid_file_pathspec->path);
+ log_unit_debug(UNIT(s)->id, "Trying to read %s's PID file %s in case it changed", UNIT(s)->id, s->pid_file_pathspec->path);
service_retry_pid_file(s);
return 0;
fail:
- log_error_unit(UNIT(s)->id, "Failed to set a watch for %s's PID file %s: %s", UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r));
+ log_unit_error_errno(UNIT(s)->id, r, "Failed to set a watch for %s's PID file %s: %m", UNIT(s)->id, s->pid_file_pathspec->path);
service_unwatch_pid_file(s);
return r;
}
@@ -2078,7 +2072,7 @@ static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events,
assert(s->pid_file_pathspec);
assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
- log_debug_unit(UNIT(s)->id, "inotify event for %s", UNIT(s)->id);
+ log_unit_debug(UNIT(s)->id, "inotify event for %s", UNIT(s)->id);
if (path_spec_fd_event(p, events) < 0)
goto fail;
@@ -2102,7 +2096,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
assert(u);
- log_debug_unit(u->id, "%s: cgroup is empty", u->id);
+ log_unit_debug(u->id, "%s: cgroup is empty", u->id);
switch (s->state) {
@@ -2117,7 +2111,7 @@ static void service_notify_cgroup_empty_event(Unit *u) {
/* If we were hoping for the daemon to write its PID file,
* we can give up now. */
if (s->pid_file_pathspec) {
- log_warning_unit(u->id, "%s never wrote its PID file. Failing.", UNIT(s)->id);
+ log_unit_warning(u->id, "%s never wrote its PID file. Failing.", UNIT(s)->id);
service_unwatch_pid_file(s);
if (s->state == SERVICE_START)
@@ -2204,16 +2198,16 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SERVICE_SUCCESS;
}
- log_struct_unit(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- u->id,
- "MESSAGE=%s: main process exited, code=%s, status=%i/%s",
- u->id, sigchld_code_to_string(code), status,
- strna(code == CLD_EXITED
- ? exit_status_to_string(status, EXIT_STATUS_FULL)
- : signal_to_string(status)),
- "EXIT_CODE=%s", sigchld_code_to_string(code),
- "EXIT_STATUS=%i", status,
- NULL);
+ log_unit_struct(u->id,
+ f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
+ LOG_MESSAGE("%s: main process exited, code=%s, status=%i/%s",
+ u->id, sigchld_code_to_string(code), status,
+ strna(code == CLD_EXITED
+ ? exit_status_to_string(status, EXIT_STATUS_FULL)
+ : signal_to_string(status))),
+ "EXIT_CODE=%s", sigchld_code_to_string(code),
+ "EXIT_STATUS=%i", status,
+ NULL);
if (f != SERVICE_SUCCESS)
s->result = f;
@@ -2225,7 +2219,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* There is another command to *
* execute, so let's do that. */
- log_debug_unit(u->id, "%s running next main command for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u->id, "%s running next main command for state %s", u->id, service_state_to_string(s->state));
service_run_next_main(s);
} else {
@@ -2292,7 +2286,8 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SERVICE_SUCCESS;
}
- log_full_unit(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, u->id,
+ log_unit_full(u->id,
+ f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
"%s: control process exited, code=%s status=%i",
u->id, sigchld_code_to_string(code), status);
@@ -2311,7 +2306,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* There is another command to *
* execute, so let's do that. */
- log_debug_unit(u->id, "%s running next control command for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u->id, "%s running next control command for state %s", u->id, service_state_to_string(s->state));
service_run_next_control(s);
} else {
@@ -2321,7 +2316,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command = NULL;
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- log_debug_unit(u->id, "%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state));
+ log_unit_debug(u->id, "%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state));
switch (s->state) {
@@ -2450,38 +2445,38 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
case SERVICE_START_PRE:
case SERVICE_START:
- log_warning_unit(UNIT(s)->id, "%s %s operation timed out. Terminating.", UNIT(s)->id, s->state == SERVICE_START ? "start" : "start-pre");
+ log_unit_warning(UNIT(s)->id, "%s %s operation timed out. Terminating.", UNIT(s)->id, s->state == SERVICE_START ? "start" : "start-pre");
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_START_POST:
- log_warning_unit(UNIT(s)->id, "%s start-post operation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s start-post operation timed out. Stopping.", UNIT(s)->id);
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_RELOAD:
- log_warning_unit(UNIT(s)->id, "%s reload operation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s reload operation timed out. Stopping.", UNIT(s)->id);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_STOP:
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_STOP_SIGABRT:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s stop-sigabrt timed out. Terminating.", UNIT(s)->id);
service_enter_signal(s, SERVICE_STOP_SIGTERM, s->result);
break;
case SERVICE_STOP_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id);
service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id);
service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
}
@@ -2492,33 +2487,33 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
* Must be something we cannot kill, so let's just be
* weirded out and continue */
- log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_STOP_POST:
- log_warning_unit(UNIT(s)->id, "%s stop-post timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stop-post timed out. Terminating.", UNIT(s)->id);
service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_FINAL_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id);
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", UNIT(s)->id);
service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
}
break;
case SERVICE_FINAL_SIGKILL:
- log_warning_unit(UNIT(s)->id, "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id);
service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
break;
case SERVICE_AUTO_RESTART:
- log_info_unit(UNIT(s)->id,
+ log_unit_info(UNIT(s)->id,
s->restart_usec > 0 ?
"%s holdoff time over, scheduling restart." :
"%s has no holdoff time, scheduling restart.",
@@ -2540,7 +2535,7 @@ static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void
assert(s);
assert(source == s->watchdog_event_source);
- log_error_unit(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id,
+ log_unit_error(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id,
format_timespan(t, sizeof(t), s->watchdog_usec, 1));
service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG);
@@ -2557,19 +2552,19 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
assert(u);
cc = strv_join(tags, ", ");
- log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT" (%s)",
+ log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT" (%s)",
u->id, pid, isempty(cc) ? "n/a" : cc);
if (s->notify_access == NOTIFY_NONE) {
- log_warning_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid);
+ log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid);
return;
}
if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
if (s->main_pid != 0)
- log_warning_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, u->id, pid, s->main_pid);
+ log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, u->id, pid, s->main_pid);
else
- log_debug_unit(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", u->id, pid);
+ log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", u->id, pid);
return;
}
@@ -2577,9 +2572,9 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
e = strv_find_startswith(tags, "MAINPID=");
if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
if (parse_pid(e, &pid) < 0)
- log_warning_unit(u->id, "Failed to parse MAINPID= field in notification message: %s", e);
+ log_unit_warning(u->id, "Failed to parse MAINPID= field in notification message: %s", e);
else {
- log_debug_unit(u->id, "%s: got MAINPID=%s", u->id, e);
+ log_unit_debug(u->id, "%s: got MAINPID=%s", u->id, e);
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
@@ -2590,7 +2585,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
/* Interpret RELOADING= */
if (strv_find(tags, "RELOADING=1")) {
- log_debug_unit(u->id, "%s: got RELOADING=1", u->id);
+ log_unit_debug(u->id, "%s: got RELOADING=1", u->id);
s->notify_state = NOTIFY_RELOADING;
if (s->state == SERVICE_RUNNING)
@@ -2602,7 +2597,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
/* Interpret READY= */
if (strv_find(tags, "READY=1")) {
- log_debug_unit(u->id, "%s: got READY=1", u->id);
+ log_unit_debug(u->id, "%s: got READY=1", u->id);
s->notify_state = NOTIFY_READY;
/* Type=notify services inform us about completed
@@ -2621,7 +2616,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
/* Interpret STOPPING= */
if (strv_find(tags, "STOPPING=1")) {
- log_debug_unit(u->id, "%s: got STOPPING=1", u->id);
+ log_unit_debug(u->id, "%s: got STOPPING=1", u->id);
s->notify_state = NOTIFY_STOPPING;
if (s->state == SERVICE_RUNNING)
@@ -2637,9 +2632,9 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
if (!isempty(e)) {
if (!utf8_is_valid(e))
- log_warning_unit(u->id, "Status message in notification is not UTF-8 clean.");
+ log_unit_warning(u->id, "Status message in notification is not UTF-8 clean.");
else {
- log_debug_unit(u->id, "%s: got STATUS=%s", u->id, e);
+ log_unit_debug(u->id, "%s: got STATUS=%s", u->id, e);
t = strdup(e);
if (!t)
@@ -2663,9 +2658,9 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
int status_errno;
if (safe_atoi(e, &status_errno) < 0 || status_errno < 0)
- log_warning_unit(u->id, "Failed to parse ERRNO= field in notification message: %s", e);
+ log_unit_warning(u->id, "Failed to parse ERRNO= field in notification message: %s", e);
else {
- log_debug_unit(u->id, "%s: got ERRNO=%s", u->id, e);
+ log_unit_debug(u->id, "%s: got ERRNO=%s", u->id, e);
if (s->status_errno != status_errno) {
s->status_errno = status_errno;
@@ -2676,7 +2671,7 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
/* Interpret WATCHDOG= */
if (strv_find(tags, "WATCHDOG=1")) {
- log_debug_unit(u->id, "%s: got WATCHDOG=1", u->id);
+ log_unit_debug(u->id, "%s: got WATCHDOG=1", u->id);
service_reset_watchdog(s);
}
@@ -2715,11 +2710,11 @@ static void service_bus_name_owner_change(
assert(old_owner || new_owner);
if (old_owner && new_owner)
- log_debug_unit(u->id, "%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner);
+ log_unit_debug(u->id, "%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner);
else if (old_owner)
- log_debug_unit(u->id, "%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
+ log_unit_debug(u->id, "%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
else
- log_debug_unit(u->id, "%s's D-Bus name %s now registered by %s", u->id, name, new_owner);
+ log_unit_debug(u->id, "%s's D-Bus name %s now registered by %s", u->id, name, new_owner);
s->bus_name_good = !!new_owner;
@@ -2748,7 +2743,7 @@ static void service_bus_name_owner_change(
if (r >= 0)
r = sd_bus_creds_get_pid(creds, &pid);
if (r >= 0) {
- log_debug_unit(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
+ log_unit_debug(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
service_set_main_pid(s, pid);
unit_watch_pid(UNIT(s), pid);
diff --git a/src/core/service.h b/src/core/service.h
index 54fbe46fa4..f6a78c403b 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -180,9 +180,6 @@ struct Service {
bool bus_name_good:1;
bool forbid_restart:1;
bool start_timeout_defined:1;
-#ifdef HAVE_SYSV_COMPAT
- int sysv_start_priority;
-#endif
char *bus_name;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 20cf526ba2..def20f5022 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -75,7 +75,9 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+ /* "-" prevents getopt from permuting argv[] and moving the verb away
+ * from argv[1]. Our interface to initrd promises it'll be there. */
+ while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
switch (c) {
case ARG_LOG_LEVEL:
@@ -113,6 +115,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case '\001':
+ if (!arg_verb)
+ arg_verb = optarg;
+ else
+ log_error("Excess arguments, ignoring");
+ break;
+
case '?':
return -EINVAL;
@@ -120,28 +129,20 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option code.");
}
- if (optind >= argc) {
+ if (!arg_verb) {
log_error("Verb argument missing.");
return -EINVAL;
}
- arg_verb = argv[optind];
-
- if (optind + 1 < argc)
- log_error("Excess arguments, ignoring");
return 0;
}
static int switch_root_initramfs(void) {
- if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
- return -errno;
- }
+ if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
- if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
- log_error("Failed to make /run/initramfs private mount: %m");
- return -errno;
- }
+ if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
+ return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
/* switch_root with MS_BIND, because there might still be processes lurking around, which have open file desriptors.
* /run/initramfs/shutdown will take care of these.
@@ -165,7 +166,7 @@ int main(int argc, char *argv[]) {
goto error;
/* journald will die if not gone yet. The log target defaults
- * to console, but may have been changed by commandline options. */
+ * to console, but may have been changed by command line options. */
log_close_console(); /* force reopen of /dev/console */
log_open();
@@ -235,7 +236,7 @@ int main(int argc, char *argv[]) {
} else if (r > 0)
log_info("Not all file systems unmounted, %d left.", r);
else
- log_error("Failed to unmount file systems: %s", strerror(-r));
+ log_error_errno(r, "Failed to unmount file systems: %m");
}
if (need_swapoff) {
@@ -247,7 +248,7 @@ int main(int argc, char *argv[]) {
} else if (r > 0)
log_info("Not all swaps deactivated, %d left.", r);
else
- log_error("Failed to deactivate swaps: %s", strerror(-r));
+ log_error_errno(r, "Failed to deactivate swaps: %m");
}
if (need_loop_detach) {
@@ -259,7 +260,7 @@ int main(int argc, char *argv[]) {
} else if (r > 0)
log_info("Not all loop devices detached, %d left.", r);
else
- log_error("Failed to detach loop devices: %s", strerror(-r));
+ log_error_errno(r, "Failed to detach loop devices: %m");
}
if (need_dm_detach) {
@@ -271,7 +272,7 @@ int main(int argc, char *argv[]) {
} else if (r > 0)
log_info("Not all DM devices detached, %d left.", r);
else
- log_error("Failed to detach DM devices: %s", strerror(-r));
+ log_error_errno(r, "Failed to detach DM devices: %m");
}
if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
@@ -322,9 +323,9 @@ int main(int argc, char *argv[]) {
"Returning to initrd...");
execv("/shutdown", argv);
- log_error("Failed to execute shutdown binary: %m");
+ log_error_errno(errno, "Failed to execute shutdown binary: %m");
} else
- log_error("Failed to switch root to \"/run/initramfs\": %s", strerror(-r));
+ log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
}
@@ -354,7 +355,7 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0)
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
else if (pid == 0) {
const char * const args[] = {
@@ -366,7 +367,7 @@ int main(int argc, char *argv[]) {
execv(args[0], (char * const *) args);
_exit(EXIT_FAILURE);
} else
- wait_for_terminate_and_warn("kexec", pid);
+ wait_for_terminate_and_warn("kexec", pid, true);
}
cmd = RB_AUTOBOOT;
@@ -407,11 +408,11 @@ int main(int argc, char *argv[]) {
exit(0);
}
- log_error("Failed to invoke reboot(): %m");
+ log_error_errno(errno, "Failed to invoke reboot(): %m");
r = -errno;
error:
- log_error("Critical error while doing system shutdown: %s", strerror(-r));
+ log_emergency_errno(r, "Critical error while doing system shutdown: %m");
freeze();
}
diff --git a/src/core/slice.c b/src/core/slice.c
index 057feefa0f..a31e629370 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -113,7 +113,7 @@ static int slice_verify(Slice *s) {
a = (char*) SPECIAL_ROOT_SLICE;
if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
- log_error_unit(UNIT(s)->id,
+ log_unit_error(UNIT(s)->id,
"%s located outside its parent slice. Refusing.", UNIT(s)->id);
return -EINVAL;
}
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index d0fd1809f9..59f6832bc2 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -56,7 +56,7 @@ static int write_rules(const char* dstpath, const char* srcdir) {
dst = fopen(dstpath, "we");
if (!dst) {
if (errno != ENOENT)
- log_warning("Failed to open %s: %m", dstpath);
+ log_warning_errno(errno, "Failed to open %s: %m", dstpath);
return -errno; /* negative error */
}
@@ -64,7 +64,7 @@ static int write_rules(const char* dstpath, const char* srcdir) {
dir = opendir(srcdir);
if (!dir) {
if (errno != ENOENT)
- log_warning("Failed to opendir %s: %m", srcdir);
+ log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
return errno; /* positive on purpose */
}
@@ -79,7 +79,7 @@ static int write_rules(const char* dstpath, const char* srcdir) {
if (fd < 0) {
if (r == 0)
r = -errno;
- log_warning("Failed to open %s: %m", entry->d_name);
+ log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
continue;
}
@@ -88,13 +88,13 @@ static int write_rules(const char* dstpath, const char* srcdir) {
if (r == 0)
r = -errno;
safe_close(fd);
- log_error("Failed to open %s: %m", entry->d_name);
+ log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
continue;
}
/* load2 write rules in the kernel require a line buffered stream */
FOREACH_LINE(buf, policy,
- log_error("Failed to read line from %s: %m",
+ log_error_errno(errno, "Failed to read line from %s: %m",
entry->d_name)) {
if (!fputs(buf, dst)) {
if (r == 0)
@@ -105,7 +105,7 @@ static int write_rules(const char* dstpath, const char* srcdir) {
if (fflush(dst)) {
if (r == 0)
r = -errno;
- log_error("Failed to flush writes to %s: %m", dstpath);
+ log_error_errno(errno, "Failed to flush writes to %s: %m", dstpath);
break;
}
}
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
index 5eed615a15..068a077f15 100644
--- a/src/core/snapshot.c
+++ b/src/core/snapshot.c
@@ -25,7 +25,7 @@
#include "snapshot.h"
#include "unit-name.h"
#include "dbus-snapshot.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
[SNAPSHOT_DEAD] = UNIT_INACTIVE,
@@ -51,7 +51,7 @@ static void snapshot_set_state(Snapshot *s, SnapshotState state) {
s->state = state;
if (state != old_state)
- log_debug_unit(UNIT(s)->id,
+ log_unit_debug(UNIT(s)->id,
"%s changed %s -> %s",
UNIT(s)->id,
snapshot_state_to_string(old_state),
@@ -155,7 +155,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
state = snapshot_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
s->deserialized_state = state;
@@ -163,7 +163,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
r = parse_boolean(value);
if (r < 0)
- log_debug_unit(u->id, "Failed to parse cleanup value %s", value);
+ log_unit_debug(u->id, "Failed to parse cleanup value %s", value);
else
s->cleanup = r;
@@ -173,7 +173,7 @@ static int snapshot_deserialize_item(Unit *u, const char *key, const char *value
if (r < 0)
return r;
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -208,7 +208,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e,
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
if (manager_get_unit(m, name))
- sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
+ return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
} else {
@@ -258,7 +258,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e,
SNAPSHOT(u)->cleanup = cleanup;
*_s = SNAPSHOT(u);
- log_info_unit(u->id, "Created snapshot %s.", u->id);
+ log_unit_info(u->id, "Created snapshot %s.", u->id);
return 0;
@@ -272,7 +272,7 @@ fail:
void snapshot_remove(Snapshot *s) {
assert(s);
- log_info_unit(UNIT(s)->id, "Removing snapshot %s.", UNIT(s)->id);
+ log_unit_info(UNIT(s)->id, "Removing snapshot %s.", UNIT(s)->id);
unit_add_to_cleanup_queue(UNIT(s));
}
diff --git a/src/core/socket.c b/src/core/socket.c
index 6ba8338d8b..8fa55e0b03 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -391,33 +391,33 @@ static int socket_verify(Socket *s) {
return 0;
if (!s->ports) {
- log_error_unit(UNIT(s)->id, "%s lacks Listen setting. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s lacks Listen setting. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->accept && have_non_accept_socket(s)) {
- log_error_unit(UNIT(s)->id, "%s configured for accepting sockets, but sockets are non-accepting. Refusing.",
+ log_unit_error(UNIT(s)->id, "%s configured for accepting sockets, but sockets are non-accepting. Refusing.",
UNIT(s)->id);
return -EINVAL;
}
if (s->accept && s->max_connections <= 0) {
- log_error_unit(UNIT(s)->id, "%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->accept && UNIT_DEREF(s->service)) {
- log_error_unit(UNIT(s)->id, "Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
return -EINVAL;
}
if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
- log_error_unit(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id);
return -EINVAL;
}
@@ -815,60 +815,60 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (s->keep_alive) {
int b = s->keep_alive;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_KEEPALIVE failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_KEEPALIVE failed: %m");
}
if (s->keep_alive_time) {
int value = s->keep_alive_time / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_KEEPIDLE failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_KEEPIDLE failed: %m");
}
if (s->keep_alive_interval) {
int value = s->keep_alive_interval / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_KEEPINTVL failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_KEEPINTVL failed: %m");
}
if (s->keep_alive_cnt) {
int value = s->keep_alive_cnt;
if (setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_KEEPCNT failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_KEEPCNT failed: %m");
}
if (s->defer_accept) {
int value = s->defer_accept / USEC_PER_SEC;
if (setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_DEFER_ACCEPT failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_DEFER_ACCEPT failed: %m");
}
if (s->no_delay) {
int b = s->no_delay;
if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_NODELAY failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_NODELAY failed: %m");
}
if (s->broadcast) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_BROADCAST failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_BROADCAST failed: %m");
}
if (s->pass_cred) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_PASSCRED failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_PASSCRED failed: %m");
}
if (s->pass_sec) {
int one = 1;
if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_PASSSEC failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_PASSSEC failed: %m");
}
if (s->priority >= 0)
if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_PRIORITY failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_PRIORITY failed: %m");
if (s->receive_buffer > 0) {
int value = (int) s->receive_buffer;
@@ -877,23 +877,23 @@ static void socket_apply_socket_options(Socket *s, int fd) {
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_RCVBUF failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_RCVBUF failed: %m");
}
if (s->send_buffer > 0) {
int value = (int) s->send_buffer;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_SNDBUF failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_SNDBUF failed: %m");
}
if (s->mark >= 0)
if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_MARK failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_MARK failed: %m");
if (s->ip_tos >= 0)
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
- log_warning_unit(UNIT(s)->id, "IP_TOS failed: %m");
+ log_unit_warning(UNIT(s)->id, "IP_TOS failed: %m");
if (s->ip_ttl >= 0) {
int x;
@@ -908,30 +908,30 @@ static void socket_apply_socket_options(Socket *s, int fd) {
}
if (r < 0 && x < 0)
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"IP_TTL/IPV6_UNICAST_HOPS failed: %m");
}
if (s->tcp_congestion)
if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
- log_warning_unit(UNIT(s)->id, "TCP_CONGESTION failed: %m");
+ log_unit_warning(UNIT(s)->id, "TCP_CONGESTION failed: %m");
if (s->reuse_port) {
int b = s->reuse_port;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0)
- log_warning_unit(UNIT(s)->id, "SO_REUSEPORT failed: %m");
+ log_unit_warning(UNIT(s)->id, "SO_REUSEPORT failed: %m");
}
if (s->smack_ip_in) {
r = mac_smack_apply_ip_in_fd(fd, s->smack_ip_in);
if (r < 0)
- log_error_unit(UNIT(s)->id, "mac_smack_apply_ip_in_fd: %s", strerror(-r));
+ log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_in_fd: %m");
}
if (s->smack_ip_out) {
r = mac_smack_apply_ip_out_fd(fd, s->smack_ip_out);
if (r < 0)
- log_error_unit(UNIT(s)->id, "mac_smack_apply_ip_out_fd: %s", strerror(-r));
+ log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_out_fd: %m");
}
}
@@ -943,12 +943,12 @@ static void socket_apply_fifo_options(Socket *s, int fd) {
if (s->pipe_size > 0)
if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_warning_unit(UNIT(s)->id, "F_SETPIPE_SZ: %m");
+ log_unit_warning(UNIT(s)->id, "F_SETPIPE_SZ: %m");
if (s->smack) {
r = mac_smack_apply_fd(fd, s->smack);
if (r < 0)
- log_error_unit(UNIT(s)->id, "mac_smack_apply_fd: %s", strerror(-r));
+ log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_fd: %m");
}
}
@@ -1249,7 +1249,7 @@ static void socket_unwatch_fds(Socket *s) {
r = sd_event_source_set_enabled(p->event_source, SD_EVENT_OFF);
if (r < 0)
- log_debug_unit(UNIT(s)->id, "Failed to disable event source.");
+ log_unit_debug(UNIT(s)->id, "Failed to disable event source.");
}
}
@@ -1269,7 +1269,7 @@ static int socket_watch_fds(Socket *s) {
r = sd_event_add_io(UNIT(s)->manager->event, &p->event_source, p->fd, EPOLLIN, socket_dispatch_io, p);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "Failed to watch listening fds: %s", strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "Failed to watch listening fds: %m");
goto fail;
}
}
@@ -1319,7 +1319,7 @@ static void socket_set_state(Socket *s, SocketState state) {
socket_close_fds(s);
if (state != old_state)
- log_debug_unit(UNIT(s)->id, "%s changed %s -> %s",
+ log_unit_debug(UNIT(s)->id, "%s changed %s -> %s",
UNIT(s)->id, socket_state_to_string(old_state), socket_state_to_string(state));
unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
@@ -1414,6 +1414,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(s)->cgroup_path;
+ exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.unit_id = UNIT(s)->id;
@@ -1455,8 +1456,8 @@ static int socket_chown(Socket *s, pid_t *_pid) {
if (pid == 0) {
SocketPort *p;
- uid_t uid = (uid_t) -1;
- gid_t gid = (gid_t) -1;
+ uid_t uid = UID_INVALID;
+ gid_t gid = GID_INVALID;
int ret;
default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
@@ -1505,7 +1506,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
fail_child:
log_open();
- log_error("Failed to chown socket at step %s: %s", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD), strerror(-r));
+ log_error_errno(r, "Failed to chown socket at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD));
_exit(ret);
}
@@ -1561,7 +1562,7 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s failed to run 'stop-post' task: %s",
UNIT(s)->id, strerror(-r));
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
@@ -1604,7 +1605,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
@@ -1635,7 +1636,7 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run 'stop-pre' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-pre' task: %m", UNIT(s)->id);
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
}
@@ -1645,7 +1646,7 @@ static void socket_enter_listening(Socket *s) {
r = socket_watch_fds(s);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
goto fail;
}
@@ -1667,7 +1668,7 @@ static void socket_enter_start_post(Socket *s) {
if (s->control_command) {
r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
goto fail;
}
@@ -1688,7 +1689,7 @@ static void socket_enter_start_chown(Socket *s) {
r = socket_open_fds(s);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to listen on sockets: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
goto fail;
}
@@ -1700,7 +1701,7 @@ static void socket_enter_start_chown(Socket *s) {
r = socket_chown(s, &s->control_pid);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to fork 'start-chown' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to fork 'start-chown' task: %m", UNIT(s)->id);
goto fail;
}
@@ -1725,7 +1726,7 @@ static void socket_enter_start_pre(Socket *s) {
if (s->control_command) {
r = socket_spawn(s, s->control_command, &s->control_pid);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
goto fail;
}
@@ -1749,7 +1750,7 @@ static void socket_enter_running(Socket *s, int cfd) {
* shut down anyway */
if (unit_stop_pending(UNIT(s))) {
- log_debug_unit(UNIT(s)->id, "Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
+ log_unit_debug(UNIT(s)->id, "Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
if (cfd >= 0)
safe_close(cfd);
@@ -1759,14 +1760,14 @@ static void socket_enter_running(Socket *s, int cfd) {
r = socket_open_fds(s);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to listen on sockets: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
return;
}
r = socket_watch_fds(s);
if (r < 0) {
- log_warning_unit(UNIT(s)->id, "%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
}
}
@@ -1789,7 +1790,7 @@ static void socket_enter_running(Socket *s, int cfd) {
if (!pending) {
if (!UNIT_ISSET(s->service)) {
- log_error_unit(UNIT(s)->id, "%s: service to activate vanished, refusing activation.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s: service to activate vanished, refusing activation.", UNIT(s)->id);
r = -ENOENT;
goto fail;
}
@@ -1805,7 +1806,7 @@ static void socket_enter_running(Socket *s, int cfd) {
Service *service;
if (s->n_connections >= s->max_connections) {
- log_warning_unit(UNIT(s)->id, "%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections);
+ log_unit_warning(UNIT(s)->id, "%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections);
safe_close(cfd);
return;
}
@@ -1867,7 +1868,7 @@ static void socket_enter_running(Socket *s, int cfd) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
+ log_unit_warning(UNIT(s)->id, "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
UNIT(s)->id, cfd >= 0 ? "template" : "non-template",
bus_error_message(&error, r));
@@ -1893,7 +1894,7 @@ static void socket_run_next(Socket *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id, "%s failed to run next task: %s", UNIT(s)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next task: %m", UNIT(s)->id);
if (s->state == SOCKET_START_POST)
socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
@@ -1933,7 +1934,7 @@ static int socket_start(Unit *u) {
service = SERVICE(UNIT_DEREF(s->service));
if (UNIT(service)->load_state != UNIT_LOADED) {
- log_error_unit(u->id, "Socket service %s not loaded, refusing.", UNIT(service)->id);
+ log_unit_error(u->id, "Socket service %s not loaded, refusing.", UNIT(service)->id);
return -ENOENT;
}
@@ -1942,7 +1943,7 @@ static int socket_start(Unit *u) {
if (service->state != SERVICE_DEAD &&
service->state != SERVICE_FAILED &&
service->state != SERVICE_AUTO_RESTART) {
- log_error_unit(u->id, "Socket service %s already active, refusing.", UNIT(service)->id);
+ log_unit_error(u->id, "Socket service %s already active, refusing.", UNIT(service)->id);
return -EBUSY;
}
}
@@ -2052,7 +2053,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
state = socket_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -2060,7 +2061,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
f = socket_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != SOCKET_SUCCESS)
s->result = f;
@@ -2068,14 +2069,14 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
unsigned k;
if (safe_atou(value, &k) < 0)
- log_debug_unit(u->id, "Failed to parse n-accepted value %s", value);
+ log_unit_debug(u->id, "Failed to parse n-accepted value %s", value);
else
s->n_accepted += k;
} else if (streq(key, "control-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
else
s->control_pid = pid;
} else if (streq(key, "control-command")) {
@@ -2083,7 +2084,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
id = socket_exec_command_from_string(value);
if (id < 0)
- log_debug_unit(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command[id];
@@ -2093,7 +2094,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse fifo value %s", value);
+ log_unit_debug(u->id, "Failed to parse fifo value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2112,7 +2113,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse special value %s", value);
+ log_unit_debug(u->id, "Failed to parse special value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2131,7 +2132,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse mqueue value %s", value);
+ log_unit_debug(u->id, "Failed to parse mqueue value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2150,7 +2151,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse socket value %s", value);
+ log_unit_debug(u->id, "Failed to parse socket value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2168,7 +2169,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
SocketPort *p;
if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_debug_unit(u->id, "Failed to parse socket value %s", value);
+ log_unit_debug(u->id, "Failed to parse socket value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
@@ -2181,7 +2182,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
}
}
} else
- log_debug_unit(UNIT(s)->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(UNIT(s)->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -2285,15 +2286,15 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (p->socket->state != SOCKET_LISTENING)
return 0;
- log_debug_unit(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id);
+ log_unit_debug(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id);
if (revents != EPOLLIN) {
if (revents & EPOLLHUP)
- log_error_unit(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.",
+ log_unit_error(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.",
UNIT(p->socket)->id);
else
- log_error_unit(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.",
+ log_unit_error(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.",
UNIT(p->socket)->id, revents);
goto fail;
@@ -2311,7 +2312,7 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
if (errno == EINTR)
continue;
- log_error_unit(UNIT(p->socket)->id,
+ log_unit_error(UNIT(p->socket)->id,
"Failed to accept socket: %m");
goto fail;
}
@@ -2360,8 +2361,8 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
f = SOCKET_SUCCESS;
}
- log_full_unit(f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- u->id,
+ log_unit_full(u->id,
+ f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
"%s control process exited, code=%s status=%i",
u->id, sigchld_code_to_string(code), status);
@@ -2372,7 +2373,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command->command_next &&
f == SOCKET_SUCCESS) {
- log_debug_unit(u->id,
+ log_unit_debug(u->id,
"%s running next command for state %s",
u->id, socket_state_to_string(s->state));
socket_run_next(s);
@@ -2383,7 +2384,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
/* No further commands for this step, so let's figure
* out what to do next */
- log_debug_unit(u->id,
+ log_unit_debug(u->id,
"%s got final SIGCHLD for state %s",
u->id, socket_state_to_string(s->state));
@@ -2440,53 +2441,53 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
switch (s->state) {
case SOCKET_START_PRE:
- log_warning_unit(UNIT(s)->id, "%s starting timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s starting timed out. Terminating.", UNIT(s)->id);
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_START_CHOWN:
case SOCKET_START_POST:
- log_warning_unit(UNIT(s)->id, "%s starting timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s starting timed out. Stopping.", UNIT(s)->id);
socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_PRE:
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_PRE_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
}
break;
case SOCKET_STOP_PRE_SIGKILL:
- log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_STOP_POST:
- log_warning_unit(UNIT(s)->id, "%s stopping timed out (2). Terminating.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Terminating.", UNIT(s)->id);
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
break;
case SOCKET_FINAL_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out (2). Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Killing.", UNIT(s)->id);
socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", UNIT(s)->id);
socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
}
break;
case SOCKET_FINAL_SIGKILL:
- log_warning_unit(UNIT(s)->id, "%s still around after SIGKILL (2). Entering failed mode.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL (2). Entering failed mode.", UNIT(s)->id);
socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
break;
@@ -2555,7 +2556,7 @@ static void socket_notify_service_dead(Socket *s, bool failed_permanent) {
* services. */
if (s->state == SOCKET_RUNNING) {
- log_debug_unit(UNIT(s)->id, "%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
+ log_unit_debug(UNIT(s)->id, "%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
if (failed_permanent)
socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
else
@@ -2574,7 +2575,7 @@ void socket_connection_unref(Socket *s) {
assert(s->n_connections > 0);
s->n_connections--;
- log_debug_unit(UNIT(s)->id, "%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
+ log_unit_debug(UNIT(s)->id, "%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
}
static void socket_trigger_notify(Unit *u, Unit *other) {
diff --git a/src/core/swap.c b/src/core/swap.c
index 1add722bf1..a6a23554c9 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -35,7 +35,7 @@
#include "unit-name.h"
#include "dbus-swap.h"
#include "special.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "exit-status.h"
#include "def.h"
#include "path-util.h"
@@ -209,8 +209,6 @@ static int swap_add_device_links(Swap *s) {
}
static int swap_add_default_dependencies(Swap *s) {
- int r;
-
assert(s);
if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
@@ -219,19 +217,7 @@ static int swap_add_default_dependencies(Swap *s) {
if (detect_container(NULL) > 0)
return 0;
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- if (!s->from_fragment)
- /* The swap unit can either be for an alternative device name, in which
- * case we don't need to add the dependency on swap.target because this unit
- * is following a different unit which will have this dependency added,
- * or it can be derived from /proc/swaps, in which case it was started
- * manually, and should not become a dependency of swap.target. */
- return 0;
-
- return unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
}
static int swap_verify(Swap *s) {
@@ -247,12 +233,12 @@ static int swap_verify(Swap *s) {
b = unit_has_name(UNIT(s), e);
if (!b) {
- log_error_unit(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
return -EINVAL;
}
if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error_unit(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
+ log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
return -EINVAL;
}
@@ -424,7 +410,7 @@ static int swap_add_one(
return 0;
fail:
- log_warning_unit(e, "Failed to load swap unit: %s", strerror(-r));
+ log_unit_warning_errno(e, r, "Failed to load swap unit: %m");
if (delete && u)
unit_free(u);
@@ -506,7 +492,7 @@ static void swap_set_state(Swap *s, SwapState state) {
}
if (state != old_state)
- log_debug_unit(UNIT(s)->id,
+ log_unit_debug(UNIT(s)->id,
"%s changed %s -> %s",
UNIT(s)->id,
swap_state_to_string(old_state),
@@ -627,6 +613,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(s)->cgroup_path;
+ exec_params.cgroup_delegate = s->cgroup_context.delegate;
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.unit_id = UNIT(s)->id;
@@ -711,7 +698,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
return;
fail:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
@@ -840,7 +827,7 @@ static void swap_enter_activating(Swap *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s failed to run 'swapon' task: %s",
UNIT(s)->id, strerror(-r));
swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
@@ -872,7 +859,7 @@ static void swap_enter_deactivating(Swap *s) {
return;
fail:
- log_warning_unit(UNIT(s)->id,
+ log_unit_warning(UNIT(s)->id,
"%s failed to run 'swapoff' task: %s",
UNIT(s)->id, strerror(-r));
swap_enter_active(s, SWAP_FAILURE_RESOURCES);
@@ -959,7 +946,7 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
state = swap_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
s->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -967,14 +954,14 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
f = swap_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != SWAP_SUCCESS)
s->result = f;
} else if (streq(key, "control-pid")) {
pid_t pid;
if (parse_pid(value, &pid) < 0)
- log_debug_unit(u->id, "Failed to parse control-pid value %s", value);
+ log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
else
s->control_pid = pid;
@@ -983,13 +970,13 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
id = swap_exec_command_from_string(value);
if (id < 0)
- log_debug_unit(u->id, "Failed to parse exec-command value %s", value);
+ log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
else {
s->control_command_id = id;
s->control_command = s->exec_command + id;
}
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -1047,8 +1034,8 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
}
- log_full_unit(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- u->id,
+ log_unit_full(u->id,
+ f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
"%s swap process exited, code=%s status=%i",
u->id, sigchld_code_to_string(code), status);
@@ -1090,38 +1077,38 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd
case SWAP_ACTIVATING:
case SWAP_ACTIVATING_DONE:
- log_warning_unit(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id);
swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
case SWAP_DEACTIVATING:
- log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id);
swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
break;
case SWAP_ACTIVATING_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id);
swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
}
break;
case SWAP_DEACTIVATING_SIGTERM:
if (s->kill_context.send_sigkill) {
- log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id);
swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
} else {
- log_warning_unit(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
}
break;
case SWAP_ACTIVATING_SIGKILL:
case SWAP_DEACTIVATING_SIGKILL:
- log_warning_unit(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id);
+ log_unit_warning(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id);
swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
break;
@@ -1183,7 +1170,7 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v
r = swap_load_proc_swaps(m, true);
if (r < 0) {
- log_error("Failed to reread /proc/swaps: %s", strerror(-r));
+ log_error_errno(r, "Failed to reread /proc/swaps: %m");
/* Reset flags, just in case, for late calls */
LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
diff --git a/src/core/system.conf b/src/core/system.conf
index 65a35a0689..a3727200df 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/system.conf.d/*.conf.
+#
# See systemd-system.conf(5) for details
[Manager]
diff --git a/src/core/timer.c b/src/core/timer.c
index a3713e2140..309852aae6 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -86,7 +86,7 @@ static int timer_verify(Timer *t) {
return 0;
if (!t->values) {
- log_error_unit(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
+ log_unit_error(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
return -EINVAL;
}
@@ -147,10 +147,8 @@ static int timer_setup_persistent(Timer *t) {
_cleanup_free_ char *h = NULL;
r = get_home_dir(&h);
- if (r < 0) {
- log_error("Failed to determine home directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine home directory: %m");
t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
}
@@ -260,7 +258,7 @@ static void timer_set_state(Timer *t, TimerState state) {
}
if (state != old_state)
- log_debug_unit(UNIT(t)->id,
+ log_unit_debug(UNIT(t)->id,
"%s changed %s -> %s", UNIT(t)->id,
timer_state_to_string(old_state),
timer_state_to_string(state));
@@ -419,7 +417,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
}
if (!found_monotonic && !found_realtime) {
- log_debug_unit(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
+ log_unit_debug(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
timer_set_state(t, TIMER_ELAPSED);
return;
}
@@ -427,7 +425,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_monotonic) {
char buf[FORMAT_TIMESPAN_MAX];
- log_debug_unit(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
+ log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
UNIT(t)->id,
format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
@@ -456,7 +454,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_realtime) {
char buf[FORMAT_TIMESTAMP_MAX];
- log_debug_unit(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
+ log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
if (t->realtime_event_source) {
r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
@@ -485,7 +483,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
return;
fail:
- log_warning_unit(UNIT(t)->id, "%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
+ log_unit_warning_errno(UNIT(t)->id, r, "%s failed to enter waiting state: %m", UNIT(t)->id);
timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
}
@@ -507,13 +505,13 @@ static void timer_enter_running(Timer *t) {
dual_timestamp_get(&t->last_trigger);
if (t->stamp_path)
- touch_file(t->stamp_path, true, t->last_trigger.realtime, (uid_t) -1, (gid_t) -1, 0);
+ touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
timer_set_state(t, TIMER_RUNNING);
return;
fail:
- log_warning_unit(UNIT(t)->id,
+ log_unit_warning(UNIT(t)->id,
"%s failed to queue unit startup job: %s",
UNIT(t)->id, bus_error_message(&error, r));
timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
@@ -521,6 +519,7 @@ fail:
static int timer_start(Unit *u) {
Timer *t = TIMER(u);
+ TimerValue *v;
assert(t);
assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
@@ -530,6 +529,11 @@ static int timer_start(Unit *u) {
t->last_trigger = DUAL_TIMESTAMP_NULL;
+ /* Reenable all timers that depend on unit activation time */
+ LIST_FOREACH(value, v, t->values)
+ if (v->base == TIMER_ACTIVE)
+ v->disabled = false;
+
if (t->stamp_path) {
struct stat st;
@@ -539,7 +543,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_t) -1, (uid_t) -1, (gid_t) -1, 0);
+ touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
}
t->result = TIMER_SUCCESS;
@@ -590,7 +594,7 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F
state = timer_state_from_string(value);
if (state < 0)
- log_debug_unit(u->id, "Failed to parse state value %s", value);
+ log_unit_debug(u->id, "Failed to parse state value %s", value);
else
t->deserialized_state = state;
} else if (streq(key, "result")) {
@@ -598,23 +602,23 @@ static int timer_deserialize_item(Unit *u, const char *key, const char *value, F
f = timer_result_from_string(value);
if (f < 0)
- log_debug_unit(u->id, "Failed to parse result value %s", value);
+ log_unit_debug(u->id, "Failed to parse result value %s", value);
else if (f != TIMER_SUCCESS)
t->result = f;
} else if (streq(key, "last-trigger-realtime")) {
r = safe_atou64(value, &t->last_trigger.realtime);
if (r < 0)
- log_debug_unit(u->id, "Failed to parse last-trigger-realtime value %s", value);
+ log_unit_debug(u->id, "Failed to parse last-trigger-realtime value %s", value);
} else if (streq(key, "last-trigger-monotonic")) {
r = safe_atou64(value, &t->last_trigger.monotonic);
if (r < 0)
- log_debug_unit(u->id, "Failed to parse last-trigger-monotonic value %s", value);
+ log_unit_debug(u->id, "Failed to parse last-trigger-monotonic value %s", value);
} else
- log_debug_unit(u->id, "Unknown serialization key '%s'", key);
+ log_unit_debug(u->id, "Unknown serialization key '%s'", key);
return 0;
}
@@ -639,7 +643,7 @@ static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
if (t->state != TIMER_WAITING)
return 0;
- log_debug_unit(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
+ log_unit_debug(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
timer_enter_running(t);
return 0;
}
@@ -672,7 +676,7 @@ static void timer_trigger_notify(Unit *u, Unit *other) {
case TIMER_RUNNING:
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_debug_unit(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
+ log_unit_debug(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
timer_enter_waiting(t, false);
}
break;
@@ -705,7 +709,7 @@ static void timer_time_change(Unit *u) {
if (t->state != TIMER_WAITING)
return;
- log_debug_unit(u->id, "%s: time change, recalculating next elapse.", u->id);
+ log_unit_debug(u->id, "%s: time change, recalculating next elapse.", u->id);
timer_enter_waiting(t, false);
}
@@ -744,6 +748,7 @@ const UnitVTable timer_vtable = {
"Unit\0"
"Timer\0"
"Install\0",
+ .private_section = "Timer",
.init = timer_init,
.done = timer_done,
@@ -769,4 +774,7 @@ const UnitVTable timer_vtable = {
.bus_interface = "org.freedesktop.systemd1.Timer",
.bus_vtable = bus_timer_vtable,
+ .bus_set_property = bus_timer_set_property,
+
+ .can_transient = true,
};
diff --git a/src/core/transaction.c b/src/core/transaction.c
index dbb4133fe3..b0b3d6bd60 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -22,7 +22,7 @@
#include <unistd.h>
#include <fcntl.h>
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "bus-util.h"
#include "bus-error.h"
#include "transaction.h"
@@ -189,11 +189,11 @@ static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
* another unit in which case we
* rather remove the start. */
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Looking at job %s/%s conflicted_by=%s",
j->unit->id, job_type_to_string(j->type),
yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
- log_debug_unit(k->unit->id,
+ log_unit_debug(k->unit->id,
"Looking at job %s/%s conflicted_by=%s",
k->unit->id, job_type_to_string(k->type),
yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
@@ -222,7 +222,7 @@ static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
return -ENOEXEC;
/* Ok, we can drop one, so let's do so. */
- log_debug_unit(d->unit->id,
+ log_unit_debug(d->unit->id,
"Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s",
j->unit->id, job_type_to_string(j->type),
k->unit->id, job_type_to_string(k->type),
@@ -264,13 +264,12 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
return -EAGAIN;
/* We couldn't merge anything. Failure */
- sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING,
- "Transaction contains conflicting jobs '%s' and '%s' for %s. "
- "Probably contradicting requirement dependencies configured.",
- job_type_to_string(t),
- job_type_to_string(k->type),
- k->unit->id);
- return r;
+ return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING,
+ "Transaction contains conflicting jobs '%s' and '%s' for %s. "
+ "Probably contradicting requirement dependencies configured.",
+ job_type_to_string(t),
+ job_type_to_string(k->type),
+ k->unit->id);
}
}
@@ -369,7 +368,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
* job to remove. We use the marker to find our way
* back, since smart how we are we stored our way back
* in there. */
- log_warning_unit(j->unit->id,
+ log_unit_warning(j->unit->id,
"Found ordering cycle on %s/%s",
j->unit->id, job_type_to_string(j->type));
@@ -377,9 +376,9 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
/* logging for j not k here here to provide consistent narrative */
- log_info_unit(j->unit->id,
- "Found dependency on %s/%s",
- k->unit->id, job_type_to_string(k->type));
+ log_unit_warning(j->unit->id,
+ "Found dependency on %s/%s",
+ k->unit->id, job_type_to_string(k->type));
if (!delete && hashmap_get(tr->jobs, k->unit) &&
!unit_matters_to_anchor(k->unit, k)) {
@@ -397,10 +396,10 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
if (delete) {
/* logging for j not k here here to provide consistent narrative */
- log_warning_unit(j->unit->id,
+ log_unit_warning(j->unit->id,
"Breaking ordering cycle by deleting job %s/%s",
delete->unit->id, job_type_to_string(delete->type));
- log_error_unit(delete->unit->id,
+ log_unit_error(delete->unit->id,
"Job %s/%s deleted to break ordering cycle starting with %s/%s",
delete->unit->id, job_type_to_string(delete->type),
j->unit->id, job_type_to_string(j->type));
@@ -412,9 +411,8 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
log_error("Unable to break cycle");
- sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
- "Transaction order is cyclic. See system logs for details.");
- return -ENOEXEC;
+ return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
+ "Transaction order is cyclic. See system logs for details.");
}
/* Make the marker point to where we come from, so that we can
@@ -513,12 +511,9 @@ static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_erro
assert(!j->transaction_next);
if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
- !job_type_is_superset(j->type, j->unit->job->type)) {
-
- sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
- "Transaction is destructive.");
- return -EEXIST;
- }
+ job_type_is_conflicting(j->unit->job->type, j->type))
+ return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
+ "Transaction is destructive.");
}
return 0;
@@ -557,17 +552,17 @@ rescan:
continue;
if (stops_running_service)
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"%s/%s would stop a running service.",
j->unit->id, job_type_to_string(j->type));
if (changes_existing_job)
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"%s/%s would change existing job.",
j->unit->id, job_type_to_string(j->type));
/* Ok, let's get rid of this */
- log_debug_unit(j->unit->id,
+ log_unit_debug(j->unit->id,
"Deleting %s/%s to minimize impact.",
j->unit->id, job_type_to_string(j->type));
@@ -727,10 +722,8 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
/* Tenth step: apply changes */
r = transaction_apply(tr, m, mode);
- if (r < 0) {
- log_warning("Failed to apply transaction: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to apply transaction: %m");
assert(hashmap_isempty(tr->jobs));
@@ -824,7 +817,7 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen
job_dependency_free(j->object_list);
if (other && delete_dependencies) {
- log_debug_unit(other->unit->id,
+ log_unit_debug(other->unit->id,
"Deleting job %s/%s as dependency of job %s/%s",
other->unit->id, job_type_to_string(other->type),
j->unit->id, job_type_to_string(j->type));
@@ -860,50 +853,39 @@ int transaction_add_job_and_dependencies(
/* by ? by->unit->id : "NA", */
/* by ? job_type_to_string(by->type) : "NA"); */
- if (unit->load_state != UNIT_LOADED &&
- unit->load_state != UNIT_ERROR &&
- unit->load_state != UNIT_NOT_FOUND &&
- unit->load_state != UNIT_MASKED) {
- sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s is not loaded properly.", unit->id);
- return -EINVAL;
- }
+ if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED))
+ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
+ "Unit %s is not loaded properly.", unit->id);
if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
if (unit->load_error == -ENOENT || unit->manager->test_run)
- sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id,
- strerror(-unit->load_error));
+ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
+ "Unit %s failed to load: %s.",
+ unit->id,
+ strerror(-unit->load_error));
else
- sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s. "
- "See system logs and 'systemctl status %s' for details.",
- unit->id,
- strerror(-unit->load_error),
- unit->id);
- return -EINVAL;
+ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
+ "Unit %s failed to load: %s. "
+ "See system logs and 'systemctl status %s' for details.",
+ unit->id,
+ strerror(-unit->load_error),
+ unit->id);
}
- if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) {
- sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id, strerror(-unit->load_error));
- return -EINVAL;
- }
+ if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
+ return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
+ "Unit %s failed to load: %s.",
+ unit->id, strerror(-unit->load_error));
- if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
- sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
- "Unit %s is masked.", unit->id);
- return -EADDRNOTAVAIL;
- }
+ if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
+ return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
+ "Unit %s is masked.", unit->id);
+
+ if (!unit_job_is_applicable(unit, type))
+ return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
+ "Job type %s is not applicable for unit %s.",
+ job_type_to_string(type), unit->id);
- if (!unit_job_is_applicable(unit, type)) {
- sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
- "Job type %s is not applicable for unit %s.",
- job_type_to_string(type), unit->id);
- return -EBADR;
- }
/* First add the job. */
ret = transaction_add_one_job(tr, type, unit, override, &is_new);
@@ -931,7 +913,7 @@ int transaction_add_job_and_dependencies(
SET_FOREACH(dep, following, i) {
r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
if (r < 0) {
- log_warning_unit(dep->id,
+ log_unit_warning(dep->id,
"Cannot add dependency job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -970,7 +952,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_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
+ log_unit_full(dep->id,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
"Cannot add dependency job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -982,7 +965,8 @@ int transaction_add_job_and_dependencies(
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);
if (r < 0) {
- log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
+ log_unit_full(dep->id,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
"Cannot add dependency job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -1005,7 +989,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_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
+ log_unit_full(dep->id,
+ r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
"Cannot add dependency job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -1028,7 +1013,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);
if (r < 0) {
- log_warning_unit(dep->id,
+ log_unit_warning(dep->id,
"Cannot add dependency job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -1081,7 +1066,7 @@ int transaction_add_job_and_dependencies(
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);
if (r < 0) {
- log_warning_unit(dep->id,
+ log_unit_warning(dep->id,
"Cannot add dependency reload job for unit %s, ignoring: %s",
dep->id, bus_error_message(e, r));
@@ -1128,7 +1113,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
if (r < 0)
- log_warning_unit(u->id,
+ log_unit_warning(u->id,
"Cannot add isolate job for unit %s, ignoring: %s",
u->id, strerror(-r));
}
diff --git a/src/core/umount.c b/src/core/umount.c
index cffa45327b..e38851dc12 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -401,7 +401,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
mount_point_free(head, m);
} else if (log_error) {
- log_warning("Could not unmount %s: %m", m->path);
+ log_warning_errno(errno, "Could not unmount %s: %m", m->path);
n_failed++;
}
}
@@ -423,7 +423,7 @@ static int swap_points_list_off(MountPoint **head, bool *changed) {
mount_point_free(head, m);
} else {
- log_warning("Could not deactivate swap %s: %m", m->path);
+ log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
n_failed++;
}
}
@@ -460,7 +460,7 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
mount_point_free(head, m);
} else {
- log_warning("Could not detach loopback %s: %m", m->path);
+ log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
n_failed++;
}
}
@@ -495,7 +495,7 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
mount_point_free(head, m);
} else {
- log_warning("Could not detach DM %s: %m", m->path);
+ log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
n_failed++;
}
}
diff --git a/src/core/unit.c b/src/core/unit.c
index 84f210a312..fe0dfb2083 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -47,7 +47,7 @@
#include "mkdir.h"
#include "label.h"
#include "fileio-label.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "dbus.h"
#include "execute.h"
#include "virt.h"
@@ -92,6 +92,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->deserialized_job = _JOB_TYPE_INVALID;
u->default_dependencies = true;
u->unit_file_state = _UNIT_FILE_STATE_INVALID;
+ u->unit_file_preset = -1;
u->on_failure_job_mode = JOB_REPLACE;
return u;
@@ -527,6 +528,7 @@ void unit_free(Unit *u) {
unit_unwatch_all_pids(u);
condition_free_list(u->conditions);
+ condition_free_list(u->asserts);
unit_ref_unset(&u->slice);
@@ -929,7 +931,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
if (u->job_timeout_reboot_arg)
fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
- condition_dump_list(u->conditions, f, prefix);
+ condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
+ condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
if (dual_timestamp_is_set(&u->condition_timestamp))
fprintf(f,
@@ -938,6 +941,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
prefix, yes_no(u->condition_result));
+ if (dual_timestamp_is_set(&u->assert_timestamp))
+ fprintf(f,
+ "%s\tAssert Timestamp: %s\n"
+ "%s\tAssert Result: %s\n",
+ prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->assert_timestamp.realtime)),
+ prefix, yes_no(u->assert_result));
+
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
Unit *other;
@@ -1209,7 +1219,7 @@ int unit_load(Unit *u) {
goto fail;
if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
- log_error_unit(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
+ log_unit_error(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
r = -EINVAL;
goto fail;
}
@@ -1230,21 +1240,77 @@ fail:
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
- log_debug_unit(u->id, "Failed to load configuration for %s: %s",
+ log_unit_debug(u->id, "Failed to load configuration for %s: %s",
u->id, strerror(-r));
return r;
}
+static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to_string)(ConditionType t)) {
+ Condition *c;
+ int triggered = -1;
+
+ assert(u);
+ assert(to_string);
+
+ /* If the condition list is empty, then it is true */
+ if (!first)
+ return true;
+
+ /* Otherwise, if all of the non-trigger conditions apply and
+ * if any of the trigger conditions apply (unless there are
+ * none) we return true */
+ LIST_FOREACH(conditions, c, first) {
+ int r;
+
+ r = condition_test(c);
+ if (r < 0)
+ log_unit_warning(u->id,
+ "Couldn't determine result for %s=%s%s%s for %s, assuming failed: %s",
+ to_string(c->type),
+ c->trigger ? "|" : "",
+ c->negate ? "!" : "",
+ c->parameter,
+ u->id,
+ strerror(-r));
+ else
+ log_unit_debug(u->id,
+ "%s=%s%s%s %s for %s.",
+ to_string(c->type),
+ c->trigger ? "|" : "",
+ c->negate ? "!" : "",
+ c->parameter,
+ condition_result_to_string(c->result),
+ u->id);
+
+ if (!c->trigger && r <= 0)
+ return false;
+
+ if (c->trigger && triggered <= 0)
+ triggered = r > 0;
+ }
+
+ return triggered != 0;
+}
+
static bool unit_condition_test(Unit *u) {
assert(u);
dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = condition_test_list(u->id, u->conditions);
+ u->condition_result = unit_condition_test_list(u, u->conditions, condition_type_to_string);
return u->condition_result;
}
+static bool unit_assert_test(Unit *u) {
+ assert(u);
+
+ dual_timestamp_get(&u->assert_timestamp);
+ u->assert_result = unit_condition_test_list(u, u->asserts, assert_type_to_string);
+
+ return u->assert_result;
+}
+
_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
const UnitStatusMessageFormats *format_table;
@@ -1329,10 +1395,10 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING :
SD_MESSAGE_UNIT_RELOADING;
- log_struct_unit(LOG_INFO,
- u->id,
- MESSAGE_ID(mid),
- "MESSAGE=%s", buf,
+ log_unit_struct(u->id,
+ LOG_INFO,
+ LOG_MESSAGE_ID(mid),
+ LOG_MESSAGE("%s", buf),
NULL);
}
@@ -1341,6 +1407,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
* -EALREADY: Unit is already started.
* -EAGAIN: An operation is already in progress. Retry later.
* -ECANCELED: Too many requests for now.
+ * -EPROTO: Assert failed
*/
int unit_start(Unit *u) {
UnitActiveState state;
@@ -1365,15 +1432,21 @@ int unit_start(Unit *u) {
* but we don't want to recheck the condition in that case. */
if (state != UNIT_ACTIVATING &&
!unit_condition_test(u)) {
- log_debug_unit(u->id, "Starting of %s requested but condition failed. Ignoring.", u->id);
+ log_unit_debug(u->id, "Starting of %s requested but condition failed. Not starting unit.", u->id);
return -EALREADY;
}
+ /* If the asserts failed, fail the entire job */
+ if (state != UNIT_ACTIVATING &&
+ !unit_assert_test(u)) {
+ log_unit_debug(u->id, "Starting of %s requested but asserts failed.", u->id);
+ return -EPROTO;
+ }
+
/* Forward to the main object, if we aren't it. */
following = unit_following(u);
if (following) {
- log_debug_unit(u->id, "Redirecting start request from %s to %s.",
- u->id, following->id);
+ log_unit_debug(u->id, "Redirecting start request from %s to %s.", u->id, following->id);
return unit_start(following);
}
@@ -1424,7 +1497,7 @@ int unit_stop(Unit *u) {
return -EALREADY;
if ((following = unit_following(u))) {
- log_debug_unit(u->id, "Redirecting stop request from %s to %s.",
+ log_unit_debug(u->id, "Redirecting stop request from %s to %s.",
u->id, following->id);
return unit_stop(following);
}
@@ -1462,14 +1535,14 @@ int unit_reload(Unit *u) {
return -EALREADY;
if (state != UNIT_ACTIVE) {
- log_warning_unit(u->id, "Unit %s cannot be reloaded because it is inactive.",
+ log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.",
u->id);
return -ENOEXEC;
}
following = unit_following(u);
if (following) {
- log_debug_unit(u->id, "Redirecting reload request from %s to %s.",
+ log_unit_debug(u->id, "Redirecting reload request from %s to %s.",
u->id, following->id);
return unit_reload(following);
}
@@ -1523,7 +1596,7 @@ static void unit_check_unneeded(Unit *u) {
if (unit_active_or_pending(other))
return;
- log_info_unit(u->id, "Unit %s is not needed anymore. Stopping.", u->id);
+ log_unit_info(u->id, "Unit %s is not needed anymore. Stopping.", u->id);
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
@@ -1555,7 +1628,7 @@ static void unit_check_binds_to(Unit *u) {
if (!stop)
return;
- log_info_unit(u->id, "Unit %s is bound to inactive service. Stopping, too.", u->id);
+ log_unit_info(u->id, "Unit %s is bound to inactive service. Stopping, too.", u->id);
/* A unit we need to run is gone. Sniff. Let's stop this. */
manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
@@ -1647,14 +1720,14 @@ void unit_start_on_failure(Unit *u) {
if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
return;
- log_info_unit(u->id, "Triggering OnFailure= dependencies of %s.", u->id);
+ log_unit_info(u->id, "Triggering OnFailure= dependencies of %s.", u->id);
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);
if (r < 0)
- log_error_unit(u->id, "Failed to enqueue OnFailure= job: %s", strerror(-r));
+ log_unit_error_errno(u->id, r, "Failed to enqueue OnFailure= job: %m");
}
}
@@ -1710,7 +1783,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
/* Make sure the cgroup is always removed when we become inactive */
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- unit_destroy_cgroup(u);
+ unit_destroy_cgroup_if_empty(u);
/* Note that this doesn't apply to RemainAfterExit services exiting
* successfully, since there's no change of state in that case. Which is
@@ -1818,7 +1891,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
check_unneeded_dependencies(u);
if (ns != os && ns == UNIT_FAILED) {
- log_notice_unit(u->id, "Unit %s entered failed state.", u->id);
+ log_unit_notice(u->id, "Unit %s entered failed state.", u->id);
unit_start_on_failure(u);
}
}
@@ -2080,10 +2153,10 @@ static int maybe_warn_about_dependency(const char *id, const char *other, UnitDe
case UNIT_TRIGGERS:
case UNIT_TRIGGERED_BY:
if (streq_ptr(id, other))
- log_warning_unit(id, "Dependency %s=%s dropped from unit %s",
+ log_unit_warning(id, "Dependency %s=%s dropped from unit %s",
unit_dependency_to_string(dependency), id, other);
else
- log_warning_unit(id, "Dependency %s=%s dropped from unit %s merged into %s",
+ log_unit_warning(id, "Dependency %s=%s dropped from unit %s merged into %s",
unit_dependency_to_string(dependency), id,
strna(other), id);
return -EINVAL;
@@ -2502,10 +2575,14 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
+ dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp);
if (dual_timestamp_is_set(&u->condition_timestamp))
unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
+ if (dual_timestamp_is_set(&u->assert_timestamp))
+ unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
+
unit_serialize_item(u, f, "transient", yes_no(u->transient));
if (u->cgroup_path)
@@ -2645,6 +2722,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} else if (streq(l, "condition-timestamp")) {
dual_timestamp_deserialize(v, &u->condition_timestamp);
continue;
+ } else if (streq(l, "assert-timestamp")) {
+ dual_timestamp_deserialize(v, &u->assert_timestamp);
+ continue;
} else if (streq(l, "condition-result")) {
int b;
@@ -2656,6 +2736,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
+ } else if (streq(l, "assert-result")) {
+ int b;
+
+ b = parse_boolean(v);
+ if (b < 0)
+ log_debug("Failed to parse assert result value %s", v);
+ else
+ u->assert_result = b;
+
+ continue;
+
} else if (streq(l, "transient")) {
int b;
@@ -2939,18 +3030,16 @@ int unit_kill_common(
if (who == KILL_MAIN && main_pid <= 0) {
if (main_pid < 0)
- sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
else
- sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
- return -ESRCH;
+ return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
}
if (who == KILL_CONTROL && control_pid <= 0) {
if (control_pid < 0)
- sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
else
- sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ESRCH;
+ return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
}
if (who == KILL_CONTROL || who == KILL_ALL)
@@ -3002,6 +3091,17 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
return u->unit_file_state;
}
+int unit_get_unit_file_preset(Unit *u) {
+ assert(u);
+
+ if (u->unit_file_preset < 0 && u->fragment_path)
+ u->unit_file_preset = unit_file_query_preset(
+ u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ NULL, basename(u->fragment_path));
+
+ return u->unit_file_preset;
+}
+
Unit* unit_ref_set(UnitRef *ref, Unit *u) {
assert(ref);
assert(u);
@@ -3172,7 +3272,7 @@ static int unit_drop_in_file(Unit *u,
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
- _cleanup_free_ char *dir = NULL;
+ _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
int r;
assert(u);
@@ -3184,7 +3284,24 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
if (r < 0)
return r;
- return write_drop_in(dir, u->id, 50, name, data);
+ r = write_drop_in(dir, u->id, 50, name, data);
+ if (r < 0)
+ return r;
+
+ r = drop_in_file(dir, u->id, 50, name, &p, &q);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(&u->dropin_paths, q);
+ if (r < 0)
+ return r;
+
+ strv_sort(u->dropin_paths);
+ strv_uniq(u->dropin_paths);
+
+ u->dropin_mtime = now(CLOCK_REALTIME);
+
+ return 0;
}
int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
@@ -3347,7 +3464,7 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(main_pid, &comm);
- log_warning_unit(u->id, "Failed to kill main process " PID_FMT " (%s): %s", main_pid, strna(comm), strerror(-r));
+ log_unit_warning_errno(u->id, r, "Failed to kill main process " PID_FMT " (%s): %m", main_pid, strna(comm));
} else {
if (!main_pid_alien)
wait_for_exit = true;
@@ -3364,7 +3481,7 @@ int unit_kill_context(
_cleanup_free_ char *comm = NULL;
get_process_comm(control_pid, &comm);
- log_warning_unit(u->id, "Failed to kill control process " PID_FMT " (%s): %s", control_pid, strna(comm), strerror(-r));
+ log_unit_warning_errno(u->id, r, "Failed to kill control process " PID_FMT " (%s): %m", control_pid, strna(comm));
} else {
wait_for_exit = true;
@@ -3384,7 +3501,7 @@ int unit_kill_context(
r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
+ log_unit_warning_errno(u->id, r, "Failed to kill control group: %m");
} else if (r > 0) {
/* FIXME: For now, we will not wait for the
diff --git a/src/core/unit.h b/src/core/unit.h
index 081ab18f10..0e45229d7b 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -129,8 +129,10 @@ struct Unit {
/* Conditions to check */
LIST_HEAD(Condition, conditions);
+ LIST_HEAD(Condition, asserts);
dual_timestamp condition_timestamp;
+ dual_timestamp assert_timestamp;
dual_timestamp inactive_exit_timestamp;
dual_timestamp active_enter_timestamp;
@@ -177,8 +179,9 @@ struct Unit {
/* Error code when we didn't manage to load the unit (negative) */
int load_error;
- /* Cached unit file state */
+ /* Cached unit file state and preset */
UnitFileState unit_file_state;
+ int unit_file_preset;
/* Counterparts in the cgroup filesystem */
char *cgroup_path;
@@ -212,6 +215,7 @@ struct Unit {
/* Did the last condition check succeed? */
bool condition_result;
+ bool assert_result;
/* Is this a transient unit? */
bool transient;
@@ -557,6 +561,7 @@ void unit_start_on_failure(Unit *u);
void unit_trigger_notify(Unit *u);
UnitFileState unit_get_unit_file_state(Unit *u);
+int unit_get_unit_file_preset(Unit *u);
Unit* unit_ref_set(UnitRef *ref, Unit *u);
void unit_ref_unset(UnitRef *ref);
@@ -593,11 +598,20 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_;
/* Macros which append UNIT= or USER_UNIT= to the message */
-#define log_full_unit(level, unit, ...) log_meta_object(level, __FILE__, __LINE__, __func__, getpid() == 1 ? "UNIT=" : "USER_UNIT=", unit, __VA_ARGS__)
-#define log_debug_unit(unit, ...) log_full_unit(LOG_DEBUG, unit, __VA_ARGS__)
-#define log_info_unit(unit, ...) log_full_unit(LOG_INFO, unit, __VA_ARGS__)
-#define log_notice_unit(unit, ...) log_full_unit(LOG_NOTICE, unit, __VA_ARGS__)
-#define log_warning_unit(unit, ...) log_full_unit(LOG_WARNING, unit, __VA_ARGS__)
-#define log_error_unit(unit, ...) log_full_unit(LOG_ERR, unit, __VA_ARGS__)
+#define log_unit_full_errno(unit, level, error, ...) log_object_internal(level, error, __FILE__, __LINE__, __func__, getpid() == 1 ? "UNIT=" : "USER_UNIT=", unit, __VA_ARGS__)
+#define log_unit_full(unit, level, ...) log_unit_full_errno(unit, level, 0, __VA_ARGS__)
-#define log_struct_unit(level, unit, ...) log_struct(level, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
+#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, __VA_ARGS__)
+#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, __VA_ARGS__)
+#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, __VA_ARGS__)
+#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, __VA_ARGS__)
+#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, __VA_ARGS__)
+
+#define log_unit_debug_errno(unit, error, ...) log_unit_full_errno(unit, LOG_DEBUG, error, __VA_ARGS__)
+#define log_unit_info_errno(unit, error, ...) log_unit_full_errno(unit, LOG_INFO, error, __VA_ARGS__)
+#define log_unit_notice_errno(unit, error, ...) log_unit_full_errno(unit, LOG_NOTICE, error, __VA_ARGS__)
+#define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__)
+#define log_unit_error_errno(unit, error, ...) log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__)
+
+#define log_unit_struct(unit, level, ...) log_struct(level, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
+#define log_unit_struct_errno(unit, level, error, ...) log_struct_errno(level, error, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
diff --git a/src/core/user.conf b/src/core/user.conf
index 8c7ecde727..87c8164378 100644
--- a/src/core/user.conf
+++ b/src/core/user.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/user.conf.d/*.conf.
+#
# See systemd-user.conf(5) for details
[Manager]
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index 05ceff443f..3a866f36fc 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -19,26 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
+#include <string.h>
#include <unistd.h>
+#include "dropin.h"
+#include "fileio.h"
+#include "generator.h"
+#include "hashmap.h"
#include "log.h"
-#include "util.h"
-#include "unit-name.h"
#include "mkdir.h"
-#include "strv.h"
-#include "fileio.h"
#include "path-util.h"
-#include "dropin.h"
-#include "generator.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "util.h"
+
+typedef struct crypto_device {
+ char *uuid;
+ char *keyfile;
+ char *name;
+ char *options;
+ bool create;
+} crypto_device;
static const char *arg_dest = "/tmp";
static bool arg_enabled = true;
static bool arg_read_crypttab = true;
-static char **arg_disks = NULL;
-static char **arg_options = NULL;
-static char *arg_keyfile = NULL;
+static bool arg_whitelist = false;
+static Hashmap *arg_disks = NULL;
+static char *arg_default_options = NULL;
+static char *arg_default_keyfile = NULL;
static bool has_option(const char *haystack, const char *needle) {
const char *f = haystack;
@@ -116,10 +126,8 @@ static int create_disk(
return log_oom();
f = fopen(p, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", p);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", p);
fputs(
"# Automatically generated by systemd-cryptsetup-generator\n\n"
@@ -200,10 +208,8 @@ static int create_disk(
name);
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write file %s: %m", p);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write file %s: %m", p);
from = strappenda("../", n);
@@ -214,10 +220,8 @@ static int create_disk(
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
free(to);
if (!nofail)
@@ -228,10 +232,8 @@ static int create_disk(
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
}
free(to);
@@ -240,10 +242,8 @@ static int create_disk(
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
if (!noauto && !nofail) {
_cleanup_free_ char *dmname;
@@ -254,17 +254,63 @@ static int create_disk(
r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator \n\n"
"[Unit]\nJobTimeoutSec=0");
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
+ }
+
+ return 0;
+}
+
+static void free_arg_disks(void) {
+ crypto_device *d;
+
+ while ((d = hashmap_steal_first(arg_disks))) {
+ free(d->uuid);
+ free(d->keyfile);
+ free(d->name);
+ free(d->options);
+ free(d);
+ }
+
+ hashmap_free(arg_disks);
+}
+
+static crypto_device *get_crypto_device(const char *uuid) {
+ int r;
+ crypto_device *d;
+
+ assert(uuid);
+
+ d = hashmap_get(arg_disks, uuid);
+ if (!d) {
+ d = new0(struct crypto_device, 1);
+ if (!d)
+ return NULL;
+
+ d->create = false;
+ d->keyfile = d->options = d->name = NULL;
+
+ d->uuid = strdup(uuid);
+ if (!d->uuid) {
+ free(d);
+ return NULL;
+ }
+
+ r = hashmap_put(arg_disks, d->uuid, d);
if (r < 0) {
- log_error("Failed to write device drop-in: %s", strerror(-r));
- return r;
+ free(d->uuid);
+ free(d);
+ return NULL;
}
}
- return 0;
+ return d;
}
static int parse_proc_cmdline_item(const char *key, const char *value) {
int r;
+ crypto_device *d;
+ _cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
if (STR_IN_SET(key, "luks", "rd.luks") && value) {
@@ -284,232 +330,214 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
} else if (STR_IN_SET(key, "luks.uuid", "rd.luks.uuid") && value) {
- if (strv_extend(&arg_disks, value) < 0)
+ d = get_crypto_device(startswith(value, "luks-") ? value+5 : value);
+ if (!d)
return log_oom();
+ d->create = arg_whitelist = true;
+
} else if (STR_IN_SET(key, "luks.options", "rd.luks.options") && value) {
- if (strv_extend(&arg_options, value) < 0)
+ r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
+ if (r == 2) {
+ d = get_crypto_device(uuid);
+ if (!d)
+ return log_oom();
+
+ free(d->options);
+ d->options = uuid_value;
+ uuid_value = NULL;
+ } else if (free_and_strdup(&arg_default_options, value) < 0)
return log_oom();
} else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) {
- free(arg_keyfile);
- arg_keyfile = strdup(value);
- if (!arg_keyfile)
+ r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
+ if (r == 2) {
+ d = get_crypto_device(uuid);
+ if (!d)
+ return log_oom();
+
+ free(d->keyfile);
+ d->keyfile = uuid_value;
+ uuid_value = NULL;
+ } else if (free_and_strdup(&arg_default_keyfile, value))
return log_oom();
+ } else if (STR_IN_SET(key, "luks.name", "rd.luks.name") && value) {
+
+ r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
+ if (r == 2) {
+ d = get_crypto_device(uuid);
+ if (!d)
+ return log_oom();
+
+ d->create = arg_whitelist = true;
+
+ free(d->name);
+ d->name = uuid_value;
+ uuid_value = NULL;
+ } else
+ log_warning("Failed to parse luks name switch %s. Ignoring.", value);
+
}
return 0;
}
-int main(int argc, char *argv[]) {
- _cleanup_strv_free_ char **disks_done = NULL;
+static int add_crypttab_devices(void) {
+ struct stat st;
+ unsigned crypttab_line = 0;
_cleanup_fclose_ FILE *f = NULL;
- unsigned n = 0;
- int r = EXIT_FAILURE, r2 = EXIT_FAILURE;
- char **i;
- if (argc > 1 && argc != 4) {
- log_error("This program takes three or no arguments.");
- return EXIT_FAILURE;
+ if (!arg_read_crypttab)
+ return 0;
+
+ f = fopen("/etc/crypttab", "re");
+ if (!f) {
+ if (errno != ENOENT)
+ log_error_errno(errno, "Failed to open /etc/crypttab: %m");
+ return 0;
}
- if (argc > 1)
- arg_dest = argv[1];
+ if (fstat(fileno(f), &st) < 0) {
+ log_error_errno(errno, "Failed to stat /etc/crypttab: %m");
+ return 0;
+ }
- log_set_target(LOG_TARGET_SAFE);
- log_parse_environment();
- log_open();
+ /* If we readd support for specifying passphrases
+ * directly in crypttab we should upgrade the warning
+ * below, though possibly only if a passphrase is
+ * specified directly. */
+ if (st.st_mode & 0005)
+ log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");
- umask(0022);
+ for (;;) {
+ int r, k;
+ char line[LINE_MAX], *l, *uuid;
+ crypto_device *d = NULL;
+ _cleanup_free_ char *name = NULL, *device = NULL, *keyfile = NULL, *options = NULL;
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- goto cleanup;
+ if (!fgets(line, sizeof(line), f))
+ break;
- if (!arg_enabled) {
- r = r2 = EXIT_SUCCESS;
- goto cleanup;
- }
+ crypttab_line++;
- strv_uniq(arg_disks);
+ l = strstrip(line);
+ if (*l == '#' || *l == 0)
+ continue;
- if (arg_read_crypttab) {
- struct stat st;
+ k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyfile, &options);
+ if (k < 2 || k > 4) {
+ log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line);
+ continue;
+ }
- f = fopen("/etc/crypttab", "re");
- if (!f) {
- if (errno == ENOENT)
- r = EXIT_SUCCESS;
- else
- log_error("Failed to open /etc/crypttab: %m");
+ uuid = startswith(device, "UUID=");
+ if (!uuid)
+ uuid = path_startswith(device, "/dev/disk/by-uuid/");
+ if (!uuid)
+ uuid = startswith(name, "luks-");
+ if (uuid)
+ d = hashmap_get(arg_disks, uuid);
- goto next;
+ if (arg_whitelist && !d) {
+ log_info("Not creating device '%s' because it was not specified on the kernel command line.", name);
+ continue;
}
- if (fstat(fileno(f), &st) < 0) {
- log_error("Failed to stat /etc/crypttab: %m");
- goto next;
- }
+ r = create_disk(name, device, keyfile, (d && d->options) ? d->options : options);
+ if (r < 0)
+ return r;
- /* If we readd support for specifying passphrases
- * directly in crypttabe we should upgrade the warning
- * below, though possibly only if a passphrase is
- * specified directly. */
- if (st.st_mode & 0005)
- log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");
+ if (d)
+ d->create = false;
+ }
- for (;;) {
- char line[LINE_MAX], *l;
- _cleanup_free_ char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
- int k;
+ return 0;
+}
- if (!fgets(line, sizeof(line), f))
- break;
+static int add_proc_cmdline_devices(void) {
+ int r;
+ Iterator i;
+ crypto_device *d;
- n++;
+ HASHMAP_FOREACH(d, arg_disks, i) {
+ const char *options;
+ _cleanup_free_ char *device = NULL;
- l = strstrip(line);
- if (*l == '#' || *l == 0)
- continue;
+ if (!d->create)
+ continue;
- k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
- if (k < 2 || k > 4) {
- log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
- continue;
- }
+ if (!d->name) {
+ d->name = strappend("luks-", d->uuid);
+ if (!d->name)
+ return log_oom();
+ }
- /*
- If options are specified on the kernel commandline, let them override
- the ones from crypttab.
- */
- STRV_FOREACH(i, arg_options) {
- _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
- const char *p = *i;
-
- k = sscanf(p, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
- if (k == 2 && streq(proc_uuid, device + 5)) {
- free(options);
- options = strdup(p);
- if (!options) {
- log_oom();
- goto cleanup;
- }
- }
- }
+ device = strappend("UUID=", d->uuid);
+ if (!device)
+ return log_oom();
- if (arg_disks) {
- /*
- If luks UUIDs are specified on the kernel command line, use them as a filter
- for /etc/crypttab and only generate units for those.
- */
- STRV_FOREACH(i, arg_disks) {
- _cleanup_free_ char *proc_device = NULL, *proc_name = NULL;
- const char *p = *i;
-
- if (startswith(p, "luks-"))
- p += 5;
-
- proc_name = strappend("luks-", p);
- proc_device = strappend("UUID=", p);
-
- if (!proc_name || !proc_device) {
- log_oom();
- goto cleanup;
- }
-
- if (streq(proc_device, device) || streq(proc_name, name)) {
- if (create_disk(name, device, password, options) < 0)
- goto cleanup;
-
- if (strv_extend(&disks_done, p) < 0) {
- log_oom();
- goto cleanup;
- }
- }
- }
- } else if (create_disk(name, device, password, options) < 0)
- goto cleanup;
+ if (d->options)
+ options = d->options;
+ else if (arg_default_options)
+ options = arg_default_options;
+ else
+ options = "timeout=0";
- }
+ r = create_disk(d->name, device, d->keyfile ?: arg_default_keyfile, options);
+ if (r < 0)
+ return r;
}
- r = EXIT_SUCCESS;
-
-next:
- STRV_FOREACH(i, arg_disks) {
- /*
- Generate units for those UUIDs, which were specified
- on the kernel command line and not yet written.
- */
+ return 0;
+}
- _cleanup_free_ char *name = NULL, *device = NULL, *options = NULL;
- const char *p = *i;
+int main(int argc, char *argv[]) {
+ int r = EXIT_FAILURE;
- if (startswith(p, "luks-"))
- p += 5;
+ if (argc > 1 && argc != 4) {
+ log_error("This program takes three or no arguments.");
+ return EXIT_FAILURE;
+ }
- if (strv_contains(disks_done, p))
- continue;
+ if (argc > 1)
+ arg_dest = argv[1];
- name = strappend("luks-", p);
- device = strappend("UUID=", p);
+ log_set_target(LOG_TARGET_SAFE);
+ log_parse_environment();
+ log_open();
- if (!name || !device) {
- log_oom();
- goto cleanup;
- }
+ umask(0022);
- if (arg_options) {
- /*
- If options are specified on the kernel commandline, use them.
- */
- char **j;
-
- STRV_FOREACH(j, arg_options) {
- _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
- const char *s = *j;
- int k;
-
- k = sscanf(s, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
- if (k == 2) {
- if (streq(proc_uuid, device + 5)) {
- free(options);
- options = proc_options;
- proc_options = NULL;
- }
- } else if (!options) {
- /*
- Fall back to options without a specified UUID
- */
- options = strdup(s);
- if (!options) {
- log_oom();
- goto cleanup;
- };
- }
- }
- }
+ arg_disks = hashmap_new(&string_hash_ops);
+ if (!arg_disks)
+ goto cleanup;
- if (!options) {
- options = strdup("timeout=0");
- if (!options) {
- log_oom();
- goto cleanup;
- }
- }
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+ r = EXIT_FAILURE;
+ }
- if (create_disk(name, device, arg_keyfile, options) < 0)
- goto cleanup;
+ if (!arg_enabled) {
+ r = EXIT_SUCCESS;
+ goto cleanup;
}
- r2 = EXIT_SUCCESS;
+ if (add_crypttab_devices() < 0)
+ goto cleanup;
+
+ if (add_proc_cmdline_devices() < 0)
+ goto cleanup;
+
+ r = EXIT_SUCCESS;
cleanup:
- strv_free(arg_disks);
- strv_free(arg_options);
- free(arg_keyfile);
+ free_arg_disks();
+ free(arg_default_options);
+ free(arg_default_keyfile);
- return r != EXIT_SUCCESS ? r : r2;
+ return r;
}
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 94570eb82d..21b1260f1b 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -280,10 +280,8 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
id = strappenda("cryptsetup:", escaped_name);
r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
- if (r < 0) {
- log_error("Failed to query password: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query password: %m");
if (arg_verify) {
_cleanup_strv_free_ char **passwords2 = NULL;
@@ -296,10 +294,8 @@ static int get_password(const char *name, usec_t until, bool accept_cached, char
id = strappenda("cryptsetup-verification:", escaped_name);
r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
- if (r < 0) {
- log_error("Failed to query verification password: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query verification password: %m");
assert(strv_length(passwords2) == 1);
@@ -355,7 +351,7 @@ static int attach_tcrypt(struct crypt_device *cd,
if (key_file) {
r = read_one_line_file(key_file, &passphrase);
if (r < 0) {
- log_error("Failed to read password file '%s': %s", key_file, strerror(-r));
+ log_error_errno(r, "Failed to read password file '%s': %m", key_file);
return -EAGAIN;
}
@@ -400,7 +396,9 @@ static int attach_luks_or_plain(struct crypt_device *cd,
/* plain isn't a real hash type. it just means "use no hash" */
if (!streq(arg_hash, "plain"))
params.hash = arg_hash;
- } else
+ } else if (!key_file)
+ /* for CRYPT_PLAIN, the behaviour of cryptsetup
+ * package is to not hash when a key file is provided */
params.hash = "ripemd160";
if (arg_cipher) {
@@ -436,10 +434,8 @@ static int attach_luks_or_plain(struct crypt_device *cd,
pass_volume_key = (params.hash == NULL);
}
- if (r < 0) {
- log_error("Loading of cryptographic parameters failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
crypt_get_cipher(cd),
@@ -452,7 +448,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
key_file, arg_keyfile_size,
arg_keyfile_offset, flags);
if (r < 0) {
- log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r));
+ log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
return -EAGAIN;
}
} else {
@@ -565,7 +561,7 @@ int main(int argc, char *argv[]) {
k = crypt_init(&cd, argv[3]);
if (k) {
- log_error("crypt_init() failed: %s", strerror(-k));
+ log_error_errno(k, "crypt_init() failed: %m");
goto finish;
}
@@ -621,7 +617,7 @@ int main(int argc, char *argv[]) {
key_file = NULL;
continue;
} else if (k != -EPERM) {
- log_error("Failed to activate: %s", strerror(-k));
+ log_error_errno(k, "Failed to activate: %m");
goto finish;
}
@@ -639,7 +635,7 @@ int main(int argc, char *argv[]) {
k = crypt_init_by_name(&cd, argv[2]);
if (k) {
- log_error("crypt_init() failed: %s", strerror(-k));
+ log_error_errno(k, "crypt_init() failed: %m");
goto finish;
}
@@ -647,7 +643,7 @@ int main(int argc, char *argv[]) {
k = crypt_deactivate(cd, argv[2]);
if (k < 0) {
- log_error("Failed to deactivate: %s", strerror(-k));
+ log_error_errno(k, "Failed to deactivate: %m");
goto finish;
}
diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c
index 3c4522b589..10a33efee5 100644
--- a/src/dbus1-generator/dbus1-generator.c
+++ b/src/dbus1-generator/dbus1-generator.c
@@ -58,10 +58,8 @@ static int create_dbus_files(
return log_oom();
f = fopen(a, "wxe");
- if (!f) {
- log_error("Failed to create %s: %m", a);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create %s: %m", a);
fprintf(f,
"# Automatically generated by systemd-dbus1-generator\n\n"
@@ -86,7 +84,7 @@ static int create_dbus_files(
fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
if (streq(type, "system"))
- fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
+ fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n");
else if (streq(type, "session")) {
char *run;
@@ -96,16 +94,14 @@ static int create_dbus_files(
return -EINVAL;
}
- fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
+ fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n",
getuid(), run);
}
}
r = fflush_and_check(f);
- if (r < 0) {
- log_error("Failed to write %s: %s", a, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", a);
fclose(f);
f = NULL;
@@ -118,10 +114,8 @@ static int create_dbus_files(
return log_oom();
f = fopen(b, "wxe");
- if (!f) {
- log_error("Failed to create %s: %m", b);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create %s: %m", b);
fprintf(f,
"# Automatically generated by systemd-dbus1-generator\n\n"
@@ -139,20 +133,16 @@ static int create_dbus_files(
service);
r = fflush_and_check(f);
- if (r < 0) {
- log_error("Failed to write %s: %s", b, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", b);
lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
if (!lnk)
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(b, lnk)) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(b, lnk))
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
return 0;
}
@@ -233,7 +223,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
if (errno == -ENOENT)
return 0;
- log_error("Failed to enumerate D-Bus activated services: %m");
+ log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
return -errno;
}
@@ -252,7 +242,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
return r;
fail:
- log_error("Failed to read D-Bus services directory: %m");
+ log_error_errno(errno, "Failed to read D-Bus services directory: %m");
return -errno;
}
@@ -263,10 +253,8 @@ static int link_busnames_target(const char *units) {
t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
mkdir_parents_label(t, 0755);
- if (symlink(f, t) < 0) {
- log_error("Failed to create symlink %s: %m", t);
- return -errno;
- }
+ if (symlink(f, t) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
return 0;
}
@@ -277,24 +265,18 @@ static int link_compatibility(const char *units) {
f = strappenda(units, "/systemd-bus-proxyd.socket");
t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
mkdir_parents_label(t, 0755);
- if (symlink(f, t) < 0) {
- log_error("Failed to create symlink %s: %m", t);
- return -errno;
- }
+ if (symlink(f, t) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
f = strappenda(units, "/systemd-bus-proxyd.socket");
t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
mkdir_parents_label(t, 0755);
- if (symlink(f, t) < 0) {
- log_error("Failed to create symlink %s: %m", t);
- return -errno;
- }
+ if (symlink(f, t) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
- if (symlink("/dev/null", t) < 0) {
- log_error("Failed to mask %s: %m", t);
- return -errno;
- }
+ if (symlink("/dev/null", t) < 0)
+ return log_error_errno(errno, "Failed to mask %s: %m", t);
return 0;
}
@@ -319,7 +301,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (access("/dev/kdbus/control", F_OK) < 0)
+ if (access("/sys/fs/kdbus/control", F_OK) < 0)
return 0;
r = cg_pid_get_owner_uid(0, NULL);
@@ -331,10 +313,8 @@ int main(int argc, char *argv[]) {
path = "/usr/share/dbus-1/system-services";
type = "system";
units = SYSTEM_DATA_UNIT_PATH;
- } else {
- log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
- return r;
- }
+ } else
+ return log_error_errno(r, "Failed to determine whether we are running as user or system instance: %m");
r = parse_dbus_fragments(path, type);
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index fd7c29d28f..1b9019325c 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -96,7 +96,7 @@ static int generate_mask_symlinks(void) {
return log_oom();
if (symlink("/dev/null", p) < 0) {
- log_error("Failed to create mask symlink %s: %m", p);
+ log_error_errno(errno, "Failed to create mask symlink %s: %m", p);
r = -errno;
}
}
@@ -125,7 +125,7 @@ static int generate_wants_symlinks(void) {
mkdir_parents_label(p, 0755);
if (symlink(f, p) < 0) {
- log_error("Failed to create wants symlink %s: %m", p);
+ log_error_errno(errno, "Failed to create wants symlink %s: %m", p);
r = -errno;
}
}
@@ -150,8 +150,9 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- return EXIT_FAILURE;
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
if (arg_debug_shell) {
r = strv_extend(&arg_wants, "debug-shell.service");
diff --git a/src/delta/delta.c b/src/delta/delta.c
index 25c4a0bcfc..a3a121fb0c 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -185,16 +185,15 @@ static int found_override(const char *top, const char *bottom) {
fflush(stdout);
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork off diff: %m");
- return -errno;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork off diff: %m");
+ else if (pid == 0) {
execlp("diff", "diff", "-us", "--", bottom, top, NULL);
- log_error("Failed to execute diff: %m");
+ log_error_errno(errno, "Failed to execute diff: %m");
_exit(1);
}
- wait_for_terminate_and_warn("diff", pid);
+ wait_for_terminate_and_warn("diff", pid, false);
putchar('\n');
return k;
@@ -226,10 +225,8 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
*c = 0;
r = get_files_in_directory(path, &list);
- if (r < 0){
- log_error("Failed to enumerate %s: %s", path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate %s: %m", path);
STRV_FOREACH(file, list) {
Hashmap *h;
@@ -307,7 +304,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
if (errno == ENOENT)
return 0;
- log_error("Failed to open %s: %m", path);
+ log_error_errno(errno, "Failed to open %s: %m", path);
return -errno;
}
@@ -487,7 +484,7 @@ static int parse_flags(const char *flag_str, int flags) {
const char *word, *state;
size_t l;
- FOREACH_WORD(word, l, flag_str, state) {
+ FOREACH_WORD_SEPARATOR(word, l, flag_str, ",", state) {
if (strneq("masked", word, l))
flags |= SHOW_MASKED;
else if (strneq ("equivalent", word, l))
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index ff5bee56f9..9a924117db 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -131,7 +131,7 @@ int main(int argc, char *argv[]) {
v = detect_virtualization(&id);
if (v < 0) {
- log_error("Failed to check for virtualization: %s", strerror(-v));
+ log_error_errno(v, "Failed to check for virtualization: %m");
return EXIT_FAILURE;
}
@@ -142,7 +142,7 @@ int main(int argc, char *argv[]) {
case ONLY_CONTAINER:
r = detect_container(&id);
if (r < 0) {
- log_error("Failed to check for container: %s", strerror(-r));
+ log_error_errno(r, "Failed to check for container: %m");
return EXIT_FAILURE;
}
@@ -152,7 +152,7 @@ int main(int argc, char *argv[]) {
case ONLY_VM:
r = detect_vm(&id);
if (r < 0) {
- log_error("Failed to check for vm: %s", strerror(-r));
+ log_error_errno(r, "Failed to check for vm: %m");
return EXIT_FAILURE;
}
diff --git a/src/efi-boot-generator/efi-boot-generator.c b/src/efi-boot-generator/efi-boot-generator.c
index d4d778036f..99a819fe37 100644
--- a/src/efi-boot-generator/efi-boot-generator.c
+++ b/src/efi-boot-generator/efi-boot-generator.c
@@ -80,14 +80,14 @@ int main(int argc, char *argv[]) {
log_debug("EFI loader partition unknown, exiting.");
return EXIT_SUCCESS;
} else if (r < 0) {
- log_error("Failed to read ESP partition UUID: %s", strerror(-r));
+ log_error_errno(r, "Failed to read ESP partition UUID: %m");
return EXIT_FAILURE;
}
name = strappenda(arg_dest, "/boot.mount");
f = fopen(name, "wxe");
if (!f) {
- log_error("Failed to create mount unit file %s: %m", name);
+ log_error_errno(errno, "Failed to create mount unit file %s: %m", name);
return EXIT_FAILURE;
}
@@ -120,7 +120,7 @@ int main(int argc, char *argv[]) {
fflush(f);
if (ferror(f)) {
- log_error("Failed to write mount unit file: %m");
+ log_error_errno(errno, "Failed to write mount unit file: %m");
return EXIT_FAILURE;
}
@@ -128,7 +128,7 @@ int main(int argc, char *argv[]) {
fclose(f);
f = fopen(name, "wxe");
if (!f) {
- log_error("Failed to create automount unit file %s: %m", name);
+ log_error_errno(errno, "Failed to create automount unit file %s: %m", name);
return EXIT_FAILURE;
}
@@ -140,7 +140,7 @@ int main(int argc, char *argv[]) {
fflush(f);
if (ferror(f)) {
- log_error("Failed to write automount unit file: %m");
+ log_error_errno(errno, "Failed to write automount unit file: %m");
return EXIT_FAILURE;
}
@@ -148,7 +148,7 @@ int main(int argc, char *argv[]) {
mkdir_parents(name, 0755);
if (symlink("../boot.automount", name) < 0) {
- log_error("Failed to create symlink %s: %m", name);
+ log_error_errno(errno, "Failed to create symlink %s: %m", name);
return EXIT_FAILURE;
}
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 93273d903c..d087ef35e9 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -98,7 +98,7 @@ static void print_welcome(void) {
}
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read os-release file: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read os-release file: %m");
printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n",
isempty(pretty_name) ? "Linux" : pretty_name);
@@ -166,10 +166,8 @@ static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char *
unsigned u;
r = ask_string(&p, "%s %s (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET), text);
- if (r < 0) {
- log_error("Failed to query user: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query user: %m");
if (isempty(p)) {
log_warning("No data entered, skipping.");
@@ -219,10 +217,8 @@ static int prompt_locale(void) {
return 0;
r = get_locales(&locales);
- if (r < 0) {
- log_error("Cannot query locales list: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot query locales list: %m");
print_welcome();
@@ -262,10 +258,8 @@ static int process_locale(void) {
mkdir_parents(etc_localeconf, 0755);
r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644);
if (r != -ENOENT) {
- if (r < 0) {
- log_error("Failed to copy %s: %s", etc_localeconf, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);
log_info("%s copied.", etc_localeconf);
return 0;
@@ -288,10 +282,8 @@ static int process_locale(void) {
mkdir_parents(etc_localeconf, 0755);
r = write_env_file(etc_localeconf, locales);
- if (r < 0) {
- log_error("Failed to write %s: %s", etc_localeconf, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", etc_localeconf);
log_info("%s written.", etc_localeconf);
return 0;
@@ -308,10 +300,8 @@ static int prompt_timezone(void) {
return 0;
r = get_timezones(&zones);
- if (r < 0) {
- log_error("Cannot query timezone list: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot query timezone list: %m");
print_welcome();
@@ -342,16 +332,12 @@ static int process_timezone(void) {
r = readlink_malloc("/etc/localtime", &p);
if (r != -ENOENT) {
- if (r < 0) {
- log_error("Failed to read host timezone: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read host timezone: %m");
mkdir_parents(etc_localtime, 0755);
- if (symlink(p, etc_localtime) < 0) {
- log_error("Failed to create %s symlink: %m", etc_localtime);
- return -errno;
- }
+ if (symlink(p, etc_localtime) < 0)
+ return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
log_info("%s copied.", etc_localtime);
return 0;
@@ -368,10 +354,8 @@ static int process_timezone(void) {
e = strappenda("../usr/share/zoneinfo/", arg_timezone);
mkdir_parents(etc_localtime, 0755);
- if (symlink(e, etc_localtime) < 0) {
- log_error("Failed to create %s symlink: %m", etc_localtime);
- return -errno;
- }
+ if (symlink(e, etc_localtime) < 0)
+ return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);
log_info("%s written", etc_localtime);
return 0;
@@ -393,10 +377,8 @@ static int prompt_hostname(void) {
_cleanup_free_ char *h = NULL;
r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET));
- if (r < 0) {
- log_error("Failed to query hostname: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query hostname: %m");
if (isempty(h)) {
log_warning("No hostname entered, skipping.");
@@ -433,10 +415,8 @@ static int process_hostname(void) {
mkdir_parents(etc_hostname, 0755);
r = write_string_file(etc_hostname, arg_hostname);
- if (r < 0) {
- log_error("Failed to write %s: %s", etc_hostname, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
log_info("%s written.", etc_hostname);
return 0;
@@ -456,10 +436,8 @@ static int process_machine_id(void) {
mkdir_parents(etc_machine_id, 0755);
r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id));
- if (r < 0) {
- log_error("Failed to write machine id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write machine id: %m");
log_info("%s written.", etc_machine_id);
return 0;
@@ -489,10 +467,8 @@ static int prompt_root_password(void) {
_cleanup_free_ char *a = NULL, *b = NULL;
r = ask_password_tty(msg1, 0, false, NULL, &a);
- if (r < 0) {
- log_error("Failed to query root password: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query root password: %m");
if (isempty(a)) {
log_warning("No password entered, skipping.");
@@ -501,7 +477,7 @@ static int prompt_root_password(void) {
r = ask_password_tty(msg2, 0, false, NULL, &b);
if (r < 0) {
- log_error("Failed to query root password: %s", strerror(-r));
+ log_error_errno(r, "Failed to query root password: %m");
clear_string(a);
return r;
}
@@ -586,15 +562,13 @@ static int process_root_password(void) {
if (!errno)
errno = EIO;
- log_error("Failed to find shadow entry for root: %m");
+ log_error_errno(errno, "Failed to find shadow entry for root: %m");
return -errno;
}
r = write_root_shadow(etc_shadow, p);
- if (r < 0) {
- log_error("Failed to write %s: %s", etc_shadow, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", etc_shadow);
log_info("%s copied.", etc_shadow);
return 0;
@@ -609,10 +583,8 @@ static int process_root_password(void) {
return 0;
r = dev_urandom(raw, 16);
- if (r < 0) {
- log_error("Failed to get salt: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get salt: %m");
/* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
assert_cc(sizeof(table) == 64 + 1);
@@ -628,17 +600,15 @@ static int process_root_password(void) {
if (!errno)
errno = -EINVAL;
- log_error("Failed to encrypt password: %m");
+ log_error_errno(errno, "Failed to encrypt password: %m");
return -errno;
}
item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
r = write_root_shadow(etc_shadow, &item);
- if (r < 0) {
- log_error("Failed to write %s: %s", etc_shadow, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write %s: %m", etc_shadow);
log_info("%s written.", etc_shadow);
return 0;
@@ -803,10 +773,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_root_password = NULL;
r = read_one_line_file(optarg, &arg_root_password);
- if (r < 0) {
- log_error("Failed to read %s: %s", optarg, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read %s: %m", optarg);
break;
@@ -870,10 +838,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_SETUP_MACHINE_ID:
r = sd_id128_randomize(&arg_machine_id);
- if (r < 0) {
- log_error("Failed to generate randomized machine ID: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate randomized machine ID: %m");
break;
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 70a591883e..20b7940948 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -35,7 +35,7 @@
#include "special.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "fileio.h"
#include "udev-util.h"
#include "path-util.h"
@@ -54,7 +54,7 @@ static void start_target(const char *target) {
r = bus_open_system_systemd(&bus);
if (r < 0) {
- log_error("Failed to get D-Bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to get D-Bus connection: %m");
return;
}
@@ -236,7 +236,10 @@ int main(int argc, char *argv[]) {
umask(0022);
- parse_proc_cmdline(parse_proc_cmdline_item);
+ q = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (q < 0)
+ log_warning_errno(q, "Failed to parse kernel command line, ignoring: %m");
+
test_files();
if (!arg_force && arg_skip)
@@ -253,7 +256,7 @@ int main(int argc, char *argv[]) {
root_directory = false;
if (stat(device, &st) < 0) {
- log_error("Failed to stat '%s': %m", device);
+ log_error_errno(errno, "Failed to stat '%s': %m", device);
return EXIT_FAILURE;
}
@@ -268,7 +271,7 @@ int main(int argc, char *argv[]) {
/* Find root device */
if (stat("/", &st) < 0) {
- log_error("Failed to stat() the root directory: %m");
+ log_error_errno(errno, "Failed to stat() the root directory: %m");
return EXIT_FAILURE;
}
@@ -306,12 +309,12 @@ int main(int argc, char *argv[]) {
log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
return EXIT_SUCCESS;
} else if (r < 0)
- log_warning("fsck.%s cannot be used for %s: %s", type, device, strerror(-r));
+ log_warning_errno(r, "fsck.%s cannot be used for %s: %m", type, device);
}
if (arg_show_progress)
if (pipe(progress_pipe) < 0) {
- log_error("pipe(): %m");
+ log_error_errno(errno, "pipe(): %m");
return EXIT_FAILURE;
}
@@ -343,7 +346,7 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0) {
- log_error("fork(): %m");
+ log_error_errno(errno, "fork(): %m");
goto finish;
} else if (pid == 0) {
/* Child */
@@ -362,7 +365,7 @@ int main(int argc, char *argv[]) {
q = wait_for_terminate(pid, &status);
if (q < 0) {
- log_error("waitid(): %s", strerror(-q));
+ log_error_errno(q, "waitid(): %m");
goto finish;
}
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index e257c121e5..1f34594928 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -74,11 +74,14 @@ static int mount_find_pri(struct mntent *me, int *ret) {
return 1;
}
-static int add_swap(const char *what, struct mntent *me) {
+static int add_swap(
+ const char *what,
+ struct mntent *me,
+ bool noauto,
+ bool nofail) {
+
_cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
_cleanup_fclose_ FILE *f = NULL;
-
- bool noauto;
int r, pri = -1;
assert(what);
@@ -95,8 +98,6 @@ static int add_swap(const char *what, struct mntent *me) {
return r;
}
- noauto = !!hasmntopt(me, "noauto");
-
name = unit_name_from_path(what, ".swap");
if (!name)
return log_oom();
@@ -110,7 +111,7 @@ static int add_swap(const char *what, struct mntent *me) {
if (errno == EEXIST)
log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
else
- log_error("Failed to create unit file %s: %m", unit);
+ log_error_errno(errno, "Failed to create unit file %s: %m", unit);
return -errno;
}
@@ -132,10 +133,8 @@ static int add_swap(const char *what, struct mntent *me) {
fprintf(f, "Options=%s\n", me->mnt_opts);
r = fflush_and_check(f);
- if (r < 0) {
- log_error("Failed to write unit file %s: %s", unit, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit);
/* use what as where, to have a nicer error message */
r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
@@ -143,15 +142,14 @@ static int add_swap(const char *what, struct mntent *me) {
return r;
if (!noauto) {
- lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
+ lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
+ nofail ? ".wants/" : ".requires/", name, NULL);
if (!lnk)
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(unit, lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
}
return 0;
@@ -229,7 +227,7 @@ static int add_mount(
if (errno == EEXIST)
log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
else
- log_error("Failed to create unit file %s: %m", unit);
+ log_error_errno(errno, "Failed to create unit file %s: %m", unit);
return -errno;
}
@@ -268,10 +266,8 @@ static int add_mount(
fprintf(f, "Options=%s\n", filtered);
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write unit file %s: %m", unit);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
if (!noauto && post) {
lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
@@ -279,10 +275,8 @@ static int add_mount(
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(unit, lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
}
if (automount) {
@@ -296,10 +290,8 @@ static int add_mount(
fclose(f);
f = fopen(automount_unit, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", automount_unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", automount_unit);
fprintf(f,
"# Automatically generated by systemd-fstab-generator\n\n"
@@ -319,10 +311,8 @@ static int add_mount(
where);
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write unit file %s: %m", automount_unit);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write unit file %s: %m", automount_unit);
free(lnk);
lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name, NULL);
@@ -330,10 +320,8 @@ static int add_mount(
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(automount_unit, lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(automount_unit, lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
}
return 0;
@@ -351,12 +339,13 @@ static int parse_fstab(bool initrd) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open %s: %m", fstab_path);
+ log_error_errno(errno, "Failed to open %s: %m", fstab_path);
return -errno;
}
while ((me = getmntent(f))) {
_cleanup_free_ char *where = NULL, *what = NULL;
+ bool noauto, nofail;
int k;
if (initrd && !mount_in_initrd(me))
@@ -378,16 +367,18 @@ static int parse_fstab(bool initrd) {
if (is_path(where))
path_kill_slashes(where);
- log_debug("Found entry what=%s where=%s type=%s", what, where, me->mnt_type);
+ noauto = !!hasmntopt(me, "noauto");
+ nofail = !!hasmntopt(me, "nofail");
+ log_debug("Found entry what=%s where=%s type=%s nofail=%s noauto=%s",
+ what, where, me->mnt_type,
+ yes_no(noauto), yes_no(nofail));
if (streq(me->mnt_type, "swap"))
- k = add_swap(what, me);
+ k = add_swap(what, me, noauto, nofail);
else {
- bool noauto, nofail, automount;
+ bool automount;
const char *post;
- noauto = !!hasmntopt(me, "noauto");
- nofail = !!hasmntopt(me, "nofail");
automount =
hasmntopt(me, "comment=systemd.automount") ||
hasmntopt(me, "x-systemd.automount");
@@ -425,7 +416,7 @@ static int add_root_mount(void) {
const char *opts;
if (isempty(arg_root_what)) {
- log_debug("Could not find a root= entry on the kernel commandline.");
+ log_debug("Could not find a root= entry on the kernel command line.");
return 0;
}
@@ -485,7 +476,7 @@ static int add_usr_mount(void) {
return log_oom();
}
- if (!arg_usr_what || !arg_usr_options)
+ if (!arg_usr_what)
return 0;
what = fstab_node_to_udev_node(arg_usr_what);
@@ -494,7 +485,13 @@ static int add_usr_mount(void) {
return -1;
}
- opts = arg_usr_options;
+ if (!arg_usr_options)
+ opts = arg_root_rw > 0 ? "rw" : "ro";
+ else if (!mount_test_option(arg_usr_options, "ro") &&
+ !mount_test_option(arg_usr_options, "rw"))
+ opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro");
+ else
+ opts = arg_usr_options;
log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
return add_mount(what,
@@ -593,8 +590,9 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- return EXIT_FAILURE;
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
/* Always honour root= and usr= in the kernel command line if we are in an initrd */
if (in_initrd()) {
@@ -625,6 +623,12 @@ int main(int argc, char *argv[]) {
}
free(arg_root_what);
+ free(arg_root_fstype);
+ free(arg_root_options);
+
+ free(arg_usr_what);
+ free(arg_usr_fstype);
+ free(arg_usr_options);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index 06ca9b9662..931651e161 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -52,7 +52,7 @@ static int add_symlink(const char *fservice, const char *tservice) {
/* In case console=hvc0 is passed this will very likely result in EEXIST */
return 0;
else {
- log_error("Failed to create symlink %s: %m", to);
+ log_error_errno(errno, "Failed to create symlink %s: %m", to);
return -errno;
}
}
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 539e2e64b5..32e9b78a1d 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -68,10 +68,8 @@ static int add_swap(const char *path) {
return log_oom();
f = fopen(unit, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
@@ -83,20 +81,16 @@ static int add_swap(const char *path) {
path);
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write unit file %s: %m", unit);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
if (!lnk)
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(unit, lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
return 0;
}
@@ -128,10 +122,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
return log_oom();
f = fopen(p, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", p);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", p);
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
@@ -155,10 +147,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
id);
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write file %s: %m", p);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write file %s: %m", p);
from = strappenda("../", n);
@@ -167,10 +157,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
free(to);
to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
@@ -178,10 +166,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
free(to);
to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
@@ -189,10 +175,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
return log_oom();
mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0) {
- log_error("Failed to create symlink %s: %m", to);
- return -errno;
- }
+ if (symlink(from, to) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
free(p);
p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
@@ -204,10 +188,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
- if (r < 0) {
- log_error("Failed to write device drop-in: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write device drop-in: %m");
ret = strappend("/dev/mapper/", id);
if (!ret)
@@ -256,10 +238,8 @@ static int add_mount(
return log_oom();
f = fopen(p, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
@@ -288,10 +268,8 @@ static int add_mount(
fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
fflush(f);
- if (ferror(f)) {
- log_error("Failed to write unit file %s: %m", p);
- return -errno;
- }
+ if (ferror(f))
+ return log_error_errno(errno, "Failed to write unit file %s: %m", p);
if (post) {
lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
@@ -299,10 +277,8 @@ static int add_mount(
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(p, lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(p, lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
}
return 0;
@@ -339,7 +315,7 @@ static int probe_and_add_mount(
if (!b) {
if (errno == 0)
return log_oom();
- log_error("Failed to allocate prober: %m");
+ log_error_errno(errno, "Failed to allocate prober: %m");
return -errno;
}
@@ -353,7 +329,7 @@ static int probe_and_add_mount(
else if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error("Failed to probe %s: %m", what);
+ log_error_errno(errno, "Failed to probe %s: %m", what);
return -errno;
}
@@ -431,7 +407,7 @@ static int enumerate_partitions(dev_t devnum) {
if (errno == 0)
return log_oom();
- log_error("Failed allocate prober: %m");
+ log_error_errno(errno, "Failed allocate prober: %m");
return -errno;
}
@@ -445,7 +421,7 @@ static int enumerate_partitions(dev_t devnum) {
else if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error("Failed to probe %s: %m", node);
+ log_error_errno(errno, "Failed to probe %s: %m", node);
return -errno;
}
@@ -454,7 +430,7 @@ static int enumerate_partitions(dev_t devnum) {
if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error("Failed to determine partition table type of %s: %m", node);
+ log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
return -errno;
}
@@ -470,7 +446,7 @@ static int enumerate_partitions(dev_t devnum) {
if (errno == 0)
return log_oom();
- log_error("Failed to list partitions of %s: %m", node);
+ log_error_errno(errno, "Failed to list partitions of %s: %m", node);
return -errno;
}
@@ -487,10 +463,8 @@ static int enumerate_partitions(dev_t devnum) {
return log_oom();
r = udev_enumerate_scan_devices(e);
- if (r < 0) {
- log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
@@ -680,8 +654,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
r = parse_boolean(value);
if (r < 0)
log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
-
- arg_enabled = r;
+ else
+ arg_enabled = r;
} else if (streq(key, "root") && value) {
@@ -712,10 +686,8 @@ static int add_root_mount(void) {
if (r == -ENOENT) {
log_debug("EFI loader partition unknown, exiting.");
return 0;
- } else if (r < 0) {
- log_error("Failed to read ESP partition UUID: %s", strerror(-r));
- return r;
- }
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to read ESP partition UUID: %m");
/* OK, we have an ESP partition, this is fantastic, so let's
* wait for a root device to show up. A udev rule will create
@@ -739,10 +711,9 @@ static int add_mounts(void) {
int r;
r = get_block_device("/", &devno);
- if (r < 0) {
- log_error("Failed to determine block device of root file system: %s", strerror(-r));
- return r;
- } else if (r == 0) {
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine block device of root file system: %m");
+ else if (r == 0) {
log_debug("Root file system not on a (single) block device.");
return 0;
}
@@ -772,8 +743,9 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- return EXIT_FAILURE;
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
if (!arg_enabled) {
log_debug("Disabled, exiting.");
diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c
index f40721662e..0207346b28 100644
--- a/src/hibernate-resume/hibernate-resume-generator.c
+++ b/src/hibernate-resume/hibernate-resume-generator.c
@@ -45,6 +45,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
static int process_resume(void) {
_cleanup_free_ char *name = NULL, *lnk = NULL;
+ if (!arg_resume_dev)
+ return 0;
+
name = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service");
if (!name)
return log_oom();
@@ -54,10 +57,8 @@ static int process_resume(void) {
return log_oom();
mkdir_parents_label(lnk, 0755);
- if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-hibernate-resume@.service", lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-hibernate-resume@.service", lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
return 0;
}
@@ -83,12 +84,11 @@ int main(int argc, char *argv[]) {
if (!in_initrd())
return EXIT_SUCCESS;
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- return EXIT_FAILURE;
-
- if (arg_resume_dev != NULL)
- r = process_resume();
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+ r = process_resume();
free(arg_resume_dev);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index b234a0b49a..f28eabbe37 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -53,7 +53,7 @@ int main(int argc, char *argv[]) {
device = argv[1];
if (stat(device, &st) < 0) {
- log_error("Failed to stat '%s': %m", device);
+ log_error_errno(errno, "Failed to stat '%s': %m", device);
return EXIT_FAILURE;
}
@@ -69,7 +69,7 @@ int main(int argc, char *argv[]) {
r = write_string_file("/sys/power/resume", major_minor);
if (r < 0) {
- log_error("Failed to write '%s' to /sys/power/resume: %s", major_minor, strerror(-r));
+ log_error_errno(r, "Failed to write '%s' to /sys/power/resume: %m", major_minor);
return EXIT_FAILURE;
}
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index e48736920f..b3ce8510ba 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -529,12 +529,12 @@ int main(int argc, char *argv[]) {
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
r = hostnamectl_main(bus, argc, argv);
finish:
- return r < 0 ? EXIT_FAILURE : r;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index a449610bb8..0b38cde169 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -138,7 +138,8 @@ static bool valid_chassis(const char *chassis) {
"server\0"
"tablet\0"
"handset\0"
- "watch\0",
+ "watch\0"
+ "embedded\0",
chassis);
}
@@ -441,7 +442,7 @@ static int method_set_hostname(sd_bus *bus, sd_bus_message *m, void *userdata, s
r = context_update_kernel_hostname(c);
if (r < 0) {
- log_error("Failed to set host name: %s", strerror(-r));
+ log_error_errno(r, "Failed to set host name: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
}
@@ -493,13 +494,13 @@ static int method_set_static_hostname(sd_bus *bus, sd_bus_message *m, void *user
r = context_update_kernel_hostname(c);
if (r < 0) {
- log_error("Failed to set host name: %s", strerror(-r));
+ log_error_errno(r, "Failed to set host name: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %s", strerror(-r));
}
r = context_write_data_static_hostname(c);
if (r < 0) {
- log_error("Failed to write static host name: %s", strerror(-r));
+ log_error_errno(r, "Failed to write static host name: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %s", strerror(-r));
}
@@ -572,7 +573,7 @@ static int set_machine_info(Context *c, sd_bus *bus, sd_bus_message *m, int prop
r = context_write_data_machine_info(c);
if (r < 0) {
- log_error("Failed to write machine info: %s", strerror(-r));
+ log_error_errno(r, "Failed to write machine info: %m");
return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %s", strerror(-r));
}
@@ -644,28 +645,20 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
assert(_bus);
r = sd_bus_default_system(&bus);
- if (r < 0) {
- log_error("Failed to get system bus connection: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get system bus connection: %m");
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
- if (r < 0) {
- log_error("Failed to register object: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register object: %m");
r = sd_bus_request_name(bus, "org.freedesktop.hostname1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(bus, event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
*_bus = bus;
bus = NULL;
@@ -700,7 +693,7 @@ int main(int argc, char *argv[]) {
r = sd_event_default(&event);
if (r < 0) {
- log_error("Failed to allocate event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate event loop: %m");
goto finish;
}
@@ -712,13 +705,13 @@ int main(int argc, char *argv[]) {
r = context_read_data(&context);
if (r < 0) {
- log_error("Failed to read hostname and machine information: %s", strerror(-r));
+ log_error_errno(r, "Failed to read hostname and machine information: %m");
goto finish;
}
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index f1c2b8dfb4..d7cd4ba29f 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -162,7 +162,7 @@ static void request_process(Server *s, const struct init_request *req) {
case 'u':
case 'U':
if (kill(1, SIGTERM) < 0)
- log_error("kill() failed: %m");
+ log_error_errno(errno, "kill() failed: %m");
/* The bus connection will be
* terminated if PID 1 is reexecuted,
@@ -175,7 +175,7 @@ static void request_process(Server *s, const struct init_request *req) {
case 'q':
case 'Q':
if (kill(1, SIGHUP) < 0)
- log_error("kill() failed: %m");
+ log_error_errno(errno, "kill() failed: %m");
break;
default:
@@ -217,7 +217,7 @@ static int fifo_process(Fifo *f) {
if (errno == EAGAIN)
return 0;
- log_warning("Failed to read from fifo: %m");
+ log_warning_errno(errno, "Failed to read from fifo: %m");
return -errno;
}
@@ -277,7 +277,7 @@ static int server_init(Server *s, unsigned n_sockets) {
s->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (s->epoll_fd < 0) {
r = -errno;
- log_error("Failed to create epoll object: %m");
+ log_error_errno(errno, "Failed to create epoll object: %m");
goto fail;
}
@@ -290,8 +290,7 @@ static int server_init(Server *s, unsigned n_sockets) {
r = sd_is_fifo(fd, NULL);
if (r < 0) {
- log_error("Failed to determine file descriptor type: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to determine file descriptor type: %m");
goto fail;
}
@@ -304,7 +303,7 @@ static int server_init(Server *s, unsigned n_sockets) {
f = new0(Fifo, 1);
if (!f) {
r = -ENOMEM;
- log_error("Failed to create fifo object: %m");
+ log_error_errno(errno, "Failed to create fifo object: %m");
goto fail;
}
@@ -316,7 +315,7 @@ static int server_init(Server *s, unsigned n_sockets) {
if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
r = -errno;
fifo_free(f);
- log_error("Failed to add fifo fd to epoll object: %m");
+ log_error_errno(errno, "Failed to add fifo fd to epoll object: %m");
goto fail;
}
@@ -328,7 +327,7 @@ static int server_init(Server *s, unsigned n_sockets) {
r = bus_open_system_systemd(&s->bus);
if (r < 0) {
- log_error("Failed to get D-Bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
goto fail;
}
@@ -355,7 +354,7 @@ static int process_event(Server *s, struct epoll_event *ev) {
f = (Fifo*) ev->data.ptr;
r = fifo_process(f);
if (r < 0) {
- log_info("Got error on fifo: %s", strerror(-r));
+ log_info_errno(r, "Got error on fifo: %m");
fifo_free(f);
return r;
}
@@ -385,7 +384,7 @@ int main(int argc, char *argv[]) {
n = sd_listen_fds(true);
if (n < 0) {
- log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+ log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
return EXIT_FAILURE;
}
@@ -414,7 +413,7 @@ int main(int argc, char *argv[]) {
if (errno == EINTR)
continue;
- log_error("epoll_wait() failed: %m");
+ log_error_errno(errno, "epoll_wait() failed: %m");
goto fail;
}
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index db81fe3ca3..7a99430a63 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -155,14 +155,14 @@ static ssize_t request_reader_entries(
r = sd_journal_next(m->journal);
if (r < 0) {
- log_error("Failed to advance journal pointer: %s", strerror(-r));
+ log_error_errno(r, "Failed to advance journal pointer: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
} else if (r == 0) {
if (m->follow) {
r = sd_journal_wait(m->journal, (uint64_t) -1);
if (r < 0) {
- log_error("Couldn't wait for journal event: %s", strerror(-r));
+ log_error_errno(r, "Couldn't wait for journal event: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -177,7 +177,7 @@ static ssize_t request_reader_entries(
r = sd_journal_test_cursor(m->journal, m->cursor);
if (r < 0) {
- log_error("Failed to test cursor: %s", strerror(-r));
+ log_error_errno(r, "Failed to test cursor: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -198,20 +198,20 @@ static ssize_t request_reader_entries(
else {
m->tmp = tmpfile();
if (!m->tmp) {
- log_error("Failed to create temporary file: %m");
+ log_error_errno(errno, "Failed to create temporary file: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
}
r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, NULL);
if (r < 0) {
- log_error("Failed to serialize item: %s", strerror(-r));
+ log_error_errno(r, "Failed to serialize item: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
sz = ftello(m->tmp);
if (sz == (off_t) -1) {
- log_error("Failed to retrieve file position: %m");
+ log_error_errno(errno, "Failed to retrieve file position: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -219,7 +219,7 @@ static ssize_t request_reader_entries(
}
if (fseeko(m->tmp, pos, SEEK_SET) < 0) {
- log_error("Failed to seek to position: %m");
+ log_error_errno(errno, "Failed to seek to position: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -394,7 +394,7 @@ static int request_parse_arguments_iterator(
r = sd_id128_get_boot(&bid);
if (r < 0) {
- log_error("Failed to get boot ID: %s", strerror(-r));
+ log_error_errno(r, "Failed to get boot ID: %m");
return MHD_NO;
}
@@ -543,7 +543,7 @@ static ssize_t request_reader_fields(
r = sd_journal_enumerate_unique(m->journal, &d, &l);
if (r < 0) {
- log_error("Failed to advance field index: %s", strerror(-r));
+ log_error_errno(r, "Failed to advance field index: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
} else if (r == 0)
return MHD_CONTENT_READER_END_OF_STREAM;
@@ -559,20 +559,20 @@ static ssize_t request_reader_fields(
else {
m->tmp = tmpfile();
if (!m->tmp) {
- log_error("Failed to create temporary file: %m");
+ log_error_errno(errno, "Failed to create temporary file: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
}
r = output_field(m->tmp, m->mode, d, l);
if (r < 0) {
- log_error("Failed to serialize item: %s", strerror(-r));
+ log_error_errno(r, "Failed to serialize item: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
sz = ftello(m->tmp);
if (sz == (off_t) -1) {
- log_error("Failed to retrieve file position: %m");
+ log_error_errno(errno, "Failed to retrieve file position: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -580,7 +580,7 @@ static ssize_t request_reader_fields(
}
if (fseeko(m->tmp, pos, SEEK_SET) < 0) {
- log_error("Failed to seek to position: %m");
+ log_error_errno(errno, "Failed to seek to position: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
}
@@ -909,10 +909,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
r = read_full_file(optarg, &key_pem, NULL);
- if (r < 0) {
- log_error("Failed to read key file: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read key file: %m");
assert(key_pem);
break;
@@ -922,10 +920,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
r = read_full_file(optarg, &cert_pem, NULL);
- if (r < 0) {
- log_error("Failed to read certificate file: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read certificate file: %m");
assert(cert_pem);
break;
@@ -936,10 +932,8 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
r = read_full_file(optarg, &trust_pem, NULL);
- if (r < 0) {
- log_error("Failed to read CA certificate file: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read CA certificate file: %m");
assert(trust_pem);
break;
#else
@@ -992,7 +986,7 @@ int main(int argc, char *argv[]) {
n = sd_listen_fds(1);
if (n < 0) {
- log_error("Failed to determine passed sockets: %s", strerror(-n));
+ log_error_errno(n, "Failed to determine passed sockets: %m");
goto finish;
} else if (n > 1) {
log_error("Can't listen on more than one socket.");
diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c
index 7dd8878ca6..76407f711b 100644
--- a/src/journal-remote/journal-remote-parse.c
+++ b/src/journal-remote/journal-remote-parse.c
@@ -125,7 +125,7 @@ static int get_line(RemoteSource *source, char **line, size_t *size) {
source->size - source->filled);
if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK)
- log_error("read(%d, ..., %zd): %m", source->fd,
+ log_error_errno(errno, "read(%d, ..., %zd): %m", source->fd,
source->size - source->filled);
return -errno;
} else if (n == 0)
@@ -186,7 +186,7 @@ static int fill_fixed_size(RemoteSource *source, void **data, size_t size) {
source->size - source->filled);
if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK)
- log_error("read(%d, ..., %zd): %m", source->fd,
+ log_error_errno(errno, "read(%d, ..., %zd): %m", source->fd,
source->size - source->filled);
return -errno;
} else if (n == 0)
@@ -451,8 +451,8 @@ int process_source(RemoteSource *source, bool compress, bool seal) {
r = writer_write(source->writer, &source->iovw, &source->ts, compress, seal);
if (r < 0)
- log_error("Failed to write entry of %zu bytes: %s",
- iovw_size(&source->iovw), strerror(-r));
+ log_error_errno(r, "Failed to write entry of %zu bytes: %m",
+ iovw_size(&source->iovw));
else
r = 1;
diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c
index 0139f851a5..df30049397 100644
--- a/src/journal-remote/journal-remote-write.c
+++ b/src/journal-remote/journal-remote-write.c
@@ -59,11 +59,9 @@ static int do_rotate(JournalFile **f, bool compress, bool seal) {
int r = journal_file_rotate(f, compress, seal);
if (r < 0) {
if (*f)
- log_error("Failed to rotate %s: %s", (*f)->path,
- strerror(-r));
+ log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
else
- log_error("Failed to create rotated journal: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to create rotated journal: %m");
}
return r;
@@ -153,7 +151,7 @@ int writer_write(Writer *w,
return 1;
}
- log_debug("%s: Write failed, rotating: %s", w->journal->path, strerror(-r));
+ log_debug_errno(r, "%s: Write failed, rotating: %m", w->journal->path);
r = do_rotate(&w->journal, compress, seal);
if (r < 0)
return r;
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index dc7120bbd5..6ec5ad2e77 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -84,17 +84,15 @@ static int spawn_child(const char* child, char** argv) {
pid_t parent_pid, child_pid;
int r;
- if (pipe(fd) < 0) {
- log_error("Failed to create pager pipe: %m");
- return -errno;
- }
+ if (pipe(fd) < 0)
+ return log_error_errno(errno, "Failed to create pager pipe: %m");
parent_pid = getpid();
child_pid = fork();
if (child_pid < 0) {
r = -errno;
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
safe_close_pair(fd);
return r;
}
@@ -103,7 +101,7 @@ static int spawn_child(const char* child, char** argv) {
if (child_pid == 0) {
r = dup2(fd[1], STDOUT_FILENO);
if (r < 0) {
- log_error("Failed to dup pipe to stdout: %m");
+ log_error_errno(errno, "Failed to dup pipe to stdout: %m");
_exit(EXIT_FAILURE);
}
@@ -119,13 +117,13 @@ static int spawn_child(const char* child, char** argv) {
_exit(EXIT_SUCCESS);
execvp(child, argv);
- log_error("Failed to exec child %s: %m", child);
+ log_error_errno(errno, "Failed to exec child %s: %m", child);
_exit(EXIT_FAILURE);
}
r = close(fd[1]);
if (r < 0)
- log_warning("Failed to close write end of pipe: %m");
+ log_warning_errno(errno, "Failed to close write end of pipe: %m");
return fd[0];
}
@@ -140,7 +138,7 @@ static int spawn_curl(const char* url) {
r = spawn_child("curl", argv);
if (r < 0)
- log_error("Failed to spawn curl: %m");
+ log_error_errno(errno, "Failed to spawn curl: %m");
return r;
}
@@ -149,21 +147,17 @@ static int spawn_getter(const char *getter, const char *url) {
_cleanup_strv_free_ char **words = NULL;
assert(getter);
- r = strv_split_quoted(&words, getter);
- if (r < 0) {
- log_error("Failed to split getter option: %s", strerror(-r));
- return r;
- }
+ r = strv_split_quoted(&words, getter, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to split getter option: %m");
r = strv_extend(&words, url);
- if (r < 0) {
- log_error("Failed to create command line: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create command line: %m");
r = spawn_child(words[0], words);
if (r < 0)
- log_error("Failed to spawn getter %s: %m", getter);
+ log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
return r;
}
@@ -210,8 +204,8 @@ static int open_output(Writer *w, const char* host) {
w->mmap,
NULL, &w->journal);
if (r < 0)
- log_error("Failed to open output journal %s: %s",
- output, strerror(-r));
+ log_error_errno(r, "Failed to open output journal %s: %m",
+ output);
else
log_info("Opened output file %s", w->journal->path);
return r;
@@ -320,11 +314,9 @@ static int get_source_for_fd(RemoteServer *s,
return log_oom();
r = get_writer(s, name, &writer);
- if (r < 0) {
- log_warning("Failed to get writer for source %s: %s",
- name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to get writer for source %s: %m",
+ name);
if (s->sources[fd] == NULL) {
s->sources[fd] = source_new(fd, false, name, writer);
@@ -376,8 +368,8 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
r = get_source_for_fd(s, fd, name, &source);
if (r < 0) {
- log_error("Failed to create source for fd:%d (%s): %s",
- fd, name, strerror(-r));
+ log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
+ fd, name);
free(name);
return r;
}
@@ -393,14 +385,14 @@ static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
sd_event_source_set_enabled(source->event, SD_EVENT_ON);
}
if (r < 0) {
- log_error("Failed to register event source for fd:%d: %s",
- fd, strerror(-r));
+ log_error_errno(r, "Failed to register event source for fd:%d: %m",
+ fd);
goto error;
}
- r = sd_event_source_set_name(source->event, name);
+ r = sd_event_source_set_description(source->event, name);
if (r < 0) {
- log_error("Failed to set source name for fd:%d: %s", fd, strerror(-r));
+ log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
goto error;
}
@@ -426,7 +418,7 @@ static int add_raw_socket(RemoteServer *s, int fd) {
snprintf(name, sizeof(name), "raw-socket-%d", fd);
- r = sd_event_source_set_name(s->listen_event, name);
+ r = sd_event_source_set_description(s->listen_event, name);
if (r < 0)
return r;
@@ -459,11 +451,9 @@ static int request_meta(void **connection_cls, int fd, char *hostname) {
return 0;
r = get_writer(server, hostname, &writer);
- if (r < 0) {
- log_warning("Failed to get writer for source %s: %s",
- hostname, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to get writer for source %s: %m",
+ hostname);
source = source_new(fd, true, hostname, writer);
if (!source) {
@@ -661,10 +651,8 @@ static int setup_microhttpd_server(RemoteServer *s,
assert(fd >= 0);
r = fd_nonblock(fd, true);
- if (r < 0) {
- log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
if (key) {
assert(cert);
@@ -720,13 +708,13 @@ static int setup_microhttpd_server(RemoteServer *s,
epoll_fd, EPOLLIN,
dispatch_http_event, d);
if (r < 0) {
- log_error("Failed to add event callback: %s", strerror(-r));
+ log_error_errno(r, "Failed to add event callback: %m");
goto error;
}
- r = sd_event_source_set_name(d->event, "epoll-fd");
+ r = sd_event_source_set_description(d->event, "epoll-fd");
if (r < 0) {
- log_error("Failed to set source name: %s", strerror(-r));
+ log_error_errno(r, "Failed to set source name: %m");
goto error;
}
@@ -738,7 +726,7 @@ static int setup_microhttpd_server(RemoteServer *s,
r = hashmap_put(s->daemons, &d->fd, d);
if (r < 0) {
- log_error("Failed to add daemon to hashmap: %s", strerror(-r));
+ log_error_errno(r, "Failed to add daemon to hashmap: %m");
goto error;
}
@@ -803,18 +791,10 @@ static int setup_signals(RemoteServer *s) {
if (r < 0)
return r;
- r = sd_event_source_set_name(s->sigterm_event, "sigterm");
- if (r < 0)
- return r;
-
r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
if (r < 0)
return r;
- r = sd_event_source_set_name(s->sigint_event, "sigint");
- if (r < 0)
- return r;
-
return 0;
}
@@ -848,10 +828,8 @@ static int remoteserver_init(RemoteServer *s,
}
r = sd_event_default(&s->events);
- if (r < 0) {
- log_error("Failed to allocate event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate event loop: %m");
setup_signals(s);
@@ -863,11 +841,9 @@ static int remoteserver_init(RemoteServer *s,
return r;
n = sd_listen_fds(true);
- if (n < 0) {
- log_error("Failed to read listening file descriptors from environment: %s",
- strerror(-n));
- return n;
- } else
+ if (n < 0)
+ return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
+ else
log_info("Received %d descriptors", n);
if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
@@ -889,10 +865,8 @@ static int remoteserver_init(RemoteServer *s,
char *hostname;
r = getnameinfo_pretty(fd, &hostname);
- if (r < 0) {
- log_error("Failed to retrieve remote name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve remote name: %m");
log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
@@ -903,11 +877,9 @@ static int remoteserver_init(RemoteServer *s,
return -EINVAL;
}
- if(r < 0) {
- log_error("Failed to register socket (fd:%d): %s",
- fd, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register socket (fd:%d): %m",
+ fd);
}
if (arg_url) {
@@ -966,10 +938,8 @@ static int remoteserver_init(RemoteServer *s,
log_info("Reading file %s...", *file);
fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
- if (fd < 0) {
- log_error("Failed to open %s: %m", *file);
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", *file);
output_name = *file;
}
@@ -1059,7 +1029,7 @@ static int dispatch_raw_source_event(sd_event_source *event,
} else if (r == -EAGAIN) {
return 0;
} else if (r < 0) {
- log_info("Closing connection: %s", strerror(-r));
+ log_info_errno(r, "Closing connection: %m");
remove_source(server, fd);
return 0;
} else
@@ -1079,10 +1049,8 @@ static int accept_connection(const char* type, int fd,
log_debug("Accepting new %s connection on fd:%d", type, fd);
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
- if (fd2 < 0) {
- log_error("accept() on fd:%d failed: %m", fd);
- return -errno;
- }
+ if (fd2 < 0)
+ return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
switch(socket_address_family(addr)) {
case AF_INET:
@@ -1092,7 +1060,7 @@ static int accept_connection(const char* type, int fd,
r = socket_address_print(addr, &a);
if (r < 0) {
- log_error("socket_address_print(): %s", strerror(-r));
+ log_error_errno(r, "socket_address_print(): %m");
close(fd2);
return r;
}
@@ -1163,10 +1131,10 @@ static int parse_config(void) {
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
- return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
- "Remote\0",
- config_item_table_lookup, items,
- false, false, true, NULL);
+ return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf",
+ CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
+ "Remote\0", config_item_table_lookup, items,
+ false, NULL);
}
static void help(void) {
@@ -1469,28 +1437,22 @@ static int load_certificates(char **key, char **cert, char **trust) {
int r;
r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
- if (r < 0) {
- log_error("Failed to read key from file '%s': %s",
- arg_key ?: PRIV_KEY_FILE, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read key from file '%s': %m",
+ arg_key ?: PRIV_KEY_FILE);
r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
- if (r < 0) {
- log_error("Failed to read certificate from file '%s': %s",
- arg_cert ?: CERT_FILE, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read certificate from file '%s': %m",
+ arg_cert ?: CERT_FILE);
if (arg_trust_all)
log_info("Certificate checking disabled.");
else {
r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
- if (r < 0) {
- log_error("Failed to read CA certificate file '%s': %s",
- arg_trust ?: TRUST_FILE, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
+ arg_trust ?: TRUST_FILE);
}
return 0;
@@ -1550,7 +1512,7 @@ int main(int argc, char **argv) {
r = sd_event_set_watchdog(s.events, true);
if (r < 0)
- log_error("Failed to enable watchdog: %s", strerror(-r));
+ log_error_errno(r, "Failed to enable watchdog: %m");
else
log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
@@ -1569,7 +1531,7 @@ int main(int argc, char **argv) {
r = sd_event_run(s.events, -1);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
break;
}
}
diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c
index 1cd52db2c1..942320cbf6 100644
--- a/src/journal-remote/journal-upload-journal.c
+++ b/src/journal-remote/journal-upload-journal.c
@@ -25,10 +25,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
u->current_cursor = NULL;
r = sd_journal_get_cursor(u->journal, &u->current_cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
r = snprintf(buf + pos, size - pos,
"__CURSOR=%s\n", u->current_cursor);
@@ -51,10 +49,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
usec_t realtime;
r = sd_journal_get_realtime_usec(u->journal, &realtime);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
r = snprintf(buf + pos, size - pos,
"__REALTIME_TIMESTAMP="USEC_FMT"\n", realtime);
@@ -78,10 +74,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
sd_id128_t boot_id;
r = sd_journal_get_monotonic_usec(u->journal, &monotonic, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = snprintf(buf + pos, size - pos,
"__MONOTONIC_TIMESTAMP="USEC_FMT"\n", monotonic);
@@ -105,10 +99,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
char sid[33];
r = sd_journal_get_monotonic_usec(u->journal, NULL, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = snprintf(buf + pos, size - pos,
"_BOOT_ID=%s\n", sd_id128_to_string(boot_id, sid));
@@ -133,11 +125,9 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
r = sd_journal_enumerate_data(u->journal,
&u->field_data,
&u->field_length);
- if (r < 0) {
- log_error("Failed to move to next field in entry: %s",
- strerror(-r));
- return r;
- } else if (r == 0) {
+ if (r < 0)
+ return log_error_errno(r, "Failed to move to next field in entry: %m");
+ else if (r == 0) {
u->entry_state = ENTRY_OUTRO;
continue;
}
@@ -250,8 +240,7 @@ static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void
if (u->entry_state == ENTRY_DONE) {
r = sd_journal_next(j);
if (r < 0) {
- log_error("Failed to move to next entry in journal: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to move to next entry in journal: %m");
return CURL_READFUNC_ABORT;
} else if (r == 0) {
if (u->input_event)
@@ -304,10 +293,9 @@ static int process_journal_input(Uploader *u, int skip) {
int r;
r = sd_journal_next_skip(u->journal, skip);
- if (r < 0) {
- log_error("Failed to skip to next entry: %s", strerror(-r));
- return r;
- } else if (r < skip)
+ if (r < 0)
+ return log_error_errno(r, "Failed to skip to next entry: %m");
+ else if (r < skip)
return 0;
/* have data */
@@ -321,7 +309,7 @@ int check_journal_input(Uploader *u) {
r = sd_journal_process(u->journal);
if (r < 0) {
- log_error("Failed to process journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to process journal: %m");
close_journal_input(u);
return r;
}
@@ -363,10 +351,8 @@ int open_journal_for_upload(Uploader *u,
if (follow) {
fd = sd_journal_get_fd(j);
- if (fd < 0) {
- log_error("sd_journal_get_fd failed: %s", strerror(-fd));
- return fd;
- }
+ if (fd < 0)
+ return log_error_errno(fd, "sd_journal_get_fd failed: %m");
events = sd_journal_get_events(j);
@@ -379,10 +365,8 @@ int open_journal_for_upload(Uploader *u,
r = sd_event_add_io(u->events, &u->input_event,
fd, events, dispatch_journal_input, u);
- if (r < 0) {
- log_error("Failed to register input event: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register input event: %m");
log_debug("Listening for journal events on fd:%d, timeout %d",
fd, u->timeout == (uint64_t) -1 ? -1 : (int) u->timeout);
@@ -392,9 +376,8 @@ int open_journal_for_upload(Uploader *u,
if (cursor) {
r = sd_journal_seek_cursor(j, cursor);
if (r < 0) {
- log_error("Failed to seek to cursor %s: %s",
- cursor, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to seek to cursor %s: %m",
+ cursor);
}
}
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 9f13ffdbfe..62853b6367 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -87,8 +87,8 @@ static size_t output_callback(char *buf,
if (nmemb && !u->answer) {
u->answer = strndup(buf, size*nmemb);
if (!u->answer)
- log_warning("Failed to store server answer (%zu bytes): %s",
- size*nmemb, strerror(ENOMEM));
+ log_warning_errno(ENOMEM, "Failed to store server answer (%zu bytes): %m",
+ size*nmemb);
}
return size * nmemb;
@@ -103,18 +103,14 @@ static int check_cursor_updating(Uploader *u) {
return 0;
r = mkdir_parents(u->state_file, 0755);
- if (r < 0) {
- log_error("Cannot create parent directory of state file %s: %s",
- u->state_file, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot create parent directory of state file %s: %m",
+ u->state_file);
r = fopen_temporary(u->state_file, &f, &temp_path);
- if (r < 0) {
- log_error("Cannot save state to %s: %s",
- u->state_file, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot save state to %s: %m",
+ u->state_file);
unlink(temp_path);
return 0;
@@ -147,7 +143,7 @@ static int update_cursor_state(Uploader *u) {
finish:
if (r < 0)
- log_error("Failed to save state %s: %s", u->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save state %s: %m", u->state_file);
return r;
}
@@ -164,11 +160,10 @@ static int load_cursor_state(Uploader *u) {
if (r == -ENOENT)
log_debug("State file %s is not present.", u->state_file);
- else if (r < 0) {
- log_error("Failed to read state file %s: %s",
- u->state_file, strerror(-r));
- return r;
- } else
+ else if (r < 0)
+ return log_error_errno(r, "Failed to read state file %s: %m",
+ u->state_file);
+ else
log_debug("Last cursor was %s", u->last_cursor);
return 0;
@@ -313,7 +308,7 @@ static size_t fd_input_callback(void *buf, size_t size, size_t nmemb, void *user
close_fd_input(u);
return 0;
} else {
- log_error("Aborting transfer after read error on input: %m.");
+ log_error_errno(errno, "Aborting transfer after read error on input: %m.");
return CURL_READFUNC_ABORT;
}
}
@@ -362,10 +357,8 @@ static int open_file_for_upload(Uploader *u, const char *filename) {
fd = STDIN_FILENO;
else {
fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- log_error("Failed to open %s: %m", filename);
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", filename);
}
u->input = fd;
@@ -374,10 +367,8 @@ static int open_file_for_upload(Uploader *u, const char *filename) {
r = sd_event_add_io(u->events, &u->input_event,
fd, EPOLLIN, dispatch_fd_input, u);
if (r < 0) {
- if (r != -EPERM || arg_follow > 0) {
- log_error("Failed to register input event: %s", strerror(-r));
- return r;
- }
+ if (r != -EPERM || arg_follow > 0)
+ return log_error_errno(r, "Failed to register input event: %m");
/* Normal files should just be consumed without polling. */
r = start_upload(u, fd_input_callback, u);
@@ -458,16 +449,12 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file)
u->state_file = state_file;
r = sd_event_default(&u->events);
- if (r < 0) {
- log_error("sd_event_default failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "sd_event_default failed: %m");
r = setup_signals(u);
- if (r < 0) {
- log_error("Failed to set up signals: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up signals: %m");
return load_cursor_state(u);
}
@@ -545,10 +532,10 @@ static int parse_config(void) {
{ "Upload", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
- return config_parse(NULL, PKGSYSCONFDIR "/journal-upload.conf", NULL,
- "Upload\0",
- config_item_table_lookup, items,
- false, false, true, NULL);
+ return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf",
+ CONF_DIRS_NULSTR("systemd/journal-upload.conf"),
+ "Upload\0", config_item_table_lookup, items,
+ false, NULL);
}
static void help(void) {
@@ -701,10 +688,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_FILE:
r = glob_extend(&arg_file, optarg);
- if (r < 0) {
- log_error("Failed to add paths: %s", strerror(-r));
- return r;
- };
+ if (r < 0)
+ return log_error_errno(r, "Failed to add paths: %m");
break;
case ARG_CURSOR:
@@ -786,9 +771,8 @@ static int open_journal(sd_journal **j) {
else
r = sd_journal_open(j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
if (r < 0)
- log_error("Failed to open %s: %s",
- arg_directory ? arg_directory : arg_file ? "files" : "journal",
- strerror(-r));
+ log_error_errno(r, "Failed to open %s: %m",
+ arg_directory ? arg_directory : arg_file ? "files" : "journal");
return r;
}
@@ -869,7 +853,7 @@ int main(int argc, char **argv) {
r = sd_event_run(u.events, u.timeout);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
break;
}
}
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index 55c45f4693..277e125403 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -41,7 +41,7 @@ void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
f = strappenda("microhttpd: ", fmt);
DISABLE_WARNING_FORMAT_NONLITERAL;
- log_metav(LOG_INFO, NULL, 0, NULL, f, ap);
+ log_internalv(LOG_INFO, 0, NULL, 0, NULL, f, ap);
REENABLE_WARNING;
}
@@ -126,11 +126,10 @@ void log_func_gnutls(int level, const char *message) {
if (0 <= level && level < (int) ELEMENTSOF(gnutls_log_map)) {
if (gnutls_log_map[level].enabled)
- log_meta(gnutls_log_map[level].level, NULL, 0, NULL,
- "gnutls %d/%s: %s", level, gnutls_log_map[level].names[1], message);
+ log_internal(gnutls_log_map[level].level, 0, NULL, 0, NULL, "gnutls %d/%s: %s", level, gnutls_log_map[level].names[1], message);
} else {
log_debug("Received GNUTLS message with unknown level %d.", level);
- log_meta(LOG_DEBUG, NULL, 0, NULL, "gnutls: %s", message);
+ log_internal(LOG_DEBUG, 0, NULL, 0, NULL, "gnutls: %s", message);
}
}
@@ -171,17 +170,13 @@ static int verify_cert_authorized(gnutls_session_t session) {
int r;
r = gnutls_certificate_verify_peers2(session, &status);
- if (r < 0) {
- log_error("gnutls_certificate_verify_peers2 failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "gnutls_certificate_verify_peers2 failed: %m");
type = gnutls_certificate_type_get(session);
r = gnutls_certificate_verification_status_print(status, type, &out, 0);
- if (r < 0) {
- log_error("gnutls_certificate_verification_status_print failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "gnutls_certificate_verification_status_print failed: %m");
log_info("Certificate status: %s", out.data);
diff --git a/src/journal/cat.c b/src/journal/cat.c
index 627c0624a5..79706b692d 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -134,7 +134,7 @@ int main(int argc, char *argv[]) {
fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
if (fd < 0) {
- log_error("Failed to create stream fd: %s", strerror(-fd));
+ log_error_errno(fd, "Failed to create stream fd: %m");
r = fd;
goto finish;
}
@@ -143,7 +143,7 @@ int main(int argc, char *argv[]) {
if (dup3(fd, STDOUT_FILENO, 0) < 0 ||
dup3(fd, STDERR_FILENO, 0) < 0) {
- log_error("Failed to duplicate fd: %m");
+ log_error_errno(errno, "Failed to duplicate fd: %m");
r = -errno;
goto finish;
}
@@ -164,7 +164,7 @@ int main(int argc, char *argv[]) {
if (saved_stderr >= 0)
dup3(saved_stderr, STDERR_FILENO, 0);
- log_error("Failed to execute process: %s", strerror(-r));
+ log_error_errno(r, "Failed to execute process: %m");
finish:
safe_close(fd);
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index 41d450b154..81a2e946e4 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -209,14 +209,12 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
assert(path);
f = fopen(path, "re");
- if (!f) {
- log_error("Failed to open file %s: %m", path);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to open file %s: %m", path);
r = catalog_file_lang(path, &deflang);
if (r < 0)
- log_error("Failed to determine language for file %s: %m", path);
+ log_error_errno(errno, "Failed to determine language for file %s: %m", path);
if (r == 1)
log_debug("File %s has language %s.", path, deflang);
@@ -229,7 +227,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
if (feof(f))
break;
- log_error("Failed to read file %s: %m", path);
+ log_error_errno(errno, "Failed to read file %s: %m", path);
return -errno;
}
@@ -341,17 +339,13 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
return log_oom();
r = mkdir_p(d, 0775);
- if (r < 0) {
- log_error("Recursive mkdir %s: %s", d, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Recursive mkdir %s: %m", d);
r = fopen_temporary(database, &w, &p);
- if (r < 0) {
- log_error("Failed to open database for writing: %s: %s",
- database, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open database for writing: %s: %m",
+ database);
zero(header);
memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
@@ -389,7 +383,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
fchmod(fileno(w), 0644);
if (rename(p, database) < 0) {
- log_error("rename (%s -> %s) failed: %m", p, database);
+ log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
r = -errno;
goto error;
}
@@ -422,7 +416,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
r = conf_files_list_strv(&files, ".catalog", root, dirs);
if (r < 0) {
- log_error("Failed to get catalog files: %s", strerror(-r));
+ log_error_errno(r, "Failed to get catalog files: %m");
goto finish;
}
@@ -463,7 +457,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
r = write_catalog(database, h, sb, items, n);
if (r < 0)
- log_error("Failed to write %s: %s", database, strerror(-r));
+ 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);
@@ -687,8 +681,8 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items
k = sd_id128_from_string(*item, &id);
if (k < 0) {
- log_error("Failed to parse id128 '%s': %s",
- *item, strerror(-k));
+ log_error_errno(k, "Failed to parse id128 '%s': %m",
+ *item);
if (r == 0)
r = k;
continue;
diff --git a/src/journal/compress.c b/src/journal/compress.c
index c4c715be2f..9440fcd60e 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -400,12 +400,9 @@ int compress_stream_xz(int fdf, int fdt, off_t max_bytes) {
n = sizeof(out) - s.avail_out;
- errno = 0;
k = loop_write(fdt, out, n, false);
if (k < 0)
return k;
- if (k != n)
- return errno ? -errno : -EIO;
if (ret == LZMA_STREAM_END) {
log_debug("XZ compression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
@@ -478,8 +475,6 @@ int compress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
n = loop_write(fdt, out, r, false);
if (n < 0)
return n;
- if (n != r)
- return errno ? -errno : -EIO;
total_out += sizeof(header) + r;
@@ -559,12 +554,9 @@ int decompress_stream_xz(int fdf, int fdt, off_t max_bytes) {
max_bytes -= n;
}
- errno = 0;
k = loop_write(fdt, out, n, false);
if (k < 0)
return k;
- if (k != n)
- return errno ? -errno : -EIO;
if (ret == LZMA_STREAM_END) {
log_debug("XZ decompression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
@@ -645,12 +637,9 @@ int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) {
return -EFBIG;
}
- errno = 0;
n = loop_write(fdt, out, r, false);
if (n < 0)
return n;
- if (n != r)
- return errno ? -errno : -EIO;
}
log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c
index fec901e8e4..9b73795e5b 100644
--- a/src/journal/coredump-vacuum.c
+++ b/src/journal/coredump-vacuum.c
@@ -139,10 +139,8 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) {
return 0;
if (exclude_fd >= 0) {
- if (fstat(exclude_fd, &exclude_st) < 0) {
- log_error("Failed to fstat(): %m");
- return -errno;
- }
+ if (fstat(exclude_fd, &exclude_st) < 0)
+ return log_error_errno(errno, "Failed to fstat(): %m");
}
/* This algorithm will keep deleting the oldest file of the
@@ -156,7 +154,7 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) {
if (errno == ENOENT)
return 0;
- log_error("Can't open coredump directory: %m");
+ log_error_errno(errno, "Can't open coredump directory: %m");
return -errno;
}
@@ -258,7 +256,7 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) {
if (errno == ENOENT)
continue;
- log_error("Failed to remove file %s: %m", worst->oldest_file);
+ log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file);
return -errno;
} else
log_info("Removed old coredump %s.", worst->oldest_file);
@@ -267,6 +265,6 @@ int coredump_vacuum(int exclude_fd, off_t keep_free, off_t max_use) {
return 0;
fail:
- log_error("Failed to read directory: %m");
+ log_error_errno(errno, "Failed to read directory: %m");
return -errno;
}
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index 88d720f651..be45a684e5 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -36,6 +36,7 @@
#include "log.h"
#include "util.h"
+#include "fileio.h"
#include "strv.h"
#include "macro.h"
#include "mkdir.h"
@@ -119,10 +120,11 @@ static int parse_config(void) {
{}
};
- return config_parse(NULL, "/etc/systemd/coredump.conf", NULL,
- "Coredump\0",
- config_item_table_lookup, items,
- false, false, true, NULL);
+ return config_parse_many("/etc/systemd/coredump.conf",
+ CONF_DIRS_NULSTR("systemd/coredump.conf"),
+ "Coredump\0",
+ config_item_table_lookup, items,
+ false, NULL);
}
static int fix_acl(int fd, uid_t uid) {
@@ -141,29 +143,25 @@ static int fix_acl(int fd, uid_t uid) {
* their own coredumps */
acl = acl_get_fd(fd);
- if (!acl) {
- log_error("Failed to get ACL: %m");
- return -errno;
- }
+ if (!acl)
+ return log_error_errno(errno, "Failed to get ACL: %m");
if (acl_create_entry(&acl, &entry) < 0 ||
acl_set_tag_type(entry, ACL_USER) < 0 ||
acl_set_qualifier(entry, &uid) < 0) {
- log_error("Failed to patch ACL: %m");
+ log_error_errno(errno, "Failed to patch ACL: %m");
return -errno;
}
if (acl_get_permset(entry, &permset) < 0 ||
acl_add_perm(permset, ACL_READ) < 0 ||
calc_acl_mask_if_needed(&acl) < 0) {
- log_warning("Failed to patch ACL: %m");
+ log_warning_errno(errno, "Failed to patch ACL: %m");
return -errno;
}
- if (acl_set_fd(fd, acl) < 0) {
- log_error("Failed to apply ACL: %m");
- return -errno;
- }
+ if (acl_set_fd(fd, acl) < 0)
+ return log_error_errno(errno, "Failed to apply ACL: %m");
#endif
return 0;
@@ -222,15 +220,11 @@ static int fix_permissions(
fix_acl(fd, uid);
fix_xattr(fd, info);
- if (fsync(fd) < 0) {
- log_error("Failed to sync coredump %s: %m", filename);
- return -errno;
- }
+ if (fsync(fd) < 0)
+ return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
- if (rename(filename, target) < 0) {
- log_error("Failed to rename coredump %s -> %s: %m", filename, target);
- return -errno;
- }
+ if (rename(filename, target) < 0)
+ return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
return 0;
}
@@ -246,10 +240,8 @@ static int maybe_remove_external_coredump(const char *filename, off_t size) {
if (!filename)
return 1;
- if (unlink(filename) < 0 && errno != ENOENT) {
- log_error("Failed to unlink %s: %m", filename);
- return -errno;
- }
+ if (unlink(filename) < 0 && errno != ENOENT)
+ return log_error_errno(errno, "Failed to unlink %s: %m", filename);
return 1;
}
@@ -311,10 +303,8 @@ static int save_external_coredump(
assert(ret_size);
r = make_filename(info, &fn);
- if (r < 0) {
- log_error("Failed to determine coredump file name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine coredump file name: %m");
tmp = tempfn_random(fn);
if (!tmp)
@@ -323,30 +313,28 @@ static int save_external_coredump(
mkdir_p_label("/var/lib/systemd/coredump", 0755);
fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
- if (fd < 0) {
- log_error("Failed to create coredump file %s: %m", tmp);
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max);
- if (r == -E2BIG) {
+ if (r == -EFBIG) {
log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]);
goto fail;
} else if (IN_SET(r, -EDQUOT, -ENOSPC)) {
log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]);
goto fail;
} else if (r < 0) {
- log_error("Failed to dump coredump to file: %s", strerror(-r));
+ log_error_errno(r, "Failed to dump coredump to file: %m");
goto fail;
}
if (fstat(fd, &st) < 0) {
- log_error("Failed to fstat coredump %s: %m", tmp);
+ log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
goto fail;
}
if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
- log_error("Failed to seek on %s: %m", tmp);
+ log_error_errno(errno, "Failed to seek on %s: %m", tmp);
goto fail;
}
@@ -372,13 +360,13 @@ static int save_external_coredump(
fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
if (fd_compressed < 0) {
- log_error("Failed to create file %s: %m", tmp_compressed);
+ log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
goto uncompressed;
}
r = compress_stream(fd, fd_compressed, -1);
if (r < 0) {
- log_error("Failed to compress %s: %s", tmp_compressed, strerror(-r));
+ log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
goto fail_compressed;
}
@@ -430,10 +418,8 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
assert(ret);
assert(ret_size);
- if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
- log_warning("Failed to seek: %m");
- return -errno;
- }
+ if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
+ return log_warning_errno(errno, "Failed to seek: %m");
field = malloc(9 + size);
if (!field) {
@@ -444,10 +430,8 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
memcpy(field, "COREDUMP=", 9);
n = read(fd, field + 9, size);
- if (n < 0) {
- log_error("Failed to read core data: %s", strerror(-n));
- return (int) n;
- }
+ if (n < 0)
+ return log_error_errno((int) n, "Failed to read core data: %m");
if ((size_t) n < size) {
log_error("Core data too short.");
return -EIO;
@@ -461,24 +445,118 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s
return 0;
}
+/* Joins /proc/[pid]/fd/ and /proc/[pid]/fdinfo/ into the following lines:
+ * 0:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ *
+ * 1:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ *
+ * 2:/dev/pts/23
+ * pos: 0
+ * flags: 0100002
+ * EOF
+ */
+static int compose_open_fds(pid_t pid, char **open_fds) {
+ _cleanup_closedir_ DIR *proc_fd_dir = NULL;
+ _cleanup_close_ int proc_fdinfo_fd = -1;
+ _cleanup_free_ char *buffer = NULL;
+ _cleanup_fclose_ FILE *stream = NULL;
+ const char *fddelim = "", *path;
+ struct dirent *dent = NULL;
+ size_t size = 0;
+ int r = 0;
+
+ assert(pid >= 0);
+ assert(open_fds != NULL);
+
+ path = procfs_file_alloca(pid, "fd");
+ proc_fd_dir = opendir(path);
+ if (!proc_fd_dir)
+ return -errno;
+
+ proc_fdinfo_fd = openat(dirfd(proc_fd_dir), "../fdinfo", O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC|O_PATH);
+ if (proc_fdinfo_fd < 0)
+ return -errno;
+
+ stream = open_memstream(&buffer, &size);
+ if (!stream)
+ return -ENOMEM;
+
+ FOREACH_DIRENT(dent, proc_fd_dir, return -errno) {
+ _cleanup_fclose_ FILE *fdinfo = NULL;
+ _cleanup_free_ char *fdname = NULL;
+ char line[LINE_MAX];
+ int fd;
+
+ r = readlinkat_malloc(dirfd(proc_fd_dir), dent->d_name, &fdname);
+ if (r < 0)
+ return r;
+
+ fprintf(stream, "%s%s:%s\n", fddelim, dent->d_name, fdname);
+ fddelim = "\n";
+
+ /* Use the directory entry from /proc/[pid]/fd with /proc/[pid]/fdinfo */
+ fd = openat(proc_fdinfo_fd, dent->d_name, O_NOFOLLOW|O_CLOEXEC|O_RDONLY);
+ if (fd < 0)
+ continue;
+
+ fdinfo = fdopen(fd, "re");
+ if (fdinfo == NULL) {
+ close(fd);
+ continue;
+ }
+
+ FOREACH_LINE(line, fdinfo, break) {
+ fputs(line, stream);
+ if (!endswith(line, "\n"))
+ fputc('\n', stream);
+ }
+ }
+
+ errno = 0;
+ fclose(stream);
+ stream = NULL;
+
+ if (errno != 0)
+ return -errno;
+
+ *open_fds = buffer;
+ buffer = NULL;
+
+ return 0;
+}
+
int main(int argc, char* argv[]) {
- _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
- *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL,
- *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *coredump_data = NULL,
- *core_slice = NULL, *core_cgroup = NULL, *core_owner_uid = NULL,
- *exe = NULL, *comm = NULL, *filename = NULL;
+ /* The small core field we allocate on the stack, to keep things simple */
+ char
+ *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL,
+ *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL,
+ *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL,
+ *core_slice = NULL;
+
+ /* The larger ones we allocate on the heap */
+ _cleanup_free_ char
+ *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL,
+ *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL,
+ *core_proc_cgroup = NULL, *core_environ = NULL;
+
+ _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL;
const char *info[_INFO_LEN];
_cleanup_close_ int coredump_fd = -1;
- struct iovec iovec[18];
+ struct iovec iovec[26];
off_t coredump_size;
int r, j = 0;
uid_t uid, owner_uid;
gid_t gid;
pid_t pid;
char *t;
+ const char *p;
/* Make sure we never enter a loop */
prctl(PR_SET_DUMPABLE, 0);
@@ -521,7 +599,7 @@ int main(int argc, char* argv[]) {
}
if (get_process_comm(pid, &comm) < 0) {
- log_warning("Failed to get COMM, falling back to the commandline.");
+ log_warning("Failed to get COMM, falling back to the command line.");
comm = strv_join(argv + INFO_COMM + 1, " ");
}
@@ -539,6 +617,7 @@ int main(int argc, char* argv[]) {
if (cg_pid_get_unit(pid, &t) >= 0) {
if (streq(t, SPECIAL_JOURNALD_SERVICE)) {
+ free(t);
/* If we are journald, we cut things short,
* don't write to the journal, but still
@@ -559,9 +638,13 @@ int main(int argc, char* argv[]) {
goto finish;
}
- core_unit = strappend("COREDUMP_UNIT=", t);
- } else if (cg_pid_get_user_unit(pid, &t) >= 0)
- core_unit = strappend("COREDUMP_USER_UNIT=", t);
+ core_unit = strappenda("COREDUMP_UNIT=", t);
+ free(t);
+
+ } else if (cg_pid_get_user_unit(pid, &t) >= 0) {
+ core_unit = strappenda("COREDUMP_USER_UNIT=", t);
+ free(t);
+ }
if (core_unit)
IOVEC_SET_STRING(iovec[j++], core_unit);
@@ -571,28 +654,23 @@ int main(int argc, char* argv[]) {
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_open();
- core_pid = strappend("COREDUMP_PID=", info[INFO_PID]);
- if (core_pid)
- IOVEC_SET_STRING(iovec[j++], core_pid);
+ core_pid = strappenda("COREDUMP_PID=", info[INFO_PID]);
+ IOVEC_SET_STRING(iovec[j++], core_pid);
- core_uid = strappend("COREDUMP_UID=", info[INFO_UID]);
- if (core_uid)
- IOVEC_SET_STRING(iovec[j++], core_uid);
+ core_uid = strappenda("COREDUMP_UID=", info[INFO_UID]);
+ IOVEC_SET_STRING(iovec[j++], core_uid);
- core_gid = strappend("COREDUMP_GID=", info[INFO_GID]);
- if (core_gid)
- IOVEC_SET_STRING(iovec[j++], core_gid);
+ core_gid = strappenda("COREDUMP_GID=", info[INFO_GID]);
+ IOVEC_SET_STRING(iovec[j++], core_gid);
- core_signal = strappend("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
- if (core_signal)
- IOVEC_SET_STRING(iovec[j++], core_signal);
+ core_signal = strappenda("COREDUMP_SIGNAL=", info[INFO_SIGNAL]);
+ IOVEC_SET_STRING(iovec[j++], core_signal);
if (sd_pid_get_session(pid, &t) >= 0) {
- core_session = strappend("COREDUMP_SESSION=", t);
+ core_session = strappenda("COREDUMP_SESSION=", t);
free(t);
- if (core_session)
- IOVEC_SET_STRING(iovec[j++], core_session);
+ IOVEC_SET_STRING(iovec[j++], core_session);
}
if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) {
@@ -603,39 +681,100 @@ int main(int argc, char* argv[]) {
}
if (sd_pid_get_slice(pid, &t) >= 0) {
- core_slice = strappend("COREDUMP_SLICE=", t);
+ core_slice = strappenda("COREDUMP_SLICE=", t);
free(t);
- if (core_slice)
- IOVEC_SET_STRING(iovec[j++], core_slice);
+ IOVEC_SET_STRING(iovec[j++], core_slice);
}
if (comm) {
- core_comm = strappend("COREDUMP_COMM=", comm);
- if (core_comm)
- IOVEC_SET_STRING(iovec[j++], core_comm);
+ core_comm = strappenda("COREDUMP_COMM=", comm);
+ IOVEC_SET_STRING(iovec[j++], core_comm);
}
if (exe) {
- core_exe = strappend("COREDUMP_EXE=", exe);
- if (core_exe)
- IOVEC_SET_STRING(iovec[j++], core_exe);
+ core_exe = strappenda("COREDUMP_EXE=", exe);
+ IOVEC_SET_STRING(iovec[j++], core_exe);
}
if (get_process_cmdline(pid, 0, false, &t) >= 0) {
- core_cmdline = strappend("COREDUMP_CMDLINE=", t);
+ core_cmdline = strappenda("COREDUMP_CMDLINE=", t);
free(t);
- if (core_cmdline)
- IOVEC_SET_STRING(iovec[j++], core_cmdline);
+ IOVEC_SET_STRING(iovec[j++], core_cmdline);
}
if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) {
- core_cgroup = strappend("COREDUMP_CGROUP=", t);
+ core_cgroup = strappenda("COREDUMP_CGROUP=", t);
+ free(t);
+
+ IOVEC_SET_STRING(iovec[j++], core_cgroup);
+ }
+
+ if (compose_open_fds(pid, &t) >= 0) {
+ core_open_fds = strappend("COREDUMP_OPEN_FDS=", t);
+ free(t);
+
+ if (core_open_fds)
+ IOVEC_SET_STRING(iovec[j++], core_open_fds);
+ }
+
+ p = procfs_file_alloca(pid, "status");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_status = strappend("COREDUMP_PROC_STATUS=", t);
+ free(t);
+
+ if (core_proc_status)
+ IOVEC_SET_STRING(iovec[j++], core_proc_status);
+ }
+
+ p = procfs_file_alloca(pid, "maps");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t);
+ free(t);
+
+ if (core_proc_maps)
+ IOVEC_SET_STRING(iovec[j++], core_proc_maps);
+ }
+
+ p = procfs_file_alloca(pid, "limits");
+ if (read_full_file(p, &t, NULL) >= 0) {
+ core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t);
+ free(t);
+
+ if (core_proc_limits)
+ IOVEC_SET_STRING(iovec[j++], core_proc_limits);
+ }
+
+ p = procfs_file_alloca(pid, "cgroup");
+ if (read_full_file(p, &t, NULL) >=0) {
+ core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t);
+ free(t);
+
+ if (core_proc_cgroup)
+ IOVEC_SET_STRING(iovec[j++], core_proc_cgroup);
+ }
+
+ if (get_process_cwd(pid, &t) >= 0) {
+ core_cwd = strappenda("COREDUMP_CWD=", t);
+ free(t);
+
+ IOVEC_SET_STRING(iovec[j++], core_cwd);
+ }
+
+ if (get_process_root(pid, &t) >= 0) {
+ core_root = strappenda("COREDUMP_ROOT=", t);
+ free(t);
+
+ IOVEC_SET_STRING(iovec[j++], core_root);
+ }
+
+ if (get_process_environ(pid, &t) >= 0) {
+ core_environ = strappend("COREDUMP_ENVIRON=", t);
free(t);
- if (core_cgroup)
- IOVEC_SET_STRING(iovec[j++], core_cgroup);
+ if (core_environ)
+ IOVEC_SET_STRING(iovec[j++], core_environ);
}
core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL);
@@ -678,7 +817,7 @@ int main(int argc, char* argv[]) {
* thus making sure the user gets access to the core dump. */
if (setresgid(gid, gid, gid) < 0 ||
setresuid(uid, uid, uid) < 0) {
- log_error("Failed to drop privileges: %m");
+ log_error_errno(errno, "Failed to drop privileges: %m");
r = -errno;
goto finish;
}
@@ -694,7 +833,7 @@ int main(int argc, char* argv[]) {
else if (r == -EINVAL)
log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
else
- log_warning("Failed to generate stack trace: %s", strerror(-r));
+ log_warning_errno(r, "Failed to generate stack trace: %m");
}
if (!core_message)
@@ -721,7 +860,7 @@ log:
r = sd_journal_sendv(iovec, j);
if (r < 0)
- log_error("Failed to log coredump: %s", strerror(-r));
+ log_error_errno(r, "Failed to log coredump: %m");
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/journal/coredump.conf b/src/journal/coredump.conf
index 0cc328f549..0fe9fe801a 100644
--- a/src/journal/coredump.conf
+++ b/src/journal/coredump.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/coredump.conf.d/*.conf.
+#
# See coredump.conf(5) for details
[Coredump]
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index d4756fe67d..a6551ac44b 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -73,7 +73,7 @@ static Set *new_matches(void) {
r = set_consume(set, tmp);
if (r < 0) {
- log_error("failed to add to set: %s", strerror(-r));
+ log_error_errno(r, "failed to add to set: %m");
set_free(set);
return NULL;
}
@@ -110,14 +110,13 @@ static int add_match(Set *set, const char *match) {
log_debug("Adding pattern: %s", pattern);
r = set_consume(set, pattern);
if (r < 0) {
- log_error("Failed to add pattern: %s", strerror(-r));
+ log_error_errno(r, "Failed to add pattern: %m");
goto fail;
}
return 0;
fail:
- log_error("Failed to add match: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to add match: %m");
}
static void help(void) {
@@ -191,10 +190,8 @@ static int parse_argv(int argc, char *argv[], Set *matches) {
}
output = fopen(optarg, "we");
- if (!output) {
- log_error("writing to '%s': %m", optarg);
- return -errno;
- }
+ if (!output)
+ return log_error_errno(errno, "writing to '%s': %m", optarg);
break;
@@ -326,10 +323,8 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) {
}
r = sd_journal_get_realtime_usec(j, &t);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
format_timestamp(buf, sizeof(buf), t);
present = filename && access(filename, F_OK) == 0;
@@ -521,10 +516,8 @@ static int focus(sd_journal *j) {
r = sd_journal_seek_tail(j);
if (r == 0)
r = sd_journal_previous(j);
- if (r < 0) {
- log_error("Failed to search journal: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to search journal: %m");
if (r == 0) {
log_error("No match found.");
return -ESRCH;
@@ -586,7 +579,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
* compressed file (probably uncached). */
r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
if (r < 0 && r != -ENOENT)
- log_warning("Failed to retrieve COREDUMP_FILENAME: %s", strerror(-r));
+ log_warning_errno(r, "Failed to retrieve COREDUMP_FILENAME: %m");
else if (r == 0)
retrieve(data, len, "COREDUMP_FILENAME", &filename);
@@ -614,10 +607,8 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
return log_oom();
fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
- if (fdt < 0) {
- log_error("Failed to create temporary file: %m");
- return -errno;
- }
+ if (fdt < 0)
+ return log_error_errno(errno, "Failed to create temporary file: %m");
log_debug("Created temporary file %s", temp);
fd = fdt;
@@ -633,7 +624,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
sz = write(fdt, data, len);
if (sz < 0) {
- log_error("Failed to write temporary file: %m");
+ log_error_errno(errno, "Failed to write temporary file: %m");
r = -errno;
goto error;
}
@@ -648,14 +639,14 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
fdf = open(filename, O_RDONLY | O_CLOEXEC);
if (fdf < 0) {
- log_error("Failed to open %s: %m", filename);
+ log_error_errno(errno, "Failed to open %s: %m", filename);
r = -errno;
goto error;
}
r = decompress_stream(filename, fdf, fd, -1);
if (r < 0) {
- log_error("Failed to decompress %s: %s", filename, strerror(-r));
+ log_error_errno(r, "Failed to decompress %s: %m", filename);
goto error;
}
#else
@@ -667,7 +658,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
if (r == -ENOENT)
log_error("Cannot retrieve coredump from journal nor disk.");
else
- log_error("Failed to retrieve COREDUMP field: %s", strerror(-r));
+ log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
goto error;
}
@@ -704,10 +695,8 @@ static int dump_core(sd_journal* j) {
}
r = save_core(j, output ? fileno(output) : STDOUT_FILENO, NULL, NULL);
- if (r < 0) {
- log_error("Coredump retrieval failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Coredump retrieval failed: %m");
r = sd_journal_previous(j);
if (r >= 0)
@@ -735,10 +724,8 @@ static int run_gdb(sd_journal *j) {
fputs("\n", stdout);
r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
- if (r < 0) {
- log_error("Failed to retrieve COREDUMP_EXE field: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
assert(len > strlen("COREDUMP_EXE="));
data += strlen("COREDUMP_EXE=");
@@ -759,27 +746,25 @@ static int run_gdb(sd_journal *j) {
}
r = save_core(j, -1, &path, &unlink_path);
- if (r < 0) {
- log_error("Failed to retrieve core: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve core: %m");
pid = fork();
if (pid < 0) {
- log_error("Failed to fork(): %m");
+ log_error_errno(errno, "Failed to fork(): %m");
r = -errno;
goto finish;
}
if (pid == 0) {
execlp("gdb", "gdb", exe, path, NULL);
- log_error("Failed to invoke gdb: %m");
+ log_error_errno(errno, "Failed to invoke gdb: %m");
_exit(1);
}
r = wait_for_terminate(pid, &st);
if (r < 0) {
- log_error("Failed to wait for gdb: %m");
+ log_error_errno(errno, "Failed to wait for gdb: %m");
goto finish;
}
@@ -820,7 +805,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
if (r < 0) {
- log_error("Failed to open journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to open journal: %m");
goto end;
}
@@ -830,8 +815,8 @@ int main(int argc, char *argv[]) {
SET_FOREACH(match, matches, it) {
r = sd_journal_add_match(j, match, strlen(match));
if (r != 0) {
- log_error("Failed to add match '%s': %s",
- match, strerror(-r));
+ log_error_errno(r, "Failed to add match '%s': %m",
+ match);
goto end;
}
}
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 5ab1982bf0..f9bd686c11 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -339,7 +339,7 @@ int journal_file_fss_load(JournalFile *f) {
fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
if (fd < 0) {
if (errno != ENOENT)
- log_error("Failed to open %s: %m", p);
+ log_error_errno(errno, "Failed to open %s: %m", p);
r = -errno;
goto finish;
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 8a2c0fcac5..c5d2d19433 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1292,7 +1292,7 @@ void journal_file_post_change(JournalFile *f) {
__sync_synchronize();
if (ftruncate(f->fd, f->last_stat.st_size) < 0)
- log_error("Failed to truncate file to its own size: %m");
+ log_error_errno(errno, "Failed to truncate file to its own size: %m");
}
static int entry_item_cmp(const void *_a, const void *_b) {
@@ -1657,7 +1657,7 @@ static int generic_array_bisect(
}
}
- if (k > n) {
+ if (k >= n) {
if (direction == DIRECTION_UP) {
i = n;
subtract_one = true;
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index bb1ef66dc9..56a96c55dd 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -32,6 +32,7 @@
#include "sd-journal.h"
#include "util.h"
#include "socket-util.h"
+#include "memfd-util.h"
#define SNDBUF_SIZE (8*1024*1024)
@@ -198,7 +199,7 @@ finish:
_public_ int sd_journal_sendv(const struct iovec *iov, int n) {
PROTECT_ERRNO;
- int fd;
+ int fd, r;
_cleanup_close_ int buffer_fd = -1;
struct iovec *w;
uint64_t *l;
@@ -218,6 +219,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
} control;
struct cmsghdr *cmsg;
bool have_syslog_identifier = false;
+ bool seal = true;
assert_return(iov, -EINVAL);
assert_return(n > 0, -EINVAL);
@@ -304,21 +306,36 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
if (errno != EMSGSIZE && errno != ENOBUFS)
return -errno;
- /* Message doesn't fit... Let's dump the data in a temporary
- * file and just pass a file descriptor of it to the other
- * side.
+ /* Message doesn't fit... Let's dump the data in a memfd or
+ * temporary file and just pass a file descriptor of it to the
+ * other side.
*
- * We use /dev/shm instead of /tmp here, since we want this to
- * be a tmpfs, and one that is available from early boot on
- * and where unprivileged users can create files. */
- buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
- if (buffer_fd < 0)
- return buffer_fd;
+ * For the temporary files we use /dev/shm instead of /tmp
+ * here, since we want this to be a tmpfs, and one that is
+ * available from early boot on and where unprivileged users
+ * can create files. */
+ buffer_fd = memfd_new(NULL);
+ if (buffer_fd < 0) {
+ if (buffer_fd == -ENOSYS) {
+ buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
+ if (buffer_fd < 0)
+ return buffer_fd;
+
+ seal = false;
+ } else
+ return buffer_fd;
+ }
n = writev(buffer_fd, w, j);
if (n < 0)
return -errno;
+ if (seal) {
+ r = memfd_set_sealed(buffer_fd);
+ if (r < 0)
+ return r;
+ }
+
mh.msg_iov = NULL;
mh.msg_iovlen = 0;
@@ -436,13 +453,10 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
header[l++] = '0';
header[l++] = '\n';
- r = (int) loop_write(fd, header, l, false);
+ r = loop_write(fd, header, l, false);
if (r < 0)
return r;
- if ((size_t) r != l)
- return -errno;
-
r = fd;
fd = -1;
return r;
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 7699482a77..4973409848 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -121,29 +121,38 @@ static void patch_realtime(
}
static int journal_file_empty(int dir_fd, const char *name) {
- int r;
- le64_t n_entries;
_cleanup_close_ int fd;
+ struct stat st;
+ le64_t n_entries;
+ ssize_t n;
fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
if (fd < 0)
return -errno;
- if (lseek(fd, offsetof(Header, n_entries), SEEK_SET) < 0)
+ if (fstat(fd, &st) < 0)
return -errno;
- r = read(fd, &n_entries, sizeof(n_entries));
- if (r != sizeof(n_entries))
- return r == 0 ? -EINVAL : -errno;
+ /* If an offline file doesn't even have a header we consider it empty */
+ if (st.st_size < (off_t) sizeof(Header))
+ return 1;
+
+ /* If the number of entries is empty, we consider it empty, too */
+ n = pread(fd, &n_entries, sizeof(n_entries), offsetof(Header, n_entries));
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(n_entries))
+ return -EIO;
- return le64toh(n_entries) == 0;
+ return le64toh(n_entries) <= 0;
}
int journal_directory_vacuum(
const char *directory,
uint64_t max_use,
usec_t max_retention_usec,
- usec_t *oldest_usec) {
+ usec_t *oldest_usec,
+ bool verbose) {
_cleanup_closedir_ DIR *d = NULL;
int r = 0;
@@ -152,6 +161,7 @@ int journal_directory_vacuum(
size_t n_allocated = 0;
uint64_t sum = 0, freed = 0;
usec_t retention_limit = 0;
+ char sbytes[FORMAT_BYTES_MAX];
assert(directory);
@@ -262,20 +272,22 @@ int journal_directory_vacuum(
uint64_t size = 512UL * (uint64_t) st.st_blocks;
if (unlinkat(dirfd(d), p, 0) >= 0) {
- log_info("Deleted empty journal %s/%s (%"PRIu64" bytes).",
- directory, p, size);
+ log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));
freed += size;
} else if (errno != ENOENT)
- log_warning("Failed to delete %s/%s: %m", directory, p);
+ log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p);
free(p);
-
continue;
}
patch_realtime(directory, p, &st, &realtime);
- GREEDY_REALLOC(list, n_allocated, n_list + 1);
+ if (!GREEDY_REALLOC(list, n_allocated, n_list + 1)) {
+ free(p);
+ r = -ENOMEM;
+ goto finish;
+ }
list[n_list].filename = p;
list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
@@ -297,8 +309,7 @@ int journal_directory_vacuum(
break;
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
- log_debug("Deleted archived journal %s/%s (%"PRIu64" bytes).",
- directory, list[i].filename, list[i].usage);
+ log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage));
freed += list[i].usage;
if (list[i].usage < sum)
@@ -307,7 +318,7 @@ int journal_directory_vacuum(
sum = 0;
} else if (errno != ENOENT)
- log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
+ log_warning_errno(errno, "Failed to delete archived journal %s/%s: %m", directory, list[i].filename);
}
if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
@@ -318,7 +329,7 @@ finish:
free(list[i].filename);
free(list);
- log_debug("Vacuuming done, freed %"PRIu64" bytes", freed);
+ log_full(verbose ? LOG_INFO : LOG_DEBUG, "Vacuuming done, freed %s of archived journals on disk.", format_bytes(sbytes, sizeof(sbytes), freed));
return r;
}
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
index bc30c3a140..a7fb6f0f0d 100644
--- a/src/journal/journal-vacuum.h
+++ b/src/journal/journal-vacuum.h
@@ -23,4 +23,4 @@
#include <inttypes.h>
-int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec);
+int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index f74adcbc89..7e3c974b33 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -825,21 +825,21 @@ int journal_file_verify(
data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
- log_error("Failed to create data file: %m");
+ log_error_errno(errno, "Failed to create data file: %m");
r = -errno;
goto fail;
}
entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
- log_error("Failed to create entry file: %m");
+ log_error_errno(errno, "Failed to create entry file: %m");
r = -errno;
goto fail;
}
entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
- log_error("Failed to create entry array file: %m");
+ log_error_errno(errno, "Failed to create entry array file: %m");
r = -errno;
goto fail;
}
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index f50faf42ad..b2f6966fca 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -59,6 +59,7 @@
#include "journal-verify.h"
#include "journal-authenticate.h"
#include "journal-qrcode.h"
+#include "journal-vacuum.h"
#include "fsprg.h"
#include "unit-name.h"
#include "catalog.h"
@@ -111,6 +112,8 @@ static bool arg_reverse = false;
static int arg_journal_type = 0;
static const char *arg_root = NULL;
static const char *arg_machine = NULL;
+static off_t arg_vacuum_size = (off_t) -1;
+static usec_t arg_vacuum_time = USEC_INFINITY;
static enum {
ACTION_SHOW,
@@ -124,6 +127,7 @@ static enum {
ACTION_UPDATE_CATALOG,
ACTION_LIST_BOOTS,
ACTION_FLUSH,
+ ACTION_VACUUM,
} arg_action = ACTION_SHOW;
typedef struct boot_id_t {
@@ -231,14 +235,16 @@ static void help(void) {
"\nCommands:\n"
" -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"
- " --header Show journal header information\n"
" --disk-usage Show total disk usage of all journal files\n"
- " -F --field=FIELD List all values that a specified field takes\n"
+ " --vacuum-size=BYTES Remove old journals until disk space drops below size\n"
+ " --vacuum-time=TIME Remove old journals until none left older than\n"
+ " --flush Flush all journal data from /run into /var\n"
+ " --header Show journal header information\n"
" --list-catalog Show message IDs of all entries in the message catalog\n"
" --dump-catalog Show entries in the message catalog\n"
" --update-catalog Update the message catalog database\n"
- " --flush Flush all journal data from /run into /var\n"
#ifdef HAVE_GCRYPT
" --setup-keys Generate a new FSS key pair\n"
" --verify Verify journal file consistency\n"
@@ -276,6 +282,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_UTC,
ARG_FLUSH,
+ ARG_VACUUM_SIZE,
+ ARG_VACUUM_TIME,
};
static const struct option options[] = {
@@ -327,6 +335,8 @@ 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 },
+ { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
+ { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{}
};
@@ -491,10 +501,8 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_FILE:
r = glob_extend(&arg_file, optarg);
- if (r < 0) {
- log_error("Failed to add paths: %s", strerror(-r));
- return r;
- };
+ if (r < 0)
+ return log_error_errno(r, "Failed to add paths: %m");
break;
case ARG_ROOT:
@@ -525,6 +533,26 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_DISK_USAGE;
break;
+ case ARG_VACUUM_SIZE:
+ r = parse_size(optarg, 1024, &arg_vacuum_size);
+ if (r < 0) {
+ log_error("Failed to parse vacuum size: %s", optarg);
+ return r;
+ }
+
+ arg_action = ACTION_VACUUM;
+ break;
+
+ case ARG_VACUUM_TIME:
+ r = parse_sec(optarg, &arg_vacuum_time);
+ if (r < 0) {
+ log_error("Failed to parse vacuum time: %s", optarg);
+ return r;
+ }
+
+ arg_action = ACTION_VACUUM;
+ break;
+
#ifdef HAVE_GCRYPT
case ARG_FORCE:
arg_force = true;
@@ -682,7 +710,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (arg_follow && !arg_no_tail && arg_lines == ARG_LINES_DEFAULT)
+ if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
arg_lines = 10;
if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
@@ -719,10 +747,8 @@ static int generate_new_id128(void) {
unsigned i;
r = sd_id128_randomize(&id);
- if (r < 0) {
- log_error("Failed to generate ID: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate ID: %m");
printf("As string:\n"
SD_ID128_FORMAT_STR "\n\n"
@@ -768,10 +794,8 @@ static int add_matches(sd_journal *j, char **args) {
p = canonicalize_file_name(*i);
path = p ? p : *i;
- if (stat(path, &st) < 0) {
- log_error("Couldn't stat file: %m");
- return -errno;
- }
+ if (stat(path, &st) < 0)
+ return log_error_errno(errno, "Couldn't stat file: %m");
if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
if (executable_is_script(path, &interpreter) > 0) {
@@ -821,10 +845,8 @@ static int add_matches(sd_journal *j, char **args) {
have_term = true;
}
- if (r < 0) {
- log_error("Failed to add match '%s': %s", *i, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match '%s': %m", *i);
}
if (!strv_isempty(args) && !have_term) {
@@ -1000,7 +1022,7 @@ static int add_boot(sd_journal *j) {
r = get_boot_id_by_offset(j, &arg_boot_id, arg_boot_offset);
if (r < 0) {
if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
- log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
+ log_error_errno(r, "Failed to look up boot %+i: %m", arg_boot_offset);
else
log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
@@ -1010,10 +1032,8 @@ static int add_boot(sd_journal *j) {
sd_id128_to_string(arg_boot_id, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
r = sd_journal_add_conjunction(j);
if (r < 0)
@@ -1030,10 +1050,8 @@ static int add_dmesg(sd_journal *j) {
return 0;
r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
r = sd_journal_add_conjunction(j);
if (r < 0)
@@ -1233,10 +1251,8 @@ static int add_priorities(sd_journal *j) {
match[sizeof(match)-2] = '0' + i;
r = sd_journal_add_match(j, match, strlen(match));
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
}
r = sd_journal_add_conjunction(j);
@@ -1285,10 +1301,8 @@ static int setup_keys(void) {
struct stat st;
r = stat("/var/log/journal", &st);
- if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
- log_error("stat(\"%s\") failed: %m", "/var/log/journal");
- return -errno;
- }
+ if (r < 0 && errno != ENOENT && errno != ENOTDIR)
+ return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
if (r < 0 || !S_ISDIR(st.st_mode)) {
log_error("%s is not a directory, must be using persistent logging for FSS.",
@@ -1297,16 +1311,12 @@ static int setup_keys(void) {
}
r = sd_id128_get_machine(&machine);
- if (r < 0) {
- log_error("Failed to get machine ID: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine ID: %m");
r = sd_id128_get_boot(&boot);
- if (r < 0) {
- log_error("Failed to get boot ID: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot ID: %m");
if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
SD_ID128_FORMAT_VAL(machine)) < 0)
@@ -1316,7 +1326,7 @@ static int setup_keys(void) {
if (arg_force) {
r = unlink(p);
if (r < 0) {
- log_error("unlink(\"%s\") failed: %m", p);
+ log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
r = -errno;
goto finish;
}
@@ -1344,7 +1354,7 @@ static int setup_keys(void) {
fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
- log_error("Failed to open /dev/random: %m");
+ log_error_errno(errno, "Failed to open /dev/random: %m");
r = -errno;
goto finish;
}
@@ -1352,7 +1362,7 @@ static int setup_keys(void) {
log_info("Generating seed...");
l = loop_read(fd, seed, seed_size, true);
if (l < 0 || (size_t) l != seed_size) {
- log_error("Failed to read random seed: %s", strerror(EIO));
+ log_error_errno(EIO, "Failed to read random seed: %m");
r = -EIO;
goto finish;
}
@@ -1371,7 +1381,7 @@ static int setup_keys(void) {
safe_close(fd);
fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- log_error("Failed to open %s: %m", k);
+ log_error_errno(errno, "Failed to open %s: %m", k);
r = -errno;
goto finish;
}
@@ -1379,12 +1389,12 @@ static int setup_keys(void) {
/* Enable secure remove, exclusion from dump, synchronous
* writing and in-place updating */
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
- log_warning("FS_IOC_GETFLAGS failed: %m");
+ log_warning_errno(errno, "FS_IOC_GETFLAGS failed: %m");
attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
- log_warning("FS_IOC_SETFLAGS failed: %m");
+ log_warning_errno(errno, "FS_IOC_SETFLAGS failed: %m");
zero(h);
memcpy(h.signature, "KSHHRHLP", 8);
@@ -1396,22 +1406,20 @@ static int setup_keys(void) {
h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
h.fsprg_state_size = htole64(state_size);
- l = loop_write(fd, &h, sizeof(h), false);
- if (l < 0 || (size_t) l != sizeof(h)) {
- log_error("Failed to write header: %s", strerror(EIO));
- r = -EIO;
+ r = loop_write(fd, &h, sizeof(h), false);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write header: %m");
goto finish;
}
- l = loop_write(fd, state, state_size, false);
- if (l < 0 || (size_t) l != state_size) {
- log_error("Failed to write state: %s", strerror(EIO));
- r = -EIO;
+ r = loop_write(fd, state, state_size, false);
+ if (r < 0) {
+ log_error_errno(r, "Failed to write state: %m");
goto finish;
}
if (link(k, p) < 0) {
- log_error("Failed to link file: %m");
+ log_error_errno(errno, "Failed to link file: %m");
r = -errno;
goto finish;
}
@@ -1632,8 +1640,7 @@ static int access_check(sd_journal *j) {
assert(err > 0);
if (err != EACCES)
- log_warning("Error was encountered while opening journal files: %s",
- strerror(err));
+ log_warning_errno(err, "Error was encountered while opening journal files: %m");
}
return r;
@@ -1652,10 +1659,8 @@ static int flush_to_var(void) {
/* OK, let's actually do the full logic, send SIGUSR1 to the
* daemon and set up inotify to wait for the flushed file to appear */
r = bus_open_system_systemd(&bus);
- if (r < 0) {
- log_error("Failed to get D-Bus connection: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get D-Bus connection: %m");
r = sd_bus_call_method(
bus,
@@ -1674,37 +1679,27 @@ static int flush_to_var(void) {
mkdir_p("/run/systemd/journal", 0755);
watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (watch_fd < 0) {
- log_error("Failed to create inotify watch: %m");
- return -errno;
- }
+ 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_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
- if (r < 0) {
- log_error("Failed to watch journal directory: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to watch journal directory: %m");
for (;;) {
if (access("/run/systemd/journal/flushed", F_OK) >= 0)
break;
- if (errno != ENOENT) {
- log_error("Failed to check for existance of /run/systemd/journal/flushed: %m");
- return -errno;
- }
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to check for existance of /run/systemd/journal/flushed: %m");
r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
- if (r < 0) {
- log_error("Failed to wait for event: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to wait for event: %m");
r = flush_fd(watch_fd);
- if (r < 0) {
- log_error("Failed to flush inotify events: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to flush inotify events: %m");
}
return 0;
@@ -1759,7 +1754,7 @@ int main(int argc, char *argv[]) {
if (arg_action == ACTION_UPDATE_CATALOG) {
r = catalog_update(database, arg_root, catalog_file_dirs);
if (r < 0)
- log_error("Failed to list catalog: %s", strerror(-r));
+ log_error_errno(r, "Failed to list catalog: %m");
} else {
bool oneline = arg_action == ACTION_LIST_CATALOG;
@@ -1769,7 +1764,7 @@ int main(int argc, char *argv[]) {
else
r = catalog_list(stdout, database, oneline);
if (r < 0)
- log_error("Failed to list catalog: %s", strerror(-r));
+ log_error_errno(r, "Failed to list catalog: %m");
}
goto finish;
@@ -1784,9 +1779,8 @@ 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("Failed to open %s: %s",
- arg_directory ? arg_directory : arg_file ? "files" : "journal",
- strerror(-r));
+ log_error_errno(r, "Failed to open %s: %m",
+ arg_directory ? arg_directory : arg_file ? "files" : "journal");
return EXIT_FAILURE;
}
@@ -1812,11 +1806,31 @@ int main(int argc, char *argv[]) {
if (r < 0)
return EXIT_FAILURE;
- printf("Journals take up %s on disk.\n",
+ printf("Archived and active journals take up %s on disk.\n",
format_bytes(sbytes, sizeof(sbytes), bytes));
return EXIT_SUCCESS;
}
+ if (arg_action == ACTION_VACUUM) {
+ Directory *d;
+ Iterator i;
+
+ HASHMAP_FOREACH(d, j->directories_by_path, i) {
+ int q;
+
+ if (d->is_root)
+ continue;
+
+ q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
+ if (q < 0) {
+ log_error_errno(q, "Failed to vacuum: %m");
+ r = q;
+ }
+ }
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ }
+
if (arg_action == ACTION_LIST_BOOTS) {
r = list_boots(j);
goto finish;
@@ -1837,25 +1851,25 @@ int main(int argc, char *argv[]) {
strv_free(arg_user_units);
if (r < 0) {
- log_error("Failed to add filter for units: %s", strerror(-r));
+ log_error_errno(r, "Failed to add filter for units: %m");
return EXIT_FAILURE;
}
r = add_syslog_identifier(j);
if (r < 0) {
- log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
+ log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
return EXIT_FAILURE;
}
r = add_priorities(j);
if (r < 0) {
- log_error("Failed to add filter for priorities: %s", strerror(-r));
+ log_error_errno(r, "Failed to add filter for priorities: %m");
return EXIT_FAILURE;
}
r = add_matches(j, argv + optind);
if (r < 0) {
- log_error("Failed to add filters: %s", strerror(-r));
+ log_error_errno(r, "Failed to add filters: %m");
return EXIT_FAILURE;
}
@@ -1878,7 +1892,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_query_unique(j, arg_field);
if (r < 0) {
- log_error("Failed to query unique data objects: %s", strerror(-r));
+ log_error_errno(r, "Failed to query unique data objects: %m");
return EXIT_FAILURE;
}
@@ -1910,7 +1924,7 @@ int main(int argc, char *argv[]) {
if (arg_cursor || arg_after_cursor) {
r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
if (r < 0) {
- log_error("Failed to seek to cursor: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to cursor: %m");
return EXIT_FAILURE;
}
if (!arg_reverse)
@@ -1918,14 +1932,18 @@ int main(int argc, char *argv[]) {
else
r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
- if (arg_after_cursor && r < 2 && !arg_follow)
+ if (arg_after_cursor && r < 2) {
/* We couldn't find the next entry after the cursor. */
- arg_lines = 0;
+ if (arg_follow)
+ need_seek = true;
+ else
+ arg_lines = 0;
+ }
} else if (arg_since_set && !arg_reverse) {
r = sd_journal_seek_realtime_usec(j, arg_since);
if (r < 0) {
- log_error("Failed to seek to date: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to date: %m");
return EXIT_FAILURE;
}
r = sd_journal_next(j);
@@ -1933,7 +1951,7 @@ int main(int argc, char *argv[]) {
} else if (arg_until_set && arg_reverse) {
r = sd_journal_seek_realtime_usec(j, arg_until);
if (r < 0) {
- log_error("Failed to seek to date: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to date: %m");
return EXIT_FAILURE;
}
r = sd_journal_previous(j);
@@ -1941,7 +1959,7 @@ int main(int argc, char *argv[]) {
} else if (arg_lines >= 0) {
r = sd_journal_seek_tail(j);
if (r < 0) {
- log_error("Failed to seek to tail: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to tail: %m");
return EXIT_FAILURE;
}
@@ -1950,7 +1968,7 @@ int main(int argc, char *argv[]) {
} else if (arg_reverse) {
r = sd_journal_seek_tail(j);
if (r < 0) {
- log_error("Failed to seek to tail: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to tail: %m");
return EXIT_FAILURE;
}
@@ -1959,7 +1977,7 @@ int main(int argc, char *argv[]) {
} else {
r = sd_journal_seek_head(j);
if (r < 0) {
- log_error("Failed to seek to head: %s", strerror(-r));
+ log_error_errno(r, "Failed to seek to head: %m");
return EXIT_FAILURE;
}
@@ -1967,7 +1985,7 @@ int main(int argc, char *argv[]) {
}
if (r < 0) {
- log_error("Failed to iterate through journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to iterate through journal: %m");
return EXIT_FAILURE;
}
@@ -1980,7 +1998,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
if (r < 0) {
- log_error("Failed to get cutoff: %s", strerror(-r));
+ log_error_errno(r, "Failed to get cutoff: %m");
goto finish;
}
@@ -2005,7 +2023,7 @@ int main(int argc, char *argv[]) {
else
r = sd_journal_previous(j);
if (r < 0) {
- log_error("Failed to iterate through journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to iterate through journal: %m");
goto finish;
}
if (r == 0)
@@ -2017,7 +2035,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_get_realtime_usec(j, &usec);
if (r < 0) {
- log_error("Failed to determine timestamp: %s", strerror(-r));
+ log_error_errno(r, "Failed to determine timestamp: %m");
goto finish;
}
if (usec > arg_until)
@@ -2029,7 +2047,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_get_realtime_usec(j, &usec);
if (r < 0) {
- log_error("Failed to determine timestamp: %s", strerror(-r));
+ log_error_errno(r, "Failed to determine timestamp: %m");
goto finish;
}
if (usec < arg_since)
@@ -2074,7 +2092,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_get_cursor(j, &cursor);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_error("Failed to get cursor: %s", strerror(-r));
+ log_error_errno(r, "Failed to get cursor: %m");
else if (r >= 0)
printf("-- cursor: %s\n", cursor);
}
@@ -2084,7 +2102,7 @@ int main(int argc, char *argv[]) {
r = sd_journal_wait(j, (uint64_t) -1);
if (r < 0) {
- log_error("Couldn't wait for journal event: %s", strerror(-r));
+ log_error_errno(r, "Couldn't wait for journal event: %m");
goto finish;
}
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
new file mode 100644
index 0000000000..69742fa59c
--- /dev/null
+++ b/src/journal/journald-audit.c
@@ -0,0 +1,551 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "journald-audit.h"
+
+typedef struct MapField {
+ const char *audit_field;
+ const char *journal_field;
+ int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov);
+} MapField;
+
+static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
+ _cleanup_free_ char *c = NULL;
+ size_t l = 0, allocated = 0;
+ const char *e;
+
+ assert(field);
+ assert(p);
+ assert(iov);
+ assert(n_iov);
+
+ l = strlen(field);
+ allocated = l + 1;
+ c = malloc(allocated);
+ if (!c)
+ return -ENOMEM;
+
+ memcpy(c, field, l);
+ for (e = *p; *e != ' ' && *e != 0; e++) {
+ if (!GREEDY_REALLOC(c, allocated, l+2))
+ return -ENOMEM;
+
+ c[l++] = *e;
+ }
+
+ c[l] = 0;
+
+ if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
+ return -ENOMEM;
+
+ (*iov)[*n_iov].iov_base = c;
+ (*iov)[*n_iov].iov_len = l;
+ (*n_iov) ++;
+
+ *p = e;
+ c = NULL;
+
+ return 1;
+}
+
+static int map_string_field_internal(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov, bool filter_printable) {
+ _cleanup_free_ char *c = NULL;
+ const char *s, *e;
+ size_t l;
+
+ assert(field);
+ assert(p);
+ assert(iov);
+ assert(n_iov);
+
+ /* The kernel formats string fields in one of two formats. */
+
+ if (**p == '"') {
+ /* Normal quoted syntax */
+ s = *p + 1;
+ e = strchr(s, '"');
+ if (!e)
+ return 0;
+
+ l = strlen(field) + (e - s);
+ c = malloc(l+1);
+ if (!c)
+ return -ENOMEM;
+
+ *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
+
+ e += 1;
+
+ } else if (unhexchar(**p) >= 0) {
+ /* Hexadecimal escaping */
+ size_t allocated = 0;
+
+ l = strlen(field);
+ allocated = l + 2;
+ c = malloc(allocated);
+ if (!c)
+ return -ENOMEM;
+
+ memcpy(c, field, l);
+ for (e = *p; *e != ' ' && *e != 0; e += 2) {
+ int a, b;
+ uint8_t x;
+
+ a = unhexchar(e[0]);
+ if (a < 0)
+ return 0;
+
+ b = unhexchar(e[1]);
+ if (b < 0)
+ return 0;
+
+ x = ((uint8_t) a << 4 | (uint8_t) b);
+
+ if (filter_printable && x < (uint8_t) ' ')
+ x = (uint8_t) ' ';
+
+ if (!GREEDY_REALLOC(c, allocated, l+2))
+ return -ENOMEM;
+
+ c[l++] = (char) x;
+ }
+
+ c[l] = 0;
+ } else
+ return 0;
+
+ if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
+ return -ENOMEM;
+
+ (*iov)[*n_iov].iov_base = c;
+ (*iov)[*n_iov].iov_len = l;
+ (*n_iov) ++;
+
+ *p = e;
+ c = NULL;
+
+ return 1;
+}
+
+static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
+ return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false);
+}
+
+static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
+ return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true);
+}
+
+static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
+ const char *e, *f;
+ char *c, *t;
+ int r;
+
+ /* Implements fallback mappings for all fields we don't know */
+
+ for (e = *p; e < *p + 16; e++) {
+
+ if (*e == 0 || *e == ' ')
+ return 0;
+
+ if (*e == '=')
+ break;
+
+ if (!((*e >= 'a' && *e <= 'z') ||
+ (*e >= 'A' && *e <= 'Z') ||
+ (*e >= '0' && *e <= '9') ||
+ *e == '_' || *e == '-'))
+ return 0;
+ }
+
+ if (e <= *p || e >= *p + 16)
+ return 0;
+
+ c = alloca(strlen(prefix) + (e - *p) + 2);
+
+ t = stpcpy(c, prefix);
+ for (f = *p; f < e; f++) {
+ char x;
+
+ if (*f >= 'a' && *f <= 'z')
+ x = (*f - 'a') + 'A'; /* uppercase */
+ else if (*f == '-')
+ x = '_'; /* dashes → underscores */
+ else
+ x = *f;
+
+ *(t++) = x;
+ }
+ strcpy(t, "=");
+
+ e ++;
+
+ r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
+ if (r < 0)
+ return r;
+
+ *p = e;
+ return r;
+}
+
+/* Kernel fields are those occuring in the audit string before
+ * msg='. All of these fields are trusted, hence carry the "_" prefix.
+ * We try to translate the fields we know into our native names. The
+ * other's are generically mapped to _AUDIT_FIELD_XYZ= */
+static const MapField map_fields_kernel[] = {
+
+ /* First, we map certain well-known audit fields into native
+ * well-known fields */
+ { "pid=", "_PID=", map_simple_field },
+ { "ppid=", "_PPID=", map_simple_field },
+ { "uid=", "_UID=", map_simple_field },
+ { "euid=", "_EUID=", map_simple_field },
+ { "fsuid=", "_FSUID=", map_simple_field },
+ { "gid=", "_GID=", map_simple_field },
+ { "egid=", "_EGID=", map_simple_field },
+ { "fsgid=", "_FSGID=", map_simple_field },
+ { "tty=", "_TTY=", map_simple_field },
+ { "ses=", "_AUDIT_SESSION=", map_simple_field },
+ { "auid=", "_AUDIT_LOGINUID=", map_simple_field },
+ { "subj=", "_SELINUX_CONTEXT=", map_simple_field },
+ { "comm=", "_COMM=", map_string_field },
+ { "exe=", "_EXE=", map_string_field },
+ { "proctitle=", "_CMDLINE=", map_string_field_printable },
+
+ /* Some fields don't map to native well-known fields. However,
+ * we know that they are string fields, hence let's undo
+ * string field escaping for them, though we stick to the
+ * generic field names. */
+ { "path=", "_AUDIT_FIELD_PATH=", map_string_field },
+ { "dev=", "_AUDIT_FIELD_DEV=", map_string_field },
+ { "name=", "_AUDIT_FIELD_NAME=", map_string_field },
+ {}
+};
+
+/* Userspace fields are thos occuring in the audit string after
+ * msg='. All of these fields are untrusted, hence carry no "_"
+ * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
+static const MapField map_fields_userspace[] = {
+ { "cwd=", "AUDIT_FIELD_CWD=", map_string_field },
+ { "cmd=", "AUDIT_FIELD_CMD=", map_string_field },
+ { "acct=", "AUDIT_FIELD_ACCT=", map_string_field },
+ { "exe=", "AUDIT_FIELD_EXE=", map_string_field },
+ { "comm=", "AUDIT_FIELD_COMM=", map_string_field },
+ {}
+};
+
+static int map_all_fields(
+ const char *p,
+ const MapField map_fields[],
+ const char *prefix,
+ bool handle_msg,
+ struct iovec **iov,
+ size_t *n_iov_allocated,
+ unsigned *n_iov) {
+
+ int r;
+
+ assert(p);
+ assert(iov);
+ assert(n_iov_allocated);
+ assert(n_iov);
+
+ for (;;) {
+ bool mapped = false;
+ const MapField *m;
+ const char *v;
+
+ p += strspn(p, WHITESPACE);
+
+ if (*p == 0)
+ return 0;
+
+ if (handle_msg) {
+ v = startswith(p, "msg='");
+ if (v) {
+ const char *e;
+ char *c;
+
+ /* Userspace message. It's enclosed in
+ simple quotation marks, is not
+ escaped, but the last field in the
+ line, hence let's remove the
+ quotation mark, and apply the
+ userspace mapping instead of the
+ kernel mapping. */
+
+ e = endswith(v, "'");
+ if (!e)
+ return 0; /* don't continue splitting up if the final quotation mark is missing */
+
+ c = strndupa(v, e - v);
+ return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
+ }
+ }
+
+ /* Try to map the kernel fields to our own names */
+ for (m = map_fields; m->audit_field; m++) {
+ v = startswith(p, m->audit_field);
+ if (!v)
+ continue;
+
+ r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse audit array: %m");
+
+ if (r > 0) {
+ mapped = true;
+ p = v;
+ break;
+ }
+ }
+
+ if (!mapped) {
+ r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse audit array: %m");
+
+ if (r == 0) {
+ /* Couldn't process as generic field, let's just skip over it */
+ p += strcspn(p, WHITESPACE);
+ }
+ }
+ }
+}
+
+static void process_audit_string(Server *s, int type, const char *data, size_t size) {
+ _cleanup_free_ struct iovec *iov = NULL;
+ size_t n_iov_allocated = 0;
+ unsigned n_iov = 0, k;
+ uint64_t seconds, msec, id;
+ const char *p;
+ unsigned z;
+ char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
+ type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
+ source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
+ char *m;
+
+ assert(s);
+
+ if (size <= 0)
+ return;
+
+ if (!data)
+ return;
+
+ /* Note that the input buffer is NUL terminated, but let's
+ * check whether there is a spurious NUL byte */
+ if (memchr(data, 0, size))
+ return;
+
+ p = startswith(data, "audit");
+ if (!p)
+ return;
+
+ if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "):%n",
+ &seconds,
+ &msec,
+ &id,
+ &k) != 3)
+ return;
+
+ p += k;
+ p += strspn(p, WHITESPACE);
+
+ if (isempty(p))
+ return;
+
+ n_iov_allocated = N_IOVEC_META_FIELDS + 5;
+ iov = new(struct iovec, n_iov_allocated);
+ if (!iov) {
+ log_oom();
+ return;
+ }
+
+ IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
+
+ sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
+ (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
+ IOVEC_SET_STRING(iov[n_iov++], source_time_field);
+
+ sprintf(type_field, "_AUDIT_TYPE=%i", type);
+ IOVEC_SET_STRING(iov[n_iov++], type_field);
+
+ sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
+ IOVEC_SET_STRING(iov[n_iov++], id_field);
+
+ m = alloca(strlen("MESSAGE=<audit-") + DECIMAL_STR_MAX(int) + strlen("> ") + strlen(p) + 1);
+ sprintf(m, "MESSAGE=<audit-%i> %s", type, p);
+ IOVEC_SET_STRING(iov[n_iov++], m);
+
+ z = n_iov;
+
+ map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
+
+ if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
+ log_oom();
+ goto finish;
+ }
+
+ server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
+
+finish:
+ /* free() all entries that map_all_fields() added. All others
+ * are allocated on the stack or are constant. */
+
+ for (; z < n_iov; z++)
+ free(iov[z].iov_base);
+}
+
+void server_process_audit_message(
+ Server *s,
+ const void *buffer,
+ size_t buffer_size,
+ const struct ucred *ucred,
+ const union sockaddr_union *sa,
+ socklen_t salen) {
+
+ const struct nlmsghdr *nl = buffer;
+
+ assert(s);
+
+ if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
+ return;
+
+ assert(buffer);
+
+ /* Filter out fake data */
+ if (!sa ||
+ salen != sizeof(struct sockaddr_nl) ||
+ sa->nl.nl_family != AF_NETLINK ||
+ sa->nl.nl_pid != 0) {
+ log_debug("Audit netlink message from invalid sender.");
+ return;
+ }
+
+ if (!ucred || ucred->pid != 0) {
+ log_debug("Audit netlink message with invalid credentials.");
+ return;
+ }
+
+ if (!NLMSG_OK(nl, buffer_size)) {
+ log_error("Audit netlink message truncated.");
+ return;
+ }
+
+ /* Ignore special Netlink messages */
+ if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
+ return;
+
+ /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
+ if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
+ return;
+
+ process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
+}
+
+static int enable_audit(int fd, bool b) {
+ struct {
+ union {
+ struct nlmsghdr header;
+ uint8_t header_space[NLMSG_HDRLEN];
+ };
+ struct audit_status body;
+ } _packed_ request = {
+ .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
+ .header.nlmsg_type = AUDIT_SET,
+ .header.nlmsg_flags = NLM_F_REQUEST,
+ .header.nlmsg_seq = 1,
+ .header.nlmsg_pid = 0,
+ .body.mask = AUDIT_STATUS_ENABLED,
+ .body.enabled = b,
+ };
+ union sockaddr_union sa = {
+ .nl.nl_family = AF_NETLINK,
+ .nl.nl_pid = 0,
+ };
+ struct iovec iovec = {
+ .iov_base = &request,
+ .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
+ };
+ struct msghdr mh = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_name = &sa.sa,
+ .msg_namelen = sizeof(sa.nl),
+ };
+
+ ssize_t n;
+
+ n = sendmsg(fd, &mh, MSG_NOSIGNAL);
+ if (n < 0)
+ return -errno;
+ if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
+ return -EIO;
+
+ /* We don't wait for the result here, we can't do anything
+ * about it anyway */
+
+ return 0;
+}
+
+int server_open_audit(Server *s) {
+ static const int one = 1;
+ int r;
+
+ if (s->audit_fd < 0) {
+ static const union sockaddr_union sa = {
+ .nl.nl_family = AF_NETLINK,
+ .nl.nl_pid = 0,
+ .nl.nl_groups = AUDIT_NLGRP_READLOG,
+ };
+
+ s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
+ if (s->audit_fd < 0) {
+ if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
+ log_debug("Audit not supported in the kernel.");
+ else
+ log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
+
+ return 0;
+ }
+
+ r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
+ if (r < 0)
+ return log_error_errno(errno, "Failed to join audit multicast group: %m");
+ } else
+ fd_nonblock(s->audit_fd, 1);
+
+ r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ if (r < 0)
+ return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m");
+
+ r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add audit fd to event loop: %m");
+
+ /* We are listening now, try to enable audit */
+ r = enable_audit(s->audit_fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to issue audit enable call: %m");
+
+ return 0;
+}
diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h
new file mode 100644
index 0000000000..68cdfb3410
--- /dev/null
+++ b/src/journal/journald-audit.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "socket-util.h"
+#include "journald-server.h"
+
+void server_process_audit_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const union sockaddr_union *sa, socklen_t salen);
+
+int server_open_audit(Server*s);
diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c
index 6ec2528d74..4afa6ef9c3 100644
--- a/src/journal/journald-console.c
+++ b/src/journal/journald-console.c
@@ -48,7 +48,7 @@ void server_forward_console(
int priority,
const char *identifier,
const char *message,
- struct ucred *ucred) {
+ const struct ucred *ucred) {
struct iovec iovec[5];
char header_pid[16];
@@ -100,12 +100,12 @@ void server_forward_console(
fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0) {
- log_debug("Failed to open %s for logging: %m", tty);
+ log_debug_errno(errno, "Failed to open %s for logging: %m", tty);
return;
}
if (writev(fd, iovec, n) < 0)
- log_debug("Failed to write to %s for logging: %m", tty);
+ log_debug_errno(errno, "Failed to write to %s for logging: %m", tty);
safe_close(fd);
}
diff --git a/src/journal/journald-console.h b/src/journal/journald-console.h
index aa8e6579ba..d8af2267e1 100644
--- a/src/journal/journald-console.h
+++ b/src/journal/journald-console.h
@@ -23,4 +23,4 @@
#include "journald-server.h"
-void server_forward_console(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred);
+void server_forward_console(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred);
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index fb8ea08e31..aca4571ece 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -37,7 +37,7 @@ void server_forward_kmsg(
int priority,
const char *identifier,
const char *message,
- struct ucred *ucred) {
+ const struct ucred *ucred) {
struct iovec iovec[5];
char header_priority[6], header_pid[16];
@@ -88,7 +88,7 @@ void server_forward_kmsg(
IOVEC_SET_STRING(iovec[n++], "\n");
if (writev(s->dev_kmsg_fd, iovec, n) < 0)
- log_debug("Failed to write to /dev/kmsg for logging: %m");
+ log_debug_errno(errno, "Failed to write to /dev/kmsg for logging: %m");
free(ident_buf);
}
@@ -104,7 +104,7 @@ static bool is_us(const char *pid) {
return t == getpid();
}
-static void dev_kmsg_record(Server *s, char *p, size_t l) {
+static void dev_kmsg_record(Server *s, const char *p, size_t l) {
struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_KERNEL_FIELDS + 2 + N_IOVEC_UDEV_FIELDS];
char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
int priority, r;
@@ -342,7 +342,7 @@ static int server_read_dev_kmsg(Server *s) {
if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
return 0;
- log_error("Failed to read from kernel: %m");
+ log_error_errno(errno, "Failed to read from kernel: %m");
return -errno;
}
@@ -413,13 +413,13 @@ int server_open_dev_kmsg(Server *s) {
goto fail;
}
- log_error("Failed to add /dev/kmsg fd to event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to add /dev/kmsg fd to event loop: %m");
goto fail;
}
r = sd_event_source_set_priority(s->dev_kmsg_event_source, SD_EVENT_PRIORITY_IMPORTANT+10);
if (r < 0) {
- log_error("Failed to adjust priority of kmsg event source: %s", strerror(-r));
+ log_error_errno(r, "Failed to adjust priority of kmsg event source: %m");
goto fail;
}
@@ -446,18 +446,18 @@ int server_open_kernel_seqnum(Server *s) {
fd = open("/run/systemd/journal/kernel-seqnum", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
if (fd < 0) {
- log_error("Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/journal/kernel-seqnum, ignoring: %m");
return 0;
}
if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
- log_error("Failed to allocate sequential number file, ignoring: %m");
+ log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m");
return 0;
}
p = mmap(NULL, sizeof(uint64_t), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED) {
- log_error("Failed to map sequential number file, ignoring: %m");
+ log_error_errno(errno, "Failed to map sequential number file, ignoring: %m");
return 0;
}
diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h
index f60f605572..9a9d089967 100644
--- a/src/journal/journald-kmsg.h
+++ b/src/journal/journald-kmsg.h
@@ -26,6 +26,6 @@
int server_open_dev_kmsg(Server *s);
int server_flush_dev_kmsg(Server *s);
-void server_forward_kmsg(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred);
+void server_forward_kmsg(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred);
int server_open_kernel_seqnum(Server *s);
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index a6352022dd..f982696255 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -22,6 +22,7 @@
#include <unistd.h>
#include <stddef.h>
#include <sys/epoll.h>
+#include <sys/mman.h>
#include "socket-util.h"
#include "path-util.h"
@@ -32,6 +33,7 @@
#include "journald-console.h"
#include "journald-syslog.h"
#include "journald-wall.h"
+#include "memfd-util.h"
bool valid_user_field(const char *p, size_t l, bool allow_protected) {
const char *a;
@@ -68,15 +70,15 @@ bool valid_user_field(const char *p, size_t l, bool allow_protected) {
return true;
}
-static bool allow_object_pid(struct ucred *ucred) {
+static bool allow_object_pid(const struct ucred *ucred) {
return ucred && ucred->uid == 0;
}
void server_process_native_message(
Server *s,
const void *buffer, size_t buffer_size,
- struct ucred *ucred,
- struct timeval *tv,
+ const struct ucred *ucred,
+ const struct timeval *tv,
const char *label, size_t label_len) {
struct iovec *iovec = NULL;
@@ -301,22 +303,32 @@ finish:
void server_process_native_file(
Server *s,
int fd,
- struct ucred *ucred,
- struct timeval *tv,
+ const struct ucred *ucred,
+ const struct timeval *tv,
const char *label, size_t label_len) {
struct stat st;
- _cleanup_free_ void *p = NULL;
- ssize_t n;
+ bool sealed;
int r;
+ /* Data is in the passed fd, since it didn't fit in a
+ * datagram. */
+
assert(s);
assert(fd >= 0);
- if (!ucred || ucred->uid != 0) {
+ /* If it's a memfd, check if it is sealed. If so, we can just
+ * use map it and use it, and do not need to copy the data
+ * out. */
+ sealed = memfd_get_sealed(fd) > 0;
+
+ if (!sealed && (!ucred || ucred->uid != 0)) {
_cleanup_free_ char *sl = NULL, *k = NULL;
const char *e;
+ /* If this is not a sealed memfd, and the peer is unknown or
+ * unprivileged, then verify the path. */
+
if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
log_oom();
return;
@@ -324,7 +336,7 @@ void server_process_native_file(
r = readlink_malloc(sl, &k);
if (r < 0) {
- log_error("readlink(%s) failed: %m", sl);
+ log_error_errno(errno, "readlink(%s) failed: %m", sl);
return;
}
@@ -344,13 +356,8 @@ void server_process_native_file(
}
}
- /* Data is in the passed file, since it didn't fit in a
- * datagram. 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 */
-
if (fstat(fd, &st) < 0) {
- log_error("Failed to stat passed file, ignoring: %m");
+ log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
return;
}
@@ -367,21 +374,46 @@ void server_process_native_file(
return;
}
- p = malloc(st.st_size);
- if (!p) {
- log_oom();
- return;
- }
+ if (sealed) {
+ void *p;
+ size_t ps;
+
+ /* The file is sealed, we can just map it and use it. */
- n = pread(fd, p, st.st_size, 0);
- if (n < 0)
- log_error("Failed to read file, ignoring: %s", strerror(-n));
- else if (n > 0)
- server_process_native_message(s, p, n, ucred, tv, label, label_len);
+ ps = PAGE_ALIGN(st.st_size);
+ p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED) {
+ log_error_errno(errno, "Failed to map memfd, ignoring: %m");
+ return;
+ }
+
+ server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
+ assert_se(munmap(p, ps) >= 0);
+ } else {
+ _cleanup_free_ void *p = NULL;
+ ssize_t n;
+
+ /* 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 */
+
+ p = malloc(st.st_size);
+ if (!p) {
+ log_oom();
+ return;
+ }
+
+ n = pread(fd, p, st.st_size, 0);
+ if (n < 0)
+ log_error_errno(n, "Failed to read file, ignoring: %m");
+ else if (n > 0)
+ server_process_native_message(s, p, n, ucred, tv, label, label_len);
+ }
}
int server_open_native_socket(Server*s) {
- int one, r;
+ static const int one = 1;
+ int r;
assert(s);
@@ -392,51 +424,38 @@ int server_open_native_socket(Server*s) {
};
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (s->native_fd < 0) {
- log_error("socket() failed: %m");
- return -errno;
- }
+ if (s->native_fd < 0)
+ return log_error_errno(errno, "socket() failed: %m");
unlink(sa.un.sun_path);
r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- log_error("bind(%s) failed: %m", sa.un.sun_path);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->native_fd, 1);
- one = 1;
r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0) {
- log_error("SO_PASSCRED failed: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "SO_PASSCRED failed: %m");
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
- one = 1;
r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
- log_warning("SO_PASSSEC failed: %m");
+ log_warning_errno(errno, "SO_PASSSEC failed: %m");
}
#endif
- one = 1;
r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
- if (r < 0) {
- log_error("SO_TIMESTAMP failed: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
- if (r < 0) {
- log_error("Failed to add native server fd to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add native server fd to event loop: %m");
return 0;
}
diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h
index e82a5b87d5..2f9d458fb5 100644
--- a/src/journal/journald-native.h
+++ b/src/journal/journald-native.h
@@ -30,8 +30,8 @@
bool valid_user_field(const char *p, size_t l, bool allow_protected);
-void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
-void server_process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_file(Server *s, int fd, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
int server_open_native_socket(Server*s);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 12735c4b81..80c9736420 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -50,6 +50,7 @@
#include "journald-stream.h"
#include "journald-console.h"
#include "journald-native.h"
+#include "journald-audit.h"
#include "journald-server.h"
#ifdef HAVE_ACL
@@ -203,7 +204,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
r = fchmod(f->fd, 0640);
if (r < 0)
- log_warning("Failed to fix access mode on %s, ignoring: %s", f->path, strerror(-r));
+ log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
#ifdef HAVE_ACL
if (uid <= SYSTEM_UID_MAX)
@@ -211,7 +212,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
acl = acl_get_fd(f->fd);
if (!acl) {
- log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path);
return;
}
@@ -221,7 +222,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
if (acl_create_entry(&acl, &entry) < 0 ||
acl_set_tag_type(entry, ACL_USER) < 0 ||
acl_set_qualifier(entry, &uid) < 0) {
- log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
goto finish;
}
}
@@ -231,12 +232,12 @@ void server_fix_perms(Server *s, JournalFile *f, 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("Failed to patch ACL on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
goto finish;
}
if (acl_set_fd(f->fd, acl) < 0)
- log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
finish:
acl_free(acl);
@@ -307,11 +308,11 @@ static int do_rotate(Server *s, JournalFile **f, const char* name,
r = journal_file_rotate(f, s->compress, seal);
if (r < 0)
if (*f)
- log_error("Failed to rotate %s: %s",
- (*f)->path, strerror(-r));
+ log_error_errno(r, "Failed to rotate %s: %m",
+ (*f)->path);
else
- log_error("Failed to create new %s journal: %s",
- name, strerror(-r));
+ log_error_errno(r, "Failed to create new %s journal: %m",
+ name);
else
server_fix_perms(s, *f, uid);
return r;
@@ -347,19 +348,19 @@ void server_sync(Server *s) {
if (s->system_journal) {
r = journal_file_set_offline(s->system_journal);
if (r < 0)
- log_error("Failed to sync system journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to sync system journal: %m");
}
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = journal_file_set_offline(f);
if (r < 0)
- log_error("Failed to sync user journal: %s", strerror(-r));
+ log_error_errno(r, "Failed to sync user journal: %m");
}
if (s->sync_event_source) {
r = sd_event_source_set_enabled(s->sync_event_source, SD_EVENT_OFF);
if (r < 0)
- log_error("Failed to disable sync timer source: %s", strerror(-r));
+ log_error_errno(r, "Failed to disable sync timer source: %m");
}
s->sync_scheduled = false;
@@ -374,9 +375,9 @@ static void do_vacuum(Server *s, char *ids, JournalFile *f, const char* path,
return;
p = strappenda(path, ids);
- r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec);
+ r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
if (r < 0 && r != -ENOENT)
- log_error("Failed to vacuum %s: %s", p, strerror(-r));
+ log_error_errno(r, "Failed to vacuum %s: %m", p);
}
void server_vacuum(Server *s) {
@@ -390,7 +391,7 @@ void server_vacuum(Server *s) {
r = sd_id128_get_machine(&machine);
if (r < 0) {
- log_error("Failed to get machine ID: %s", strerror(-r));
+ log_error_errno(r, "Failed to get machine ID: %m");
return;
}
sd_id128_to_string(machine, ids);
@@ -510,7 +511,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
for (i = 0; i < n; i++)
size += iovec[i].iov_len;
- log_error("Failed to write entry (%d items, %zu bytes), ignoring: %s", n, size, strerror(-r));
+ log_error_errno(r, "Failed to write entry (%d items, %zu bytes), ignoring: %m", n, size);
return;
}
@@ -529,7 +530,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
for (i = 0; i < n; i++)
size += iovec[i].iov_len;
- log_error("Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %s", n, size, strerror(-r));
+ log_error_errno(r, "Failed to write entry (%d items, %zu bytes) despite vacuuming, ignoring: %m", n, size);
} else
server_schedule_sync(s, priority);
}
@@ -537,8 +538,8 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
static void dispatch_message_real(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- struct ucred *ucred,
- struct timeval *tv,
+ const struct ucred *ucred,
+ const struct timeval *tv,
const char *label, size_t label_len,
const char *unit_id,
int priority,
@@ -840,7 +841,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
IOVEC_SET_STRING(iovec[n++], buffer);
if (!sd_id128_equal(message_id, SD_ID128_NULL)) {
- snprintf(mid, sizeof(mid), MESSAGE_ID(message_id));
+ snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id));
char_array_0(mid);
IOVEC_SET_STRING(iovec[n++], mid);
}
@@ -855,8 +856,8 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
void server_dispatch_message(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- struct ucred *ucred,
- struct timeval *tv,
+ const struct ucred *ucred,
+ const struct timeval *tv,
const char *label, size_t label_len,
const char *unit_id,
int priority,
@@ -926,10 +927,8 @@ static int system_journal_open(Server *s, bool flush_requested) {
char ids[33];
r = sd_id128_get_machine(&machine);
- if (r < 0) {
- log_error("Failed to get machine id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine id: %m");
sd_id128_to_string(machine, ids);
@@ -957,7 +956,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
server_fix_perms(s, s->system_journal, 0);
else if (r < 0) {
if (r != -ENOENT && r != -EROFS)
- log_warning("Failed to open system journal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to open system journal: %m");
r = 0;
}
@@ -981,7 +980,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
if (r < 0) {
if (r != -ENOENT)
- log_warning("Failed to open runtime journal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to open runtime journal: %m");
r = 0;
}
@@ -998,10 +997,8 @@ static int system_journal_open(Server *s, bool flush_requested) {
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
free(fn);
- if (r < 0) {
- log_error("Failed to open runtime journal: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open runtime journal: %m");
}
if (s->runtime_journal)
@@ -1044,10 +1041,8 @@ int server_flush_to_var(Server *s) {
return r;
r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY);
- if (r < 0) {
- log_error("Failed to read runtime journal: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read runtime journal: %m");
sd_journal_set_data_threshold(j, 0);
@@ -1062,7 +1057,7 @@ int server_flush_to_var(Server *s) {
r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o);
if (r < 0) {
- log_error("Can't read entry: %s", strerror(-r));
+ log_error_errno(r, "Can't read entry: %m");
goto finish;
}
@@ -1071,7 +1066,7 @@ int server_flush_to_var(Server *s) {
continue;
if (!shall_try_append_again(s->system_journal, r)) {
- log_error("Can't write entry: %s", strerror(-r));
+ log_error_errno(r, "Can't write entry: %m");
goto finish;
}
@@ -1087,7 +1082,7 @@ int server_flush_to_var(Server *s) {
log_debug("Retrying write.");
r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL);
if (r < 0) {
- log_error("Can't write entry: %s", strerror(-r));
+ log_error_errno(r, "Can't write entry: %m");
goto finish;
}
}
@@ -1112,7 +1107,7 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
Server *s = userdata;
assert(s);
- assert(fd == s->native_fd || fd == s->syslog_fd);
+ assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd);
if (revents != EPOLLIN) {
log_error("Got invalid event from epoll for datagram fd: %"PRIx32, revents);
@@ -1142,35 +1137,44 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
CMSG_SPACE(sizeof(int)) + /* fd */
CMSG_SPACE(NAME_MAX)]; /* selinux label */
} control = {};
+ union sockaddr_union sa = {};
struct msghdr msghdr = {
.msg_iov = &iovec,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control),
+ .msg_name = &sa,
+ .msg_namelen = sizeof(sa),
};
ssize_t n;
- int v;
int *fds = NULL;
unsigned n_fds = 0;
+ int v = 0;
+ size_t m;
- if (ioctl(fd, SIOCINQ, &v) < 0) {
- log_error("SIOCINQ failed: %m");
- return -errno;
- }
+ /* Try to get the right size, if we can. (Not all
+ * sockets support SIOCINQ, hence we just try, but
+ * don't rely on it. */
+ (void) ioctl(fd, SIOCINQ, &v);
+
+ /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful!*/
+ m = PAGE_ALIGN(MAX3((size_t) v + 1,
+ (size_t) LINE_MAX,
+ ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
- if (!GREEDY_REALLOC(s->buffer, s->buffer_size, LINE_MAX + (size_t) v))
+ if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
return log_oom();
iovec.iov_base = s->buffer;
- iovec.iov_len = s->buffer_size;
+ iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
if (n < 0) {
if (errno == EINTR || errno == EAGAIN)
return 0;
- log_error("recvmsg() failed: %m");
+ log_error_errno(errno, "recvmsg() failed: %m");
return -errno;
}
@@ -1195,20 +1199,30 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
}
}
+ /* And a trailing NUL, just in case */
+ s->buffer[n] = 0;
+
if (fd == s->syslog_fd) {
- if (n > 0 && n_fds == 0) {
- s->buffer[n] = 0;
+ if (n > 0 && n_fds == 0)
server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
- } else if (n_fds > 0)
+ else if (n_fds > 0)
log_warning("Got file descriptors via syslog socket. Ignoring.");
- } else {
+ } else if (fd == s->native_fd) {
if (n > 0 && n_fds == 0)
server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
else if (n == 0 && n_fds == 1)
server_process_native_file(s, fds[0], ucred, tv, label, label_len);
else if (n_fds > 0)
log_warning("Got too many file descriptors via native socket. Ignoring.");
+
+ } else {
+ assert(fd == s->audit_fd);
+
+ if (n > 0 && n_fds == 0)
+ server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
+ else if (n_fds > 0)
+ log_warning("Got file descriptors via audit socket. Ignoring.");
}
close_many(fds, n_fds);
@@ -1290,10 +1304,10 @@ static int server_parse_proc_cmdline(Server *s) {
int r;
r = proc_cmdline(&line);
- if (r < 0)
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- if (r <= 0)
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
return 0;
+ }
FOREACH_WORD_QUOTED(w, l, line, state) {
_cleanup_free_ char *word;
@@ -1337,10 +1351,11 @@ static int server_parse_proc_cmdline(Server *s) {
static int server_parse_config_file(Server *s) {
assert(s);
- return config_parse(NULL, "/etc/systemd/journald.conf", NULL,
- "Journal\0",
- config_item_perf_lookup, journald_gperf_lookup,
- false, false, true, s);
+ return config_parse_many("/etc/systemd/journald.conf",
+ CONF_DIRS_NULSTR("systemd/journald.conf"),
+ "Journal\0",
+ config_item_perf_lookup, journald_gperf_lookup,
+ false, s);
}
static int server_dispatch_sync(sd_event_source *es, usec_t t, void *userdata) {
@@ -1417,10 +1432,8 @@ static int server_open_hostname(Server *s) {
assert(s);
s->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
- if (s->hostname_fd < 0) {
- log_error("Failed to open /proc/sys/kernel/hostname: %m");
- return -errno;
- }
+ if (s->hostname_fd < 0)
+ return log_error_errno(errno, "Failed to open /proc/sys/kernel/hostname: %m");
r = sd_event_add_io(s->event, &s->hostname_event_source, s->hostname_fd, 0, dispatch_hostname_change, s);
if (r < 0) {
@@ -1433,15 +1446,12 @@ static int server_open_hostname(Server *s) {
return 0;
}
- log_error("Failed to register hostname fd in event loop: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to register hostname fd in event loop: %m");
}
r = sd_event_source_set_priority(s->hostname_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
- if (r < 0) {
- log_error("Failed to adjust priority of host name event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust priority of host name event source: %m");
return 0;
}
@@ -1452,7 +1462,7 @@ int server_init(Server *s) {
assert(s);
zero(*s);
- s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->hostname_fd = -1;
+ s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
s->compress = true;
s->seal = true;
@@ -1494,18 +1504,14 @@ int server_init(Server *s) {
return log_oom();
r = sd_event_default(&s->event);
- if (r < 0) {
- log_error("Failed to create event loop: %s", strerror(-r));
- return r;
- }
+ 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) {
- log_error("Failed to read listening file descriptors from environment: %s", strerror(-n));
- return n;
- }
+ if (n < 0)
+ return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
@@ -1537,9 +1543,24 @@ int server_init(Server *s) {
s->syslog_fd = fd;
+ } else if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
+
+ if (s->audit_fd >= 0) {
+ log_error("Too many audit sockets passed.");
+ return -EINVAL;
+ }
+
+ s->audit_fd = fd;
+
} else {
- log_error("Unknown socket passed.");
- return -EINVAL;
+ log_warning("Unknown socket passed as file descriptor %d, ignoring.", fd);
+
+ /* Let's close the fd, better be safe than
+ sorry. The fd might reference some resource
+ that we really want to release if we don't
+ make use of it. */
+
+ safe_close(fd);
}
}
@@ -1559,6 +1580,10 @@ int server_init(Server *s) {
if (r < 0)
return r;
+ r = server_open_audit(s);
+ if (r < 0)
+ return r;
+
r = server_open_kernel_seqnum(s);
if (r < 0)
return r;
@@ -1632,6 +1657,7 @@ void server_done(Server *s) {
sd_event_source_unref(s->native_event_source);
sd_event_source_unref(s->stdout_event_source);
sd_event_source_unref(s->dev_kmsg_event_source);
+ sd_event_source_unref(s->audit_event_source);
sd_event_source_unref(s->sync_event_source);
sd_event_source_unref(s->sigusr1_event_source);
sd_event_source_unref(s->sigusr2_event_source);
@@ -1644,6 +1670,7 @@ void server_done(Server *s) {
safe_close(s->native_fd);
safe_close(s->stdout_fd);
safe_close(s->dev_kmsg_fd);
+ safe_close(s->audit_fd);
safe_close(s->hostname_fd);
if (s->rate_limit)
@@ -1655,6 +1682,7 @@ void server_done(Server *s) {
free(s->buffer);
free(s->tty_path);
free(s->cgroup_root);
+ free(s->hostname_field);
if (s->mmap)
mmap_cache_unref(s->mmap);
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index 6888187df9..9c7fa50a96 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -59,6 +59,7 @@ typedef struct Server {
int native_fd;
int stdout_fd;
int dev_kmsg_fd;
+ int audit_fd;
int hostname_fd;
sd_event *event;
@@ -67,6 +68,7 @@ typedef struct Server {
sd_event_source *native_event_source;
sd_event_source *stdout_event_source;
sd_event_source *dev_kmsg_event_source;
+ sd_event_source *audit_event_source;
sd_event_source *sync_event_source;
sd_event_source *sigusr1_event_source;
sd_event_source *sigusr2_event_source;
@@ -148,7 +150,7 @@ typedef struct Server {
#define N_IOVEC_UDEV_FIELDS 32
#define N_IOVEC_OBJECT_FIELDS 11
-void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
+void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4);
/* gperf lookup function */
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 76580f8263..be498d4919 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -306,7 +306,7 @@ static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents,
if (errno == EAGAIN)
return 0;
- log_warning("Failed to read from stream: %m");
+ log_warning_errno(errno, "Failed to read from stream: %m");
goto terminate;
}
@@ -370,7 +370,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
if (errno == EAGAIN)
return 0;
- log_error("Failed to accept stdout connection: %m");
+ log_error_errno(errno, "Failed to accept stdout connection: %m");
return -errno;
}
@@ -390,31 +390,31 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
r = getpeercred(fd, &stream->ucred);
if (r < 0) {
- log_error("Failed to determine peer credentials: %m");
+ log_error_errno(errno, "Failed to determine peer credentials: %m");
goto fail;
}
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
if (getpeercon(fd, &stream->security_context) < 0 && errno != ENOPROTOOPT)
- log_error("Failed to determine peer security context: %m");
+ log_error_errno(errno, "Failed to determine peer security context: %m");
}
#endif
if (shutdown(fd, SHUT_WR) < 0) {
- log_error("Failed to shutdown writing side of socket: %m");
+ log_error_errno(errno, "Failed to shutdown writing side of socket: %m");
goto fail;
}
r = sd_event_add_io(s->event, &stream->event_source, fd, EPOLLIN, stdout_stream_process, stream);
if (r < 0) {
- log_error("Failed to add stream to event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to add stream to event loop: %m");
goto fail;
}
r = sd_event_source_set_priority(stream->event_source, SD_EVENT_PRIORITY_NORMAL+5);
if (r < 0) {
- log_error("Failed to adjust stdout event source priority: %s", strerror(-r));
+ log_error_errno(r, "Failed to adjust stdout event source priority: %m");
goto fail;
}
@@ -441,39 +441,29 @@ int server_open_stdout_socket(Server *s) {
};
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (s->stdout_fd < 0) {
- log_error("socket() failed: %m");
- return -errno;
- }
+ if (s->stdout_fd < 0)
+ return log_error_errno(errno, "socket() failed: %m");
unlink(sa.un.sun_path);
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- log_error("bind(%s) failed: %m", sa.un.sun_path);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
chmod(sa.un.sun_path, 0666);
- if (listen(s->stdout_fd, SOMAXCONN) < 0) {
- log_error("listen(%s) failed: %m", sa.un.sun_path);
- return -errno;
- }
+ if (listen(s->stdout_fd, SOMAXCONN) < 0)
+ return log_error_errno(errno, "listen(%s) failed: %m", sa.un.sun_path);
} else
fd_nonblock(s->stdout_fd, 1);
r = sd_event_add_io(s->event, &s->stdout_event_source, s->stdout_fd, EPOLLIN, stdout_stream_new, s);
- if (r < 0) {
- log_error("Failed to add stdout server fd to event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add stdout server fd to event source: %m");
r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10);
- if (r < 0) {
- log_error("Failed to adjust priority of stdout server event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
return 0;
}
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 79c07fffa1..cc44d45949 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -35,7 +35,7 @@
/* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
-static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
+static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, const struct ucred *ucred, const struct timeval *tv) {
static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
@@ -106,10 +106,10 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
}
if (errno != ENOENT)
- log_debug("Failed to forward syslog message: %m");
+ log_debug_errno(errno, "Failed to forward syslog message: %m");
}
-static void forward_syslog_raw(Server *s, int priority, const char *buffer, struct ucred *ucred, struct timeval *tv) {
+static void forward_syslog_raw(Server *s, int priority, const char *buffer, const struct ucred *ucred, const struct timeval *tv) {
struct iovec iovec;
assert(s);
@@ -122,7 +122,7 @@ static void forward_syslog_raw(Server *s, int priority, const char *buffer, stru
forward_syslog_iovec(s, &iovec, 1, ucred, tv);
}
-void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
+void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv) {
struct iovec iovec[5];
char header_priority[6], header_time[64], header_pid[16];
int n = 0;
@@ -351,16 +351,18 @@ static void syslog_skip_date(char **buf) {
void server_process_syslog_message(
Server *s,
const char *buf,
- struct ucred *ucred,
- struct timeval *tv,
+ const struct ucred *ucred,
+ const struct timeval *tv,
const char *label,
size_t label_len) {
- char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
+ char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
+ syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)];
+ const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
struct iovec iovec[N_IOVEC_META_FIELDS + 6];
unsigned n = 0;
int priority = LOG_USER | LOG_INFO;
- char *identifier = NULL, *pid = NULL;
+ _cleanup_free_ char *identifier = NULL, *pid = NULL;
const char *orig;
assert(s);
@@ -386,42 +388,36 @@ void server_process_syslog_message(
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
- if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
- IOVEC_SET_STRING(iovec[n++], syslog_priority);
+ sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK);
+ IOVEC_SET_STRING(iovec[n++], syslog_priority);
- if (priority & LOG_FACMASK)
- if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
- IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ if (priority & LOG_FACMASK) {
+ sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority));
+ IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ }
if (identifier) {
- syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
+ syslog_identifier = strappenda("SYSLOG_IDENTIFIER=", identifier);
if (syslog_identifier)
IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
- syslog_pid = strappend("SYSLOG_PID=", pid);
+ syslog_pid = strappenda("SYSLOG_PID=", pid);
if (syslog_pid)
IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
- message = strappend("MESSAGE=", buf);
+ message = strappenda("MESSAGE=", buf);
if (message)
IOVEC_SET_STRING(iovec[n++], message);
server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
-
- free(message);
- free(identifier);
- free(pid);
- free(syslog_priority);
- free(syslog_facility);
- free(syslog_identifier);
- free(syslog_pid);
}
int server_open_syslog_socket(Server *s) {
- int one, r;
+ static const int one = 1;
+ int r;
assert(s);
@@ -432,51 +428,38 @@ int server_open_syslog_socket(Server *s) {
};
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (s->syslog_fd < 0) {
- log_error("socket() failed: %m");
- return -errno;
- }
+ if (s->syslog_fd < 0)
+ return log_error_errno(errno, "socket() failed: %m");
unlink(sa.un.sun_path);
r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- log_error("bind(%s) failed: %m", sa.un.sun_path);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
chmod(sa.un.sun_path, 0666);
} else
fd_nonblock(s->syslog_fd, 1);
- one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0) {
- log_error("SO_PASSCRED failed: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "SO_PASSCRED failed: %m");
#ifdef HAVE_SELINUX
if (mac_selinux_use()) {
- one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
if (r < 0)
- log_warning("SO_PASSSEC failed: %m");
+ log_warning_errno(errno, "SO_PASSSEC failed: %m");
}
#endif
- one = 1;
r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
- if (r < 0) {
- log_error("SO_TIMESTAMP failed: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
r = sd_event_add_io(s->event, &s->syslog_event_source, s->syslog_fd, EPOLLIN, process_datagram, s);
- if (r < 0) {
- log_error("Failed to add syslog server fd to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add syslog server fd to event loop: %m");
return 0;
}
diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h
index 057ea79def..25f89883f4 100644
--- a/src/journal/journald-syslog.h
+++ b/src/journal/journald-syslog.h
@@ -28,9 +28,9 @@ int syslog_fixup_facility(int priority) _const_;
void syslog_parse_priority(const char **p, int *priority, bool with_facility);
size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
-void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv);
+void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred, const struct timeval *tv);
-void server_process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_syslog_message(Server *s, const char *buf, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len);
int server_open_syslog_socket(Server *s);
void server_maybe_warn_forward_syslog_missed(Server *s);
diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c
index fcbd9183fe..e3201674d4 100644
--- a/src/journal/journald-wall.c
+++ b/src/journal/journald-wall.c
@@ -28,7 +28,7 @@ void server_forward_wall(
int priority,
const char *identifier,
const char *message,
- struct ucred *ucred) {
+ const struct ucred *ucred) {
_cleanup_free_ char *ident_buf = NULL, *l_buf = NULL;
const char *l;
@@ -65,5 +65,5 @@ void server_forward_wall(
r = utmp_wall(l, "systemd-journald", NULL);
if (r < 0)
- log_debug("Failed to send wall message: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send wall message: %m");
}
diff --git a/src/journal/journald-wall.h b/src/journal/journald-wall.h
index 93c3cec1d2..45c52854a0 100644
--- a/src/journal/journald-wall.h
+++ b/src/journal/journald-wall.h
@@ -23,4 +23,4 @@
#include "journald-server.h"
-void server_forward_wall(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred);
+void server_forward_wall(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred);
diff --git a/src/journal/journald.c b/src/journal/journald.c
index de40827d6a..604c8617bb 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -104,7 +104,7 @@ int main(int argc, char *argv[]) {
r = sd_event_run(server.event, t);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 2073f1bf21..29bdf8f183 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/journald.conf.d/*.conf.
+#
# See journald.conf(5) for details
[Journal]
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index cf21c4d899..23aad740dd 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -497,6 +497,47 @@ static int compare_entry_order(JournalFile *af, Object *_ao,
return 0;
}
+static bool whole_file_precedes_location(JournalFile *f, Location *l, direction_t direction) {
+ assert(f);
+ assert(l);
+
+ if (l->type != LOCATION_DISCRETE && l->type != LOCATION_SEEK)
+ return false;
+
+ if (l->seqnum_set && sd_id128_equal(l->seqnum_id, f->header->seqnum_id))
+ return direction == DIRECTION_DOWN ?
+ l->seqnum > le64toh(f->header->tail_entry_seqnum) :
+ l->seqnum < le64toh(f->header->head_entry_seqnum);
+
+ if (l->realtime_set)
+ return direction == DIRECTION_DOWN ?
+ l->realtime > le64toh(f->header->tail_entry_realtime) :
+ l->realtime < le64toh(f->header->head_entry_realtime);
+
+ return false;
+}
+
+static bool file_may_have_preceding_entry(JournalFile *f, JournalFile *of, uint64_t op, direction_t direction) {
+ Object *o;
+ int r;
+
+ assert(f);
+ assert(of);
+
+ r = journal_file_move_to_object(of, OBJECT_ENTRY, op, &o);
+ if (r < 0)
+ return true;
+
+ if (sd_id128_equal(f->header->seqnum_id, of->header->seqnum_id))
+ return direction == DIRECTION_DOWN ?
+ le64toh(o->entry.seqnum) >= le64toh(f->header->head_entry_seqnum) :
+ le64toh(o->entry.seqnum) <= le64toh(f->header->tail_entry_seqnum);
+
+ return direction == DIRECTION_DOWN ?
+ le64toh(o->entry.realtime) >= le64toh(f->header->head_entry_realtime) :
+ le64toh(o->entry.realtime) <= le64toh(f->header->tail_entry_realtime);
+}
+
_pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) {
uint64_t a;
@@ -882,9 +923,15 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
ORDERED_HASHMAP_FOREACH(f, j->files, i) {
bool found;
+ if (whole_file_precedes_location(f, &j->current_location, direction))
+ continue;
+
+ if (new_file && !file_may_have_preceding_entry(f, new_file, new_offset, direction))
+ continue;
+
r = next_beyond_location(j, f, direction, &o, &p);
if (r < 0) {
- log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r));
+ log_debug_errno(r, "Can't iterate through %s, ignoring: %m", f->path);
remove_file_real(j, f);
continue;
} else if (r == 0)
@@ -1410,7 +1457,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
d = opendir(path);
if (!d) {
- log_debug("Failed to open %s: %m", path);
+ log_debug_errno(errno, "Failed to open %s: %m", path);
if (errno == ENOENT)
return 0;
return -errno;
@@ -1456,7 +1503,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
de = readdir(d);
if (!de && errno != 0) {
r = -errno;
- log_debug("Failed to read directory %s: %m", m->path);
+ log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
return r;
}
if (!de)
@@ -1466,8 +1513,8 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
dirent_is_file_with_suffix(de, ".journal~")) {
r = add_file(j, m->path, de->d_name);
if (r < 0) {
- log_debug("Failed to add file %s/%s: %s",
- m->path, de->d_name, strerror(-r));
+ 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;
@@ -1546,7 +1593,7 @@ static int add_root_directory(sd_journal *j, const char *p) {
de = readdir(d);
if (!de && errno != 0) {
r = -errno;
- log_debug("Failed to read directory %s: %m", m->path);
+ log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
return r;
}
if (!de)
@@ -1556,8 +1603,8 @@ static int add_root_directory(sd_journal *j, const char *p) {
dirent_is_file_with_suffix(de, ".journal~")) {
r = add_file(j, m->path, de->d_name);
if (r < 0) {
- log_debug("Failed to add file %s/%s: %s",
- m->path, de->d_name, strerror(-r));
+ 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;
@@ -1567,7 +1614,7 @@ static int add_root_directory(sd_journal *j, const char *p) {
r = add_directory(j, m->path, de->d_name);
if (r < 0)
- log_debug("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r));
+ log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
}
}
@@ -1810,7 +1857,7 @@ _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("Failed to open %s: %s", *path, strerror(-r));
+ log_error_errno(r, "Failed to open %s: %m", *path);
goto fail;
}
}
@@ -2218,8 +2265,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
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("Failed to add file %s/%s: %s",
- d->path, e->name, strerror(-r));
+ log_debug_errno(r, "Failed to add file %s/%s: %m",
+ d->path, e->name);
set_put_error(j, r);
}
@@ -2227,7 +2274,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
r = remove_file(j, d->path, e->name);
if (r < 0)
- log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
+ log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
}
} else if (!d->is_root && e->len == 0) {
@@ -2237,7 +2284,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
r = remove_directory(j, d);
if (r < 0)
- log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
+ log_debug_errno(r, "Failed to remove directory %s: %m", d->path);
}
@@ -2248,7 +2295,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
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("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
+ log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
}
}
@@ -2273,7 +2320,6 @@ static int determine_change(sd_journal *j) {
}
_public_ int sd_journal_process(sd_journal *j) {
- uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX] _alignas_(struct inotify_event);
bool got_something = false;
assert_return(j, -EINVAL);
@@ -2282,6 +2328,7 @@ _public_ int sd_journal_process(sd_journal *j) {
j->last_process_usec = now(CLOCK_MONOTONIC);
for (;;) {
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
struct inotify_event *e;
ssize_t l;
@@ -2295,18 +2342,8 @@ _public_ int sd_journal_process(sd_journal *j) {
got_something = true;
- e = (struct inotify_event*) buffer;
- while (l > 0) {
- size_t step;
-
+ FOREACH_INOTIFY_EVENT(e, buffer, l)
process_inotify_event(j, e);
-
- step = sizeof(struct inotify_event) + e->len;
- assert(step <= (size_t) l);
-
- e = (struct inotify_event*) ((uint8_t*) e + step);
- l -= step;
- }
}
}
diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c
index 5fe2f6a269..c605ee0e70 100644
--- a/src/journal/test-catalog.c
+++ b/src/journal/test-catalog.c
@@ -49,11 +49,11 @@ static void test_import(Hashmap *h, struct strbuf *sb,
_cleanup_close_ int fd;
fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert(fd >= 0);
+ assert_se(fd >= 0);
assert_se(write(fd, contents, size) == size);
r = catalog_import_file(h, sb, name);
- assert(r == code);
+ assert_se(r == code);
unlink(name);
}
@@ -68,7 +68,7 @@ static void test_catalog_importing(void) {
#define BUF "xxx"
test_import(h, sb, BUF, sizeof(BUF), -EINVAL);
#undef BUF
- assert(hashmap_isempty(h));
+ assert_se(hashmap_isempty(h));
log_debug("----------------------------------------");
#define BUF \
@@ -89,7 +89,7 @@ static void test_catalog_importing(void) {
test_import(h, sb, BUF, sizeof(BUF), 0);
#undef BUF
- assert(hashmap_size(h) == 1);
+ assert_se(hashmap_size(h) == 1);
log_debug("----------------------------------------");
@@ -105,22 +105,22 @@ static void test_catalog_update(void) {
int r;
r = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert(r >= 0);
+ assert_se(r >= 0);
database = name;
/* Test what happens if there are no files. */
r = catalog_update(database, NULL, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
/* Test what happens if there are no files in the directory. */
r = catalog_update(database, NULL, no_catalog_dirs);
- assert(r >= 0);
+ assert_se(r >= 0);
/* Make sure that we at least have some files loaded or the
catalog_list below will fail. */
r = catalog_update(database, NULL, catalog_dirs);
- assert(r >= 0);
+ assert_se(r >= 0);
}
static void test_catalog_file_lang(void) {
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index 78b3203bef..97577e827c 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -63,29 +63,29 @@ static void test_compress_decompress(int compression,
r = compress(data, data_len, compressed, &csize);
if (r == -ENOBUFS) {
- log_info("compression failed: %s", strerror(-r));
- assert(may_fail);
+ log_info_errno(r, "compression failed: %m");
+ assert_se(may_fail);
} else {
- assert(r == 0);
+ assert_se(r == 0);
r = decompress(compressed, csize,
(void **) &decompressed, &usize, &csize, 0);
- assert(r == 0);
+ assert_se(r == 0);
assert_se(decompressed);
assert_se(memcmp(decompressed, data, data_len) == 0);
}
r = decompress("garbage", 7,
(void **) &decompressed, &usize, &csize, 0);
- assert(r < 0);
+ assert_se(r < 0);
/* make sure to have the minimal lz4 compressed size */
r = decompress("00000000\1g", 9,
(void **) &decompressed, &usize, &csize, 0);
- assert(r < 0);
+ assert_se(r < 0);
r = decompress("\100000000g", 9,
(void **) &decompressed, &usize, &csize, 0);
- assert(r < 0);
+ assert_se(r < 0);
memzero(decompressed, usize);
}
@@ -108,11 +108,11 @@ static void test_decompress_startswith(int compression,
r = compress(data, data_len, compressed, &csize);
if (r == -ENOBUFS) {
- log_info("compression failed: %s", strerror(-r));
- assert(may_fail);
+ log_info_errno(r, "compression failed: %m");
+ assert_se(may_fail);
return;
}
- assert(r == 0);
+ assert_se(r == 0);
assert_se(decompress_sw(compressed,
csize,
@@ -184,7 +184,7 @@ static void test_compress_stream(int compression,
assert_se(lseek(dst, 1, SEEK_SET) == 1);
r = decompress(dst, dst2, st.st_size);
- assert(r == -EBADMSG);
+ assert_se(r == -EBADMSG);
assert_se(lseek(dst, 0, SEEK_SET) == 0);
assert_se(lseek(dst2, 0, SEEK_SET) == 0);
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index 6c5995e0c1..23a26c43f6 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -37,9 +37,9 @@
static bool arg_keep = false;
noreturn static void log_assert_errno(const char *text, int eno, const char *file, int line, const char *func) {
- log_meta(LOG_CRIT, file, line, func,
- "'%s' failed at %s:%u (%s): %s.",
- text, file, line, func, strerror(eno));
+ log_internal(LOG_CRIT, 0, file, line, func,
+ "'%s' failed at %s:%u (%s): %s.",
+ text, file, line, func, strerror(eno));
abort();
}
@@ -189,7 +189,7 @@ static void test_skip(void (*setup)(void)) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL);
+ journal_directory_vacuum(".", 3000000, 0, NULL, true);
assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
}
@@ -274,7 +274,7 @@ static void test_sequence_numbers(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL);
+ journal_directory_vacuum(".", 3000000, 0, NULL, true);
assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
}
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index c4d407148c..c99ca0654b 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -30,9 +30,9 @@ static void test_syslog_parse_identifier(const char* str,
ret2 = syslog_parse_identifier(&buf, &ident2, &pid2);
- assert(ret == ret2);
- assert(ident == ident2 || streq_ptr(ident, ident2));
- assert(pid == pid2 || streq_ptr(pid, pid2));
+ assert_se(ret == ret2);
+ assert_se(ident == ident2 || streq_ptr(ident, ident2));
+ assert_se(pid == pid2 || streq_ptr(pid, pid2));
}
int main(void) {
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index 3b181c6794..9da120c0bb 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -38,15 +38,15 @@ static void bit_toggle(const char *fn, uint64_t p) {
int fd;
fd = open(fn, O_RDWR|O_CLOEXEC);
- assert(fd >= 0);
+ assert_se(fd >= 0);
r = pread(fd, &b, 1, p/8);
- assert(r == 1);
+ assert_se(r == 1);
b ^= 1 << (p % 8);
r = pwrite(fd, &b, 1, p/8);
- assert(r == 1);
+ assert_se(r == 1);
safe_close(fd);
}
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index 6025d04ba4..ff9dc9e170 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -66,55 +66,55 @@ static void test_non_empty(void) {
#endif
journal_file_dump(f);
- assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 2);
+ assert_se(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 2);
- assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 3);
+ assert_se(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 3);
- assert(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 0);
+ assert_se(journal_file_next_entry(f, o, p, DIRECTION_DOWN, &o, &p) == 0);
- assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_skip_entry(f, o, p, 2, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 3);
+ assert_se(journal_file_skip_entry(f, o, p, 2, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 3);
- assert(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_skip_entry(f, o, p, -2, &o, &p) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_find_data_object(f, test, strlen(test), NULL, &p) == 1);
- assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_find_data_object(f, test, strlen(test), NULL, &p) == 1);
+ assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 3);
+ assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 3);
- assert(journal_file_find_data_object(f, test2, strlen(test2), NULL, &p) == 1);
- assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 2);
+ assert_se(journal_file_find_data_object(f, test2, strlen(test2), NULL, &p) == 1);
+ assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_UP, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 2);
- assert(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 2);
+ assert_se(journal_file_next_entry_for_data(f, NULL, 0, p, DIRECTION_DOWN, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 2);
- assert(journal_file_find_data_object(f, "quux", 4, NULL, &p) == 0);
+ assert_se(journal_file_find_data_object(f, "quux", 4, NULL, &p) == 0);
- assert(journal_file_move_to_entry_by_seqnum(f, 1, DIRECTION_DOWN, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 1);
+ assert_se(journal_file_move_to_entry_by_seqnum(f, 1, DIRECTION_DOWN, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 1);
- assert(journal_file_move_to_entry_by_seqnum(f, 3, DIRECTION_DOWN, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 3);
+ assert_se(journal_file_move_to_entry_by_seqnum(f, 3, DIRECTION_DOWN, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 3);
- assert(journal_file_move_to_entry_by_seqnum(f, 2, DIRECTION_DOWN, &o, NULL) == 1);
- assert(le64toh(o->entry.seqnum) == 2);
+ assert_se(journal_file_move_to_entry_by_seqnum(f, 2, DIRECTION_DOWN, &o, NULL) == 1);
+ assert_se(le64toh(o->entry.seqnum) == 2);
- assert(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0);
+ assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0);
journal_file_rotate(&f, true, true);
journal_file_rotate(&f, true, true);
@@ -126,7 +126,7 @@ static void test_non_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL);
+ journal_directory_vacuum(".", 3000000, 0, NULL, true);
assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
}
@@ -165,7 +165,7 @@ static void test_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL);
+ journal_directory_vacuum(".", 3000000, 0, NULL, true);
assert_se(rm_rf_dangerous(t, false, true, false) >= 0);
}
diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c
index 778e884c3f..1227b62310 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/journal/test-mmap-cache.c
@@ -38,37 +38,37 @@ int main(int argc, char *argv[]) {
assert_se(m = mmap_cache_new());
x = mkostemp_safe(px, O_RDWR|O_CLOEXEC);
- assert(x >= 0);
+ assert_se(x >= 0);
unlink(px);
y = mkostemp_safe(py, O_RDWR|O_CLOEXEC);
- assert(y >= 0);
+ assert_se(y >= 0);
unlink(py);
z = mkostemp_safe(pz, O_RDWR|O_CLOEXEC);
- assert(z >= 0);
+ assert_se(z >= 0);
unlink(pz);
r = mmap_cache_get(m, x, PROT_READ, 0, false, 1, 2, NULL, &p, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
r = mmap_cache_get(m, x, PROT_READ, 0, false, 2, 2, NULL, &q, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
- assert((uint8_t*) p + 1 == (uint8_t*) q);
+ assert_se((uint8_t*) p + 1 == (uint8_t*) q);
r = mmap_cache_get(m, x, PROT_READ, 1, false, 3, 2, NULL, &q, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
- assert((uint8_t*) p + 2 == (uint8_t*) q);
+ assert_se((uint8_t*) p + 2 == (uint8_t*) q);
r = mmap_cache_get(m, x, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
r = mmap_cache_get(m, x, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL);
- assert(r >= 0);
+ assert_se(r >= 0);
- assert((uint8_t*) p + 1 == (uint8_t*) q);
+ assert_se((uint8_t*) p + 1 == (uint8_t*) q);
mmap_cache_unref(m);
diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install
index 6f032b5a4b..d433e00a5c 100644
--- a/src/kernel-install/90-loaderentry.install
+++ b/src/kernel-install/90-loaderentry.install
@@ -47,7 +47,7 @@ if [[ -f /etc/kernel/cmdline ]]; then
fi
if ! [[ ${BOOT_OPTIONS[*]} ]]; then
- read -ar line < /proc/cmdline
+ read -a line -r < /proc/cmdline
for i in "${line[@]}"; do
[[ "${i#initrd=*}" != "$i" ]] && continue
BOOT_OPTIONS[${#BOOT_OPTIONS[@]}]="$i"
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index d358a49307..7c60ef123c 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -71,4 +71,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref);
#define DHCP_CLIENT_DONT_DESTROY(client) \
_cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client)
-#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
+#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h
index d4675f3e47..9e184ac4b5 100644
--- a/src/libsystemd-network/dhcp-lease-internal.h
+++ b/src/libsystemd-network/dhcp-lease-internal.h
@@ -35,7 +35,7 @@
struct sd_dhcp_route {
struct in_addr dst_addr;
struct in_addr gw_addr;
- uint8_t dst_prefixlen;
+ unsigned char dst_prefixlen;
};
struct sd_dhcp_lease {
@@ -70,16 +70,18 @@ struct sd_dhcp_lease {
char *domainname;
char *hostname;
char *root_path;
+ uint8_t *client_id;
+ size_t client_id_len;
};
int dhcp_lease_new(sd_dhcp_lease **ret);
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
void *user_data);
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
-int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret);
-
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
+int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
+ size_t client_id_len);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref);
#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp)
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index 480da22c01..eb7d6d44d3 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -79,7 +79,7 @@ typedef struct DHCPRequest {
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref);
#define _cleanup_dhcp_server_unref_ _cleanup_(sd_dhcp_server_unrefp)
-#define log_dhcp_server(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__)
+#define log_dhcp_server(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__)
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
size_t length);
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 6cc0aa8a8d..4f54ad89a6 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -56,7 +56,7 @@ struct DHCP6IA {
typedef struct DHCP6IA DHCP6IA;
-#define log_dhcp6_client(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#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);
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index e6a31778f4..ea863f45e4 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -24,31 +24,37 @@
#include <string.h>
#include "sparse-endian.h"
+#include "unaligned.h"
#include "util.h"
#include "dhcp6-internal.h"
#include "dhcp6-protocol.h"
-#define DHCP6_OPTION_HDR_LEN 4
#define DHCP6_OPTION_IA_NA_LEN 12
#define DHCP6_OPTION_IA_TA_LEN 4
+typedef struct DHCP6Option {
+ be16_t code;
+ be16_t len;
+ uint8_t data[];
+} _packed_ DHCP6Option;
+
static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode,
size_t optlen) {
+ DHCP6Option *option = (DHCP6Option*) *buf;
+
assert_return(buf, -EINVAL);
assert_return(*buf, -EINVAL);
assert_return(buflen, -EINVAL);
- if (optlen > 0xffff || *buflen < optlen + DHCP6_OPTION_HDR_LEN)
+ if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option))
return -ENOBUFS;
- (*buf)[0] = optcode >> 8;
- (*buf)[1] = optcode & 0xff;
- (*buf)[2] = optlen >> 8;
- (*buf)[3] = optlen & 0xff;
+ option->code = htobe16(optcode);
+ option->len = htobe16(optlen);
- *buf += DHCP6_OPTION_HDR_LEN;
- *buflen -= DHCP6_OPTION_HDR_LEN;
+ *buf += sizeof(DHCP6Option);
+ *buflen -= sizeof(DHCP6Option);
return 0;
}
@@ -100,8 +106,8 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
ia_hdr = *buf;
ia_buflen = *buflen;
- *buf += DHCP6_OPTION_HDR_LEN;
- *buflen -= DHCP6_OPTION_HDR_LEN;
+ *buf += sizeof(DHCP6Option);
+ *buflen -= sizeof(DHCP6Option);
memcpy(*buf, &ia->id, len);
@@ -119,7 +125,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
*buf += sizeof(addr->iaaddr);
*buflen -= sizeof(addr->iaaddr);
- ia_addrlen += DHCP6_OPTION_HDR_LEN + sizeof(addr->iaaddr);
+ ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr);
}
r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen);
@@ -130,23 +136,23 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) {
}
-static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *opt,
- size_t *optlen) {
+static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
+ DHCP6Option *option = (DHCP6Option*) *buf;
uint16_t len;
assert_return(buf, -EINVAL);
- assert_return(opt, -EINVAL);
+ assert_return(optcode, -EINVAL);
assert_return(optlen, -EINVAL);
- if (*buflen < 4)
+ if (*buflen < sizeof(DHCP6Option))
return -ENOMSG;
- len = (*buf)[2] << 8 | (*buf)[3];
+ len = be16toh(option->len);
if (len > *buflen)
return -ENOMSG;
- *opt = (*buf)[0] << 8 | (*buf)[1];
+ *optcode = be16toh(option->code);
*optlen = len;
*buf += 4;
@@ -190,7 +196,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
switch (iatype) {
case DHCP6_OPTION_IA_NA:
- if (*buflen < DHCP6_OPTION_IA_NA_LEN + DHCP6_OPTION_HDR_LEN +
+ if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) +
sizeof(addr->iaaddr)) {
r = -ENOBUFS;
goto error;
@@ -212,7 +218,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype,
break;
case DHCP6_OPTION_IA_TA:
- if (*buflen < DHCP6_OPTION_IA_TA_LEN + DHCP6_OPTION_HDR_LEN +
+ if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) +
sizeof(addr->iaaddr)) {
r = -ENOBUFS;
goto error;
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index eaa671711f..3e0f339237 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -51,6 +51,8 @@ enum {
DHCP6_PORT_CLIENT = 546,
};
+#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC
+#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC
#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC
#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC
#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC
@@ -71,6 +73,7 @@ enum {
enum DHCP6State {
DHCP6_STATE_STOPPED = 0,
+ DHCP6_STATE_INFORMATION_REQUEST = 1,
DHCP6_STATE_SOLICITATION = 2,
DHCP6_STATE_REQUEST = 3,
DHCP6_STATE_BOUND = 4,
diff --git a/src/libsystemd-network/ipv4ll-internal.h b/src/libsystemd-network/ipv4ll-internal.h
index fe5ef8e2b8..ae0ce43985 100644
--- a/src/libsystemd-network/ipv4ll-internal.h
+++ b/src/libsystemd-network/ipv4ll-internal.h
@@ -35,4 +35,4 @@ void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr
void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
int arp_packet_verify_headers(struct ether_arp *arp);
-#define log_ipv4ll(ll, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
+#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 372f3ed371..6852a7129a 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -98,38 +98,38 @@ bool net_match_config(const struct ether_addr *match_mac,
const char *dev_type,
const char *dev_name) {
- if (match_host && !condition_test_host(match_host))
- return 0;
+ if (match_host && !condition_test(match_host))
+ return false;
- if (match_virt && !condition_test_virtualization(match_virt))
- return 0;
+ if (match_virt && !condition_test(match_virt))
+ return false;
- if (match_kernel && !condition_test_kernel_command_line(match_kernel))
- return 0;
+ if (match_kernel && !condition_test(match_kernel))
+ return false;
- if (match_arch && !condition_test_architecture(match_arch))
- return 0;
+ if (match_arch && !condition_test(match_arch))
+ return false;
if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN)))
- return 0;
+ return false;
if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0)))
- return 0;
+ return false;
if (match_driver) {
if (dev_parent_driver && !streq(match_driver, dev_parent_driver))
- return 0;
+ return false;
else if (!streq_ptr(match_driver, dev_driver))
- return 0;
+ return false;
}
if (match_type && !streq_ptr(match_type, dev_type))
- return 0;
+ return false;
if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0)))
- return 0;
+ return false;
- return 1;
+ return true;
}
int config_parse_net_condition(const char *unit,
@@ -392,10 +392,12 @@ void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *route
fprintf(f, "%s=", key);
- for (i = 0; i < size; i++)
- fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr),
- routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr),
+ for (i = 0; i < size; i++) {
+ fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr),
+ routes[i].dst_prefixlen);
+ fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr),
(i < (size - 1)) ? " ": "");
+ }
fputs("\n", f);
}
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 49387d03cf..c64db2e79d 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -26,7 +26,7 @@
#include <stdbool.h>
#include "udev.h"
-#include "condition-util.h"
+#include "condition.h"
bool net_match_config(const struct ether_addr *match_mac,
const char *match_path,
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 0eba4c379d..b2b72befbf 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -38,6 +38,7 @@
#include "dhcp-lease-internal.h"
#include "sd-dhcp-client.h"
+#define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
struct sd_dhcp_client {
@@ -56,19 +57,38 @@ struct sd_dhcp_client {
size_t req_opts_allocated;
size_t req_opts_size;
be32_t last_addr;
- struct {
- uint8_t type;
- struct ether_addr mac_addr;
- } _packed_ client_id;
uint8_t mac_addr[MAX_MAC_ADDR_LEN];
size_t mac_addr_len;
uint16_t arp_type;
+ union {
+ struct {
+ uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ gen;
+ struct {
+ uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */
+ uint8_t haddr[ETH_ALEN];
+ } _packed_ eth;
+ struct {
+ uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */
+ uint8_t haddr[0];
+ } _packed_ ll;
+ struct {
+ uint8_t type; /* 255: Node-specific (RFC 4361) */
+ uint8_t iaid[4];
+ uint8_t duid[MAX_CLIENT_ID_LEN - 4];
+ } _packed_ ns;
+ struct {
+ uint8_t type;
+ uint8_t data[MAX_CLIENT_ID_LEN];
+ } _packed_ raw;
+ } client_id;
+ size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
uint32_t mtu;
uint32_t xid;
usec_t start_time;
- uint16_t secs;
unsigned int attempt;
usec_t request_sent;
sd_event_source *timeout_t1;
@@ -201,8 +221,70 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
client->mac_addr_len = addr_len;
client->arp_type = arp_type;
- memcpy(&client->client_id.mac_addr, addr, ETH_ALEN);
- client->client_id.type = 0x01;
+ if (need_restart && client->state != DHCP_STATE_STOPPED)
+ sd_dhcp_client_start(client);
+
+ return 0;
+}
+
+int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
+ const uint8_t **data, size_t *data_len) {
+
+ assert_return(client, -EINVAL);
+ assert_return(type, -EINVAL);
+ assert_return(data, -EINVAL);
+ assert_return(data_len, -EINVAL);
+
+ *type = 0;
+ *data = NULL;
+ *data_len = 0;
+ if (client->client_id_len) {
+ *type = client->client_id.raw.type;
+ *data = client->client_id.raw.data;
+ *data_len = client->client_id_len -
+ sizeof (client->client_id.raw.type);
+ }
+
+ return 0;
+}
+
+int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
+ const uint8_t *data, size_t data_len) {
+ DHCP_CLIENT_DONT_DESTROY(client);
+ bool need_restart = false;
+
+ assert_return(client, -EINVAL);
+ assert_return(data, -EINVAL);
+ assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL);
+
+ switch (type) {
+ case ARPHRD_ETHER:
+ if (data_len != ETH_ALEN)
+ return -EINVAL;
+ break;
+ case ARPHRD_INFINIBAND:
+ if (data_len != INFINIBAND_ALEN)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) &&
+ client->client_id.raw.type == type &&
+ memcmp(&client->client_id.raw.data, data, data_len) == 0)
+ return 0;
+
+ if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
+ log_dhcp_client(client, "Changing client ID on running DHCP "
+ "client, restarting");
+ need_restart = true;
+ client_stop(client, DHCP_EVENT_STOP);
+ }
+
+ client->client_id.raw.type = type;
+ memcpy(&client->client_id.raw.data, data, data_len);
+ client->client_id_len = data_len + sizeof (client->client_id.raw.type);
if (need_restart && client->state != DHCP_STATE_STOPPED)
sd_dhcp_client_start(client);
@@ -321,10 +403,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
_cleanup_free_ DHCPPacket *packet;
size_t optlen, optoffset, size;
be16_t max_size;
+ usec_t time_now;
+ uint16_t secs;
int r;
assert(client);
- assert(client->secs);
+ assert(client->start_time);
assert(ret);
assert(_optlen);
assert(_optoffset);
@@ -344,7 +428,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
/* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
refuse to issue an DHCP lease if 'secs' is set to zero */
- packet->dhcp.secs = htobe16(client->secs);
+ r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0)
+ return r;
+ assert(time_now >= client->start_time);
+
+ /* seconds between sending first and last DISCOVER
+ * must always be strictly positive to deal with broken servers */
+ secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
+ packet->dhcp.secs = htobe16(secs);
/* RFC2132 section 4.1
A client that cannot receive unicast IP datagrams until its protocol
@@ -369,14 +461,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
if (client->arp_type == ARPHRD_ETHER)
memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN);
+ /* If no client identifier exists, construct one from an ethernet
+ address if present */
+ if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) {
+ client->client_id.eth.type = ARPHRD_ETHER;
+ memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN);
+ client->client_id_len = sizeof (client->client_id.eth);
+ }
+
/* Some DHCP servers will refuse to issue an DHCP lease if the Client
Identifier option is not set */
- r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
- DHCP_OPTION_CLIENT_IDENTIFIER,
- sizeof(client->client_id), &client->client_id);
- if (r < 0)
- return r;
-
+ if (client->client_id_len) {
+ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0,
+ DHCP_OPTION_CLIENT_IDENTIFIER,
+ client->client_id_len,
+ &client->client_id.raw);
+ if (r < 0)
+ return r;
+ }
/* RFC2131 section 3.5:
in its initial DHCPDISCOVER or DHCPREQUEST message, a
@@ -441,24 +543,12 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
static int client_send_discover(sd_dhcp_client *client) {
_cleanup_free_ DHCPPacket *discover = NULL;
size_t optoffset, optlen;
- usec_t time_now;
int r;
assert(client);
assert(client->state == DHCP_STATE_INIT ||
client->state == DHCP_STATE_SELECTING);
- /* See RFC2131 section 4.4.1 */
-
- r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- return r;
- assert(time_now >= client->start_time);
-
- /* seconds between sending first and last DISCOVER
- * must always be strictly positive to deal with broken servers */
- client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1;
-
r = client_message_init(client, &discover, DHCP_DISCOVER,
&optlen, &optoffset);
if (r < 0)
@@ -723,8 +813,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
if (r < 0)
goto error;
- r = sd_event_source_set_name(client->timeout_resend,
- "dhcp4-resend-timer");
+ r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
if (r < 0)
goto error;
@@ -801,8 +890,7 @@ static int client_initialize_io_events(sd_dhcp_client *client,
if (r < 0)
goto error;
- r = sd_event_source_set_name(client->receive_message,
- "dhcp4-receive-message");
+ r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message");
if (r < 0)
goto error;
@@ -832,8 +920,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
r = sd_event_source_set_priority(client->timeout_resend,
client->event_priority);
- r = sd_event_source_set_name(client->timeout_resend,
- "dhcp4-resend-timer");
+ r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
if (r < 0)
goto error;
@@ -875,10 +962,8 @@ static int client_start(sd_dhcp_client *client) {
}
client->fd = r;
- if (client->state == DHCP_STATE_INIT) {
+ if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT)
client->start_time = now(clock_boottime_or_monotonic());
- client->secs = 0;
- }
return client_initialize_events(client, client_receive_message_raw);
}
@@ -944,6 +1029,14 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
if (r < 0)
return r;
+ if (client->client_id_len) {
+ r = dhcp_lease_set_client_id(lease,
+ (uint8_t *) &client->client_id.raw,
+ client->client_id_len);
+ if (r < 0)
+ return r;
+ }
+
r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
if (r != DHCP_OFFER) {
log_dhcp_client(client, "received message was not an OFFER, ignoring");
@@ -1003,6 +1096,14 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
if (r < 0)
return r;
+ if (client->client_id_len) {
+ r = dhcp_lease_set_client_id(lease,
+ (uint8_t *) &client->client_id.raw,
+ client->client_id_len);
+ if (r < 0)
+ return r;
+ }
+
r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
if (r == DHCP_NAK) {
log_dhcp_client(client, "NAK");
@@ -1149,8 +1250,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
if (r < 0)
return r;
- r = sd_event_source_set_name(client->timeout_expire,
- "dhcp4-lifetime");
+ r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime");
if (r < 0)
return r;
@@ -1177,8 +1277,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
if (r < 0)
return r;
- r = sd_event_source_set_name(client->timeout_t2,
- "dhcp4-t2-timeout");
+ r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout");
if (r < 0)
return r;
@@ -1204,8 +1303,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
if (r < 0)
return r;
- r = sd_event_source_set_name(client->timeout_t1,
- "dhcp4-t1-timer");
+ r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer");
if (r < 0)
return r;
@@ -1250,8 +1348,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
if (r < 0)
goto error;
- r = sd_event_source_set_name(client->timeout_resend,
- "dhcp4-resend-timer");
+ r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer");
if (r < 0)
goto error;
} else if (r == -ENOMSG)
@@ -1269,6 +1366,9 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
if (r >= 0) {
client->timeout_resend =
sd_event_source_unref(client->timeout_resend);
+ client->receive_message =
+ sd_event_source_unref(client->receive_message);
+ client->fd = asynchronous_close(client->fd);
if (IN_SET(client->state, DHCP_STATE_REQUESTING,
DHCP_STATE_REBOOTING))
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 4fb01c0729..22a4af6837 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -30,6 +30,7 @@
#include "list.h"
#include "mkdir.h"
#include "fileio.h"
+#include "unaligned.h"
#include "in-addr-util.h"
#include "dhcp-protocol.h"
@@ -50,7 +51,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) {
assert_return(lease, -EINVAL);
- assert_return(lease, -EINVAL);
+ assert_return(lifetime, -EINVAL);
*lifetime = lease->lifetime;
@@ -198,6 +199,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
free(lease->dns);
free(lease->ntp);
free(lease->static_route);
+ free(lease->client_id);
free(lease);
}
@@ -205,14 +207,11 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
}
static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) {
- be32_t val;
-
assert(option);
assert(ret);
if (len == 4) {
- memcpy(&val, option, 4);
- *ret = be32toh(val);
+ *ret = unaligned_read_be32((be32_t*) option);
if (*ret < min)
*ret = min;
@@ -224,14 +223,11 @@ static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) {
}
static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) {
- be16_t val;
-
assert(option);
assert(ret);
if (len == 2) {
- memcpy(&val, option, 2);
- *ret = be16toh(val);
+ *ret = unaligned_read_be16((be16_t*) option);
if (*ret < min)
*ret = min;
@@ -315,23 +311,6 @@ static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct
return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2);
}
-static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) {
- if (msb_octet < 128)
- /* Class A */
- *ret = 8;
- else if (msb_octet < 192)
- /* Class B */
- *ret = 16;
- else if (msb_octet < 224)
- /* Class C */
- *ret = 24;
- else
- /* Class D or E -- no subnet mask */
- return -ERANGE;
-
- return 0;
-}
-
static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes,
size_t *routes_size, size_t *routes_allocated) {
@@ -353,8 +332,10 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_
while (len >= 8) {
struct sd_dhcp_route *route = *routes + *routes_size;
+ int r;
- if (class_prefixlen(*option, &route->dst_prefixlen) < 0) {
+ r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
+ if (r < 0) {
log_error("Failed to determine destination prefix length from class based IP, ignoring");
continue;
}
@@ -600,11 +581,13 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
return 0;
}
-int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
+int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
struct in_addr address;
const struct in_addr *addresses;
+ const uint8_t *client_id;
+ size_t client_id_len;
const char *string;
uint16_t mtu;
struct sd_dhcp_route *routes;
@@ -678,6 +661,18 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0)
serialize_dhcp_routes(f, "ROUTES", routes, r);
+ r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
+ if (r >= 0) {
+ _cleanup_free_ char *client_id_hex;
+
+ client_id_hex = hexmem (client_id, client_id_len);
+ if (!client_id_hex) {
+ r = -ENOMEM;
+ goto finish;
+ }
+ fprintf(f, "CLIENTID=%s\n", client_id_hex);
+ }
+
r = 0;
fflush(f);
@@ -690,16 +685,17 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
finish:
if (r < 0)
- log_error("Failed to save lease data %s: %s", lease_file, strerror(-r));
+ log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
return r;
}
-int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
+int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
_cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
_cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
*server_address = NULL, *next_server = NULL,
- *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL;
+ *dns = NULL, *ntp = NULL, *mtu = NULL,
+ *routes = NULL, *client_id_hex = NULL;
struct in_addr addr;
int r;
@@ -723,13 +719,13 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
"HOSTNAME", &lease->hostname,
"ROOT_PATH", &lease->root_path,
"ROUTES", &routes,
+ "CLIENTID", &client_id_hex,
NULL);
if (r < 0) {
if (r == -ENOENT)
return 0;
- log_error("Failed to read %s: %s", lease_file, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to read %s: %m", lease_file);
}
r = inet_pton(AF_INET, address, &addr);
@@ -797,6 +793,16 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
return r;
}
+ if (client_id_hex) {
+ if (strlen (client_id_hex) % 2)
+ return -EINVAL;
+
+ lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
+ if (!lease->client_id)
+ return -ENOMEM;
+ lease->client_id_len = strlen (client_id_hex) / 2;
+ }
+
*ret = lease;
lease = NULL;
@@ -821,3 +827,32 @@ int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
return 0;
}
+
+int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
+ size_t *client_id_len) {
+ assert_return(lease, -EINVAL);
+ assert_return(client_id, -EINVAL);
+ assert_return(client_id_len, -EINVAL);
+
+ *client_id = lease->client_id;
+ *client_id_len = lease->client_id_len;
+ return 0;
+}
+
+int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id,
+ size_t client_id_len) {
+ assert_return(lease, -EINVAL);
+ assert_return((!client_id && !client_id_len) ||
+ (client_id && client_id_len), -EINVAL);
+
+ free (lease->client_id);
+ lease->client_id = NULL;
+ lease->client_id_len = 0;
+
+ if (client_id) {
+ lease->client_id = memdup (client_id, client_id_len);
+ lease->client_id_len = client_id_len;
+ }
+
+ return 0;
+}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index fa4f9b5dc2..017371e837 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -62,6 +62,7 @@ struct sd_dhcp6_client {
usec_t transaction_start;
struct sd_dhcp6_lease *lease;
int fd;
+ bool information_request;
be16_t *req_opts;
size_t req_opts_allocated;
size_t req_opts_len;
@@ -200,19 +201,19 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
switch (type) {
case DHCP6_DUID_LLT:
- if (duid_len <= sizeof(client->duid.llt))
+ if (duid_len <= sizeof(client->duid.llt) - 2)
return -EINVAL;
break;
case DHCP6_DUID_EN:
- if (duid_len != sizeof(client->duid.en))
+ if (duid_len != sizeof(client->duid.en) - 2)
return -EINVAL;
break;
case DHCP6_DUID_LL:
- if (duid_len <= sizeof(client->duid.ll))
+ if (duid_len <= sizeof(client->duid.ll) - 2)
return -EINVAL;
break;
case DHCP6_DUID_UUID:
- if (duid_len != sizeof(client->duid.uuid))
+ if (duid_len != sizeof(client->duid.uuid) - 2)
return -EINVAL;
break;
default:
@@ -222,7 +223,26 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du
client->duid.raw.type = htobe16(type);
memcpy(&client->duid.raw.data, duid, duid_len);
- client->duid_len = duid_len;
+ client->duid_len = duid_len + 2; /* +2 for sizeof(type) */
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
+ bool enabled) {
+ assert_return(client, -EINVAL);
+
+ client->information_request = enabled;
+
+ return 0;
+}
+
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
+ bool *enabled) {
+ assert_return(client, -EINVAL);
+ assert_return(enabled, -EINVAL);
+
+ *enabled = client->information_request;
return 0;
}
@@ -333,6 +353,11 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
message->transaction_id = client->transaction_id;
switch(client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ message->type = DHCP6_INFORMATION_REQUEST;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
message->type = DHCP6_SOLICIT;
@@ -494,6 +519,12 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ init_retransmit_time = DHCP6_INF_TIMEOUT;
+ max_retransmit_time = DHCP6_INF_MAX_RT;
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
if (client->retransmit_count && client->lease) {
@@ -590,8 +621,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
if (r < 0)
goto error;
- r = sd_event_source_set_name(client->timeout_resend,
- "dhcp6-resend-timer");
+ r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer");
if (r < 0)
goto error;
@@ -614,8 +644,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
if (r < 0)
goto error;
- r = sd_event_source_set_name(client->timeout_resend_expire,
- "dhcp6-resend-expire-timer");
+ r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer");
if (r < 0)
goto error;
}
@@ -746,6 +775,12 @@ static int client_parse_message(sd_dhcp6_client *client,
break;
case DHCP6_OPTION_IA_NA:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ log_dhcp6_client(client, "Information request ignoring IA NA option");
+
+ break;
+ }
+
r = dhcp6_option_parse_ia(&optval, &optlen, optcode,
&lease->ia);
if (r < 0 && r != -ENOMSG)
@@ -772,16 +807,21 @@ static int client_parse_message(sd_dhcp6_client *client,
}
}
- if ((r < 0 && r != -ENOMSG) || !clientid) {
+ if (r == -ENOMSG)
+ r = 0;
+
+ if (r < 0 || !clientid) {
log_dhcp6_client(client, "%s has incomplete options",
dhcp6_message_type_to_string(message->type));
return -EINVAL;
}
- r = dhcp6_lease_get_serverid(lease, &id, &id_len);
- if (r < 0)
- log_dhcp6_client(client, "%s has no server id",
- dhcp6_message_type_to_string(message->type));
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ r = dhcp6_lease_get_serverid(lease, &id, &id_len);
+ if (r < 0)
+ log_dhcp6_client(client, "%s has no server id",
+ dhcp6_message_type_to_string(message->type));
+ }
return r;
}
@@ -813,12 +853,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply,
return 0;
}
- if (client->lease)
+ if (client->lease) {
dhcp6_lease_clear_timers(&client->lease->ia);
+ client->lease = sd_dhcp6_lease_unref(client->lease);
+ }
- client->lease = sd_dhcp6_lease_unref(client->lease);
- client->lease = lease;
- lease = NULL;
+ if (client->state != DHCP6_STATE_INFORMATION_REQUEST) {
+ client->lease = lease;
+ lease = NULL;
+ }
return DHCP6_STATE_BOUND;
}
@@ -845,7 +888,8 @@ static int client_receive_advertise(sd_dhcp6_client *client,
return r;
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
- if (!client->lease || r < 0 || pref_advertise > pref_lease) {
+
+ if (r < 0 || pref_advertise > pref_lease) {
sd_dhcp6_lease_unref(client->lease);
client->lease = lease;
lease = NULL;
@@ -912,6 +956,17 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
switch (client->state) {
+ case DHCP6_STATE_INFORMATION_REQUEST:
+ r = client_receive_reply(client, message, len);
+ if (r < 0)
+ return 0;
+
+ client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
+
+ client_start(client, DHCP6_STATE_STOPPED);
+
+ break;
+
case DHCP6_STATE_SOLICITATION:
r = client_receive_advertise(client, message, len);
@@ -970,6 +1025,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
assert_return(client->index > 0, -EINVAL);
assert_return(client->state != state, -EINVAL);
+ log_dhcp6_client(client, "client state %d new state %d", client->state, state);
client->timeout_resend_expire =
sd_event_source_unref(client->timeout_resend_expire);
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
@@ -987,38 +1043,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
switch (state) {
case DHCP6_STATE_STOPPED:
- case DHCP6_STATE_SOLICITATION:
+ if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
+ client->state = DHCP6_STATE_STOPPED;
- r = client_ensure_iaid(client);
- if (r < 0)
- return r;
-
- r = dhcp6_network_bind_udp_socket(client->index, NULL);
- if (r < 0)
- return r;
-
- client->fd = r;
-
- r = sd_event_add_io(client->event, &client->receive_message,
- client->fd, EPOLLIN, client_receive_message,
- client);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(client->receive_message,
- client->event_priority);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_name(client->receive_message,
- "dhcp6-receive-message");
- if (r < 0)
- return r;
+ return 0;
+ }
+ /* fall through */
+ case DHCP6_STATE_SOLICITATION:
client->state = DHCP6_STATE_SOLICITATION;
break;
+ case DHCP6_STATE_INFORMATION_REQUEST:
case DHCP6_STATE_REQUEST:
case DHCP6_STATE_RENEW:
case DHCP6_STATE_REBIND:
@@ -1059,8 +1096,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
if (r < 0)
return r;
- r = sd_event_source_set_name(client->lease->ia.timeout_t1,
- "dhcp6-t1-timeout");
+ r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout");
if (r < 0)
return r;
@@ -1084,8 +1120,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
if (r < 0)
return r;
- r = sd_event_source_set_name(client->lease->ia.timeout_t2,
- "dhcp6-t2-timeout");
+ r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout");
if (r < 0)
return r;
@@ -1108,8 +1143,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
if (r < 0)
return r;
- r = sd_event_source_set_name(client->timeout_resend,
- "dhcp6-resend-timeout");
+ r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout");
if (r < 0)
return r;
@@ -1126,6 +1160,7 @@ int sd_dhcp6_client_stop(sd_dhcp6_client *client)
int sd_dhcp6_client_start(sd_dhcp6_client *client)
{
int r = 0;
+ enum DHCP6State state = DHCP6_STATE_SOLICITATION;
assert_return(client, -EINVAL);
assert_return(client->event, -EINVAL);
@@ -1135,7 +1170,44 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client)
if (r < 0)
return r;
- return client_start(client, DHCP6_STATE_SOLICITATION);
+ r = client_ensure_iaid(client);
+ if (r < 0)
+ return r;
+
+ r = dhcp6_network_bind_udp_socket(client->index, NULL);
+ if (r < 0)
+ return r;
+
+ client->fd = r;
+
+ r = sd_event_add_io(client->event, &client->receive_message,
+ client->fd, EPOLLIN, client_receive_message,
+ client);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_priority(client->receive_message,
+ client->event_priority);
+ if (r < 0)
+ goto error;
+
+ r = sd_event_source_set_description(client->receive_message,
+ "dhcp6-receive-message");
+ if (r < 0)
+ goto error;
+
+ if (client->information_request)
+ state = DHCP6_STATE_INFORMATION_REQUEST;
+
+ log_dhcp6_client(client, "Started in %s mode",
+ client->information_request? "Information request":
+ "Managed");
+
+ return client_start(client, state);
+
+error:
+ client_reset(client);
+ return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index e2715ea659..8960fac92f 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -110,9 +110,11 @@ int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) {
}
int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) {
- assert_return(lease, -EINVAL);
assert_return(preference, -EINVAL);
+ if (!lease)
+ return -EINVAL;
+
*preference = lease->preference;
return 0;
diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c
index bbb4531ddb..cb06151514 100644
--- a/src/libsystemd-network/sd-icmp6-nd.c
+++ b/src/libsystemd-network/sd-icmp6-nd.c
@@ -54,7 +54,7 @@ struct sd_icmp6_nd {
void *userdata;
};
-#define log_icmp6_nd(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__)
static void icmp6_nd_notify(sd_icmp6_nd *nd, int event)
{
@@ -278,7 +278,7 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
return 0;
}
- r = sd_event_source_set_name(nd->timeout, "icmp6-timeout");
+ r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
if (r < 0) {
icmp6_nd_notify(nd, r);
return 0;
@@ -328,7 +328,7 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
if (r < 0)
goto error;
- r = sd_event_source_set_name(nd->recv, "icmp6-receive-message");
+ r = sd_event_source_set_description(nd->recv, "icmp6-receive-message");
if (r < 0)
goto error;
@@ -341,7 +341,7 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
if (r < 0)
goto error;
- r = sd_event_source_set_name(nd->timeout, "icmp6-timeout");
+ r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
error:
if (r < 0)
icmp6_nd_init(nd);
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 8b243319b6..8626d4afa9 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -353,7 +353,7 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void
if (r < 0)
goto out;
- r = sd_event_source_set_name(ll->timer, "ipv4ll-timer");
+ r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
if (r < 0)
goto out;
}
@@ -564,7 +564,7 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) {
if (r < 0)
goto out;
- r = sd_event_source_set_name(ll->receive_message, "ipv4ll-receive-message");
+ r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
if (r < 0)
goto out;
@@ -581,7 +581,7 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) {
if (r < 0)
goto out;
- r = sd_event_source_set_name(ll->timer, "ipv4ll-timer");
+ r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
out:
if (r < 0)
ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
new file mode 100644
index 0000000000..4f49b799ec
--- /dev/null
+++ b/src/libsystemd-network/sd-pppoe.c
@@ -0,0 +1,802 @@
+/*-*- 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 "socket-util.h"
+#include "async.h"
+#include "refcnt.h"
+#include "unaligned.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 {
+ RefCount 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)
+ assert_se(REFCNT_INC(ppp->n_ref) >= 2);
+
+ return ppp;
+}
+
+sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) {
+ if (ppp && REFCNT_DEC(ppp->n_ref) <= 0) {
+ 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 = REFCNT_INIT;
+ 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;
+ int r;
+
+ assert(ppp);
+
+ r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
+ if (r == -ENODATA)
+ next_timeout = now(clock_boottime_or_monotonic());
+ else 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)",
+ 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],
+ ppp->tags.service_name ? : "",
+ 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, 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, 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;
+}
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 26b28a20e8..75908391f0 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -41,7 +41,7 @@ static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
};
-static bool verbose = false;
+static bool verbose = true;
static sd_event_source *hangcheck;
static int test_dhcp_fd[2];
@@ -335,13 +335,19 @@ int detect_virtualization(const char **id) {
return 1;
}
-int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
- assert_se(index == test_index);
+static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
+ void *userdata) {
+ sd_event *e = userdata;
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
- return -errno;
+ assert_se(e);
+ assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
- return test_dhcp_fd[0];
+ assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
+
+ if (verbose)
+ printf(" got DHCPv6 event %d\n", event);
+
+ sd_event_exit(e, 0);
}
static int test_client_send_reply(DHCP6Message *request) {
@@ -513,6 +519,83 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option,
return 0;
}
+static void test_client_information_cb(sd_dhcp6_client *client, int event,
+ void *userdata) {
+ sd_event *e = userdata;
+
+ assert_se(e);
+ assert_se(event == DHCP6_EVENT_INFORMATION_REQUEST);
+
+ if (verbose)
+ printf(" got DHCPv6 event %d\n", event);
+
+ assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
+ assert_se(sd_dhcp6_client_set_callback(client,
+ test_client_solicit_cb, e) >= 0);
+
+ assert_se(sd_dhcp6_client_start(client) >= 0);
+}
+
+static int test_client_verify_information_request(DHCP6Message *information_request,
+ uint8_t *option, size_t len) {
+
+ _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL;
+ uint8_t *optval;
+ uint16_t optcode;
+ size_t optlen;
+ bool found_clientid = false, found_elapsed_time = false;
+ int r;
+ struct in6_addr addr;
+ uint32_t lt_pref, lt_valid;
+
+ assert_se(information_request->type == DHCP6_INFORMATION_REQUEST);
+
+ assert_se(dhcp6_lease_new(&lease) >= 0);
+
+ while ((r = dhcp6_option_parse(&option, &len,
+ &optcode, &optlen, &optval)) >= 0) {
+ switch(optcode) {
+ case DHCP6_OPTION_CLIENTID:
+ assert_se(!found_clientid);
+ found_clientid = true;
+
+ assert_se(optlen == sizeof(test_duid));
+ memcpy(&test_duid, optval, sizeof(test_duid));
+
+ break;
+
+ case DHCP6_OPTION_IA_NA:
+ assert_not_reached("IA TA option must not be present");
+
+ break;
+
+ case DHCP6_OPTION_SERVERID:
+ assert_not_reached("Server ID option must not be present");
+
+ break;
+
+ case DHCP6_OPTION_ELAPSED_TIME:
+ assert_se(!found_elapsed_time);
+ found_elapsed_time = true;
+
+ assert_se(optlen == 2);
+
+ break;
+ }
+ }
+
+ assert_se(r == -ENOMSG);
+ assert_se(found_clientid && found_elapsed_time);
+
+ assert_se(sd_dhcp6_lease_get_first_address(lease, &addr, &lt_pref,
+ &lt_valid) == -ENOMSG);
+
+ assert_se(sd_dhcp6_lease_get_next_address(lease, &addr, &lt_pref,
+ &lt_valid) == -ENOMSG);
+
+ return 0;
+}
+
int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
const void *packet, size_t len) {
struct in6_addr mcast =
@@ -534,10 +617,14 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
assert_se(message->transaction_id & 0x00ffffff);
if (test_client_message_num == 0) {
+ test_client_verify_information_request(message, option, len);
+ test_client_send_reply(message);
+ test_client_message_num++;
+ } else if (test_client_message_num == 1) {
test_client_verify_solicit(message, option, len);
test_client_send_advertise(message);
test_client_message_num++;
- } else if (test_client_message_num == 1) {
+ } else if (test_client_message_num == 2) {
test_client_verify_request(message, option, len);
test_client_send_reply(message);
test_client_message_num++;
@@ -546,24 +633,19 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
return len;
}
-static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
- void *userdata) {
- sd_event *e = userdata;
-
- assert_se(e);
- assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
-
- assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY);
+int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
+ assert_se(index == test_index);
- if (verbose)
- printf(" got DHCPv6 event %d\n", event);
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
+ return -errno;
- sd_event_exit(e, 0);
+ return test_dhcp_fd[0];
}
static int test_client_solicit(sd_event *e) {
sd_dhcp6_client *client;
usec_t time_now = now(clock_boottime_or_monotonic());
+ bool val = true;
if (verbose)
printf("* %s\n", __FUNCTION__);
@@ -578,8 +660,14 @@ static int test_client_solicit(sd_event *e) {
sizeof (mac_addr),
ARPHRD_ETHER) >= 0);
+ assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
+ assert_se(val == false);
+ assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
+ assert_se(sd_dhcp6_client_get_information_request(client, &val) >= 0);
+ assert_se(val == true);
+
assert_se(sd_dhcp6_client_set_callback(client,
- test_client_solicit_cb, e) >= 0);
+ test_client_information_cb, e) >= 0);
assert_se(sd_event_add_time(e, &hangcheck, clock_boottime_or_monotonic(),
time_now + 2 * USEC_PER_SEC, 0,
diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c
index afa8562659..be64d334fa 100644
--- a/src/libsystemd-network/test-icmp6-rs.c
+++ b/src/libsystemd-network/test-icmp6-rs.c
@@ -36,13 +36,13 @@ static int test_fd[2];
static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
void *userdata) {
- assert(false);
+ assert_se(false);
return 0;
}
int dhcp_network_icmp6_bind_router_solicitation(int index) {
- assert(index == 42);
+ assert_se(index == 42);
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
return -errno;
@@ -69,7 +69,7 @@ static int send_ra(uint8_t flags) {
advertisement[5] = flags;
- assert(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+ assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
sizeof(advertisement));
if (verbose)
@@ -93,9 +93,9 @@ static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
{ ND_RA_FLAG_OTHER, ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER },
{ ND_RA_FLAG_MANAGED, ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED }
};
- assert(nd);
+ assert_se(nd);
- assert(event == flag_event[idx].event);
+ assert_se(event == flag_event[idx].event);
idx++;
if (verbose)
@@ -114,31 +114,31 @@ static void test_rs(sd_event *e) {
if (verbose)
printf("* %s\n", __FUNCTION__);
- assert(sd_icmp6_nd_new(&nd) >= 0);
- assert(nd);
+ assert_se(sd_icmp6_nd_new(&nd) >= 0);
+ assert_se(nd);
- assert(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
+ assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
- assert(sd_icmp6_nd_set_index(nd, 42) >= 0);
- assert(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
- assert(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 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(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
+ 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(sd_icmp6_nd_stop(nd) >= 0);
- assert(sd_icmp6_router_solicitation_start(nd) >= 0);
- assert(sd_icmp6_nd_stop(nd) >= 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(sd_icmp6_router_solicitation_start(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(!nd);
+ assert_se(!nd);
close(test_fd[1]);
}
@@ -146,7 +146,7 @@ static void test_rs(sd_event *e) {
int main(int argc, char *argv[]) {
sd_event *e;
- assert(sd_event_new(&e) >= 0);
+ assert_se(sd_event_new(&e) >= 0);
log_set_max_level(LOG_DEBUG);
log_parse_environment();
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
new file mode 100644
index 0000000000..0d419aa172
--- /dev/null
+++ b/src/libsystemd-network/test-pppoe.c
@@ -0,0 +1,181 @@
+/*-*- 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 <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <linux/veth.h>
+#include <net/if.h>
+
+#include "util.h"
+#include "socket-util.h"
+#include "sd-event.h"
+#include "event-util.h"
+#include "sd-rtnl.h"
+#include "rtnl-util.h"
+#include "sd-pppoe.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 PPPOE_EVENT_RUNNING:
+ assert_se(pppoe_state == -1);
+ log_info("running");
+ break;
+ case PPPOE_EVENT_STOPPED:
+ assert_se(pppoe_state == 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_rtnl *rtnl;
+ sd_rtnl_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_rtnl_open(&rtnl, 0) >= 0);
+ assert_se(sd_rtnl_attach_event(rtnl, e, 0) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
+ assert_se(sd_rtnl_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
+ assert_se(sd_rtnl_message_open_container(m, IFLA_LINKINFO) >= 0);
+ assert_se(sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
+ assert_se(sd_rtnl_message_open_container(m, VETH_INFO_PEER) >= 0);
+ assert_se(sd_rtnl_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
+ assert_se(sd_rtnl_message_close_container(m) >= 0);
+ assert_se(sd_rtnl_message_close_container(m) >= 0);
+ assert_se(sd_rtnl_message_close_container(m) >= 0);
+ assert_se(sd_rtnl_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_rtnl_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_rtnl_call(rtnl, m, 0, NULL) >= 0);
+
+ m = sd_rtnl_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_rtnl_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-Auxillary",
+ "-S", "Service-Second-Auxillary",
+ 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_rtnl_message_unref(m));
+ assert_se(!sd_rtnl_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;
+ }
+}
diff --git a/src/libsystemd-terminal/evcat.c b/src/libsystemd-terminal/evcat.c
index 9e8a262b79..f4c25b5556 100644
--- a/src/libsystemd-terminal/evcat.c
+++ b/src/libsystemd-terminal/evcat.c
@@ -137,16 +137,12 @@ static int evcat_new(Evcat **out) {
return log_oom();
r = sd_pid_get_session(getpid(), &e->session);
- if (r < 0) {
- log_error("Cannot retrieve logind session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot retrieve logind session: %m");
r = sd_session_get_seat(e->session, &e->seat);
- if (r < 0) {
- log_error("Cannot retrieve seat of logind session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot retrieve seat of logind session: %m");
e->managed = is_managed(e->session);
@@ -318,17 +314,13 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e
name,
evcat_idev_fn,
e);
- if (r < 0) {
- log_error("Cannot create idev session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot create idev session: %m");
if (e->managed) {
r = sysview_session_take_control(ev->session_add.session);
- if (r < 0) {
- log_error("Cannot request session control: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot request session control: %m");
}
idev_session_enable(e->idev_session);
@@ -345,10 +337,8 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_EVDEV) {
r = idev_session_add_evdev(e->idev_session, sysview_device_get_ud(d));
- if (r < 0) {
- log_error("Cannot add evdev device to idev: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot add evdev device to idev: %m");
}
break;
@@ -357,31 +347,23 @@ static int evcat_sysview_fn(sysview_context *c, void *userdata, sysview_event *e
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_EVDEV) {
r = idev_session_remove_evdev(e->idev_session, sysview_device_get_ud(d));
- if (r < 0) {
- log_error("Cannot remove evdev device from idev: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot remove evdev device from idev: %m");
}
break;
case SYSVIEW_EVENT_SESSION_CONTROL:
r = ev->session_control.error;
- if (r < 0) {
- log_error("Cannot acquire session control: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot acquire session control: %m");
r = ioctl(1, KDSKBMODE, K_UNICODE);
- if (r < 0) {
- log_error("Cannot set K_UNICODE on stdout: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Cannot set K_UNICODE on stdout: %m");
r = ioctl(1, KDSETMODE, KD_TEXT);
- if (r < 0) {
- log_error("Cannot set KD_TEXT on stdout: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Cannot set KD_TEXT on stdout: %m");
printf("\n");
diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c
index dba6db2691..2df63537f0 100644
--- a/src/libsystemd-terminal/grdev-drm.c
+++ b/src/libsystemd-terminal/grdev-drm.c
@@ -468,9 +468,11 @@ static int grdrm_plane_resync(grdrm_plane *plane) {
if (r == -ENOENT) {
card->async_hotplug = true;
r = 0;
- log_debug("grdrm: %s: plane %u removed during resync", card->base.name, plane->object.id);
+ log_debug("grdrm: %s: plane %u removed during resync",
+ card->base.name, plane->object.id);
} else {
- log_debug("grdrm: %s: cannot retrieve plane %u: %m", card->base.name, plane->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve plane %u: %m",
+ card->base.name, plane->object.id);
}
return r;
@@ -625,9 +627,11 @@ static int grdrm_connector_resync(grdrm_connector *connector) {
if (r == -ENOENT) {
card->async_hotplug = true;
r = 0;
- log_debug("grdrm: %s: connector %u removed during resync", card->base.name, connector->object.id);
+ log_debug("grdrm: %s: connector %u removed during resync",
+ card->base.name, connector->object.id);
} else {
- log_debug("grdrm: %s: cannot retrieve connector %u: %m", card->base.name, connector->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve connector %u: %m",
+ card->base.name, connector->object.id);
}
return r;
@@ -783,9 +787,11 @@ static int grdrm_encoder_resync(grdrm_encoder *encoder) {
if (r == -ENOENT) {
card->async_hotplug = true;
r = 0;
- log_debug("grdrm: %s: encoder %u removed during resync", card->base.name, encoder->object.id);
+ log_debug("grdrm: %s: encoder %u removed during resync",
+ card->base.name, encoder->object.id);
} else {
- log_debug("grdrm: %s: cannot retrieve encoder %u: %m", card->base.name, encoder->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve encoder %u: %m",
+ card->base.name, encoder->object.id);
}
return r;
@@ -916,9 +922,11 @@ static int grdrm_crtc_resync(grdrm_crtc *crtc) {
if (r == -ENOENT) {
card->async_hotplug = true;
r = 0;
- log_debug("grdrm: %s: crtc %u removed during resync", card->base.name, crtc->object.id);
+ log_debug("grdrm: %s: crtc %u removed during resync",
+ card->base.name, crtc->object.id);
} else {
- log_debug("grdrm: %s: cannot retrieve crtc %u: %m", card->base.name, crtc->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve crtc %u: %m",
+ card->base.name, crtc->object.id);
}
return r;
@@ -1119,8 +1127,8 @@ static void grdrm_crtc_commit_deep(grdrm_crtc *crtc, grdev_fb *basefb) {
r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
if (r < 0) {
r = -errno;
- log_debug("grdrm: %s: cannot set crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot set crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
grdrm_card_async(card, r);
return;
@@ -1188,8 +1196,8 @@ static int grdrm_crtc_commit_flip(grdrm_crtc *crtc, grdev_fb *basefb) {
* possible to see whether cards support page-flipping, so
* avoid logging on each frame. */
if (r != -EINVAL)
- log_debug("grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot schedule page-flip on crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
if (grdrm_card_async(card, r))
return r;
@@ -1241,8 +1249,8 @@ static void grdrm_crtc_commit(grdrm_crtc *crtc) {
r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
if (r < 0) {
r = -errno;
- log_debug("grdrm: %s: cannot shutdown crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot shutdown crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
grdrm_card_async(card, r);
return;
@@ -1298,8 +1306,8 @@ static void grdrm_crtc_restore(grdrm_crtc *crtc) {
r = ioctl(card->fd, DRM_IOCTL_MODE_SETCRTC, &set_crtc);
if (r < 0) {
r = -errno;
- log_debug("grdrm: %s: cannot restore crtc %" PRIu32 ": %m",
- card->base.name, crtc->object.id);
+ log_debug_errno(errno, "grdrm: %s: cannot restore crtc %" PRIu32 ": %m",
+ card->base.name, crtc->object.id);
grdrm_card_async(card, r);
return;
@@ -1393,9 +1401,9 @@ static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_
r = ioctl(card->fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
if (r < 0) {
- r = -errno;
- log_debug("grdrm: %s: cannot create dumb buffer %" PRIu32 "x%" PRIu32": %m",
- card->base.name, fb->base.width, fb->base.height);
+ r = negative_errno();
+ log_debug_errno(errno, "grdrm: %s: cannot create dumb buffer %" PRIu32 "x%" PRIu32": %m",
+ card->base.name, fb->base.width, fb->base.height);
return r;
}
@@ -1407,17 +1415,17 @@ static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_
r = ioctl(card->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
if (r < 0) {
- r = -errno;
- log_debug("grdrm: %s: cannot map dumb buffer %" PRIu32 "x%" PRIu32": %m",
- card->base.name, fb->base.width, fb->base.height);
+ r = negative_errno();
+ log_debug_errno(errno, "grdrm: %s: cannot map dumb buffer %" PRIu32 "x%" PRIu32": %m",
+ card->base.name, fb->base.width, fb->base.height);
return r;
}
fb->base.maps[0] = mmap(0, fb->sizes[0], PROT_WRITE, MAP_SHARED, card->fd, map_dumb.offset);
if (fb->base.maps[0] == MAP_FAILED) {
- r = -errno;
- log_debug("grdrm: %s: cannot memory-map dumb buffer %" PRIu32 "x%" PRIu32": %m",
- card->base.name, fb->base.width, fb->base.height);
+ r = negative_errno();
+ log_debug_errno(errno, "grdrm: %s: cannot memory-map dumb buffer %" PRIu32 "x%" PRIu32": %m",
+ card->base.name, fb->base.width, fb->base.height);
return r;
}
@@ -1433,9 +1441,9 @@ static int grdrm_fb_new(grdrm_fb **out, grdrm_card *card, const struct drm_mode_
r = ioctl(card->fd, DRM_IOCTL_MODE_ADDFB2, &add_fb);
if (r < 0) {
- r = -errno;
- log_debug("grdrm: %s: cannot add framebuffer %" PRIu32 "x%" PRIu32": %m",
- card->base.name, fb->base.width, fb->base.height);
+ r = negative_errno();
+ log_debug_errno(errno, "grdrm: %s: cannot add framebuffer %" PRIu32 "x%" PRIu32": %m",
+ card->base.name, fb->base.width, fb->base.height);
return r;
}
@@ -1461,8 +1469,8 @@ grdrm_fb *grdrm_fb_free(grdrm_fb *fb) {
if (fb->id > 0 && fb->card->fd >= 0) {
r = ioctl(fb->card->fd, DRM_IOCTL_MODE_RMFB, fb->id);
if (r < 0)
- log_debug("grdrm: %s: cannot delete framebuffer %" PRIu32 ": %m",
- fb->card->base.name, fb->id);
+ log_debug_errno(errno, "grdrm: %s: cannot delete framebuffer %" PRIu32 ": %m",
+ fb->card->base.name, fb->id);
}
for (i = 0; i < ELEMENTSOF(fb->handles); ++i) {
@@ -1475,8 +1483,8 @@ grdrm_fb *grdrm_fb_free(grdrm_fb *fb) {
destroy_dumb.handle = fb->handles[i];
r = ioctl(fb->card->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb);
if (r < 0)
- log_debug("grdrm: %s: cannot destroy dumb-buffer %" PRIu32 ": %m",
- fb->card->base.name, fb->handles[i]);
+ log_debug_errno(errno, "grdrm: %s: cannot destroy dumb-buffer %" PRIu32 ": %m",
+ fb->card->base.name, fb->handles[i]);
}
}
@@ -1777,7 +1785,8 @@ static int grdrm_card_resync(grdrm_card *card) {
r = ioctl(card->fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
if (r < 0) {
r = -errno;
- log_debug("grdrm: %s: cannot retrieve drm resources: %m", card->base.name);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve drm resources: %m",
+ card->base.name);
return r;
}
@@ -1788,7 +1797,8 @@ static int grdrm_card_resync(grdrm_card *card) {
r = ioctl(card->fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &pres);
if (r < 0) {
r = -errno;
- log_debug("grdrm: %s: cannot retrieve drm plane-resources: %m", card->base.name);
+ log_debug_errno(errno, "grdrm: %s: cannot retrieve drm plane-resources: %m",
+ card->base.name);
return r;
}
@@ -1799,7 +1809,8 @@ static int grdrm_card_resync(grdrm_card *card) {
n = ALIGN_POWER2(max);
if (!n || n > UINT16_MAX) {
- log_debug("grdrm: %s: excessive DRM resource limit: %" PRIu32, card->base.name, max);
+ log_debug("grdrm: %s: excessive DRM resource limit: %" PRIu32,
+ card->base.name, max);
return -ERANGE;
}
@@ -2186,8 +2197,8 @@ static void grdrm_card_hotplug(grdrm_card *card) {
card->ready = false;
r = grdrm_card_resync(card);
if (r < 0) {
- log_debug("grdrm: %s/%s: cannot re-sync card: %s",
- card->base.session->name, card->base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot re-sync card: %m",
+ card->base.session->name, card->base.name);
return;
}
@@ -2228,7 +2239,8 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void *
if (errno == EAGAIN || errno == EINTR)
return 0;
- log_debug("grdrm: %s/%s: read error: %m", card->base.session->name, card->base.name);
+ log_debug_errno(errno, "grdrm: %s/%s: read error: %m",
+ card->base.session->name, card->base.name);
grdrm_card_close(card);
return 0;
}
@@ -2237,7 +2249,8 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void *
event = (void*)buf;
if (len < sizeof(*event) || len < event->length) {
- log_debug("grdrm: %s/%s: truncated event", card->base.session->name, card->base.name);
+ log_debug("grdrm: %s/%s: truncated event",
+ card->base.session->name, card->base.name);
break;
}
@@ -2245,7 +2258,8 @@ static int grdrm_card_io_fn(sd_event_source *s, int fd, uint32_t revents, void *
case DRM_EVENT_FLIP_COMPLETE:
vblank = (void*)event;
if (event->length < sizeof(*vblank)) {
- log_debug("grdrm: %s/%s: truncated vblank event", card->base.session->name, card->base.name);
+ log_debug("grdrm: %s/%s: truncated vblank event",
+ card->base.session->name, card->base.name);
break;
}
@@ -2415,8 +2429,8 @@ static int grdrm_card_open(grdrm_card *card, int dev_fd) {
r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap);
card->cap_dumb = r >= 0 && cap.value;
if (r < 0)
- log_debug("grdrm: %s/%s: cannot retrieve DUMB_BUFFER capability: %s",
- card->base.session->name, card->base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot retrieve DUMB_BUFFER capability: %m",
+ card->base.session->name, card->base.name);
else if (!card->cap_dumb)
log_debug("grdrm: %s/%s: DUMB_BUFFER capability not supported",
card->base.session->name, card->base.name);
@@ -2427,8 +2441,8 @@ static int grdrm_card_open(grdrm_card *card, int dev_fd) {
r = ioctl(card->fd, DRM_IOCTL_GET_CAP, &cap);
card->cap_monotonic = r >= 0 && cap.value;
if (r < 0)
- log_debug("grdrm: %s/%s: cannot retrieve TIMESTAMP_MONOTONIC capability: %s",
- card->base.session->name, card->base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot retrieve TIMESTAMP_MONOTONIC capability: %m",
+ card->base.session->name, card->base.name);
else if (!card->cap_monotonic)
log_debug("grdrm: %s/%s: TIMESTAMP_MONOTONIC is disabled globally, fix this NOW!",
card->base.session->name, card->base.name);
@@ -2498,8 +2512,8 @@ static void unmanaged_card_enable(grdev_card *basecard) {
fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
/* not fatal; simply ignore the device */
- log_debug("grdrm: %s/%s: cannot open node %s: %m",
- basecard->session->name, basecard->name, cu->devnode);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot open node %s: %m",
+ basecard->session->name, basecard->name, cu->devnode);
return;
}
@@ -2507,16 +2521,16 @@ static void unmanaged_card_enable(grdev_card *basecard) {
r = grdrm_card_open(&cu->card, fd);
if (r < 0) {
- log_debug("grdrm: %s/%s: cannot open: %s",
- basecard->session->name, basecard->name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
+ basecard->session->name, basecard->name);
return;
}
}
r = ioctl(cu->card.fd, DRM_IOCTL_SET_MASTER, 0);
if (r < 0) {
- log_debug("grdrm: %s/%s: cannot acquire DRM-Master: %m",
- basecard->session->name, basecard->name);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot acquire DRM-Master: %m",
+ basecard->session->name, basecard->name);
return;
}
@@ -2566,8 +2580,8 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u
fd = open(cu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
/* not fatal; allow uaccess based control on activation */
- log_debug("grdrm: %s/%s: cannot open node %s: %m",
- basecard->session->name, basecard->name, cu->devnode);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot open node %s: %m",
+ basecard->session->name, basecard->name, cu->devnode);
} else {
/* We might get DRM-Master implicitly on open(); drop it immediately
* so we acquire it only once we're actually enabled. We don't
@@ -2575,13 +2589,13 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u
* weird errors, anyway. */
r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0);
if (r < 0 && errno != EACCES && errno != EINVAL)
- log_debug("grdrm: %s/%s: cannot drop DRM-Master: %m",
- basecard->session->name, basecard->name);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot drop DRM-Master: %m",
+ basecard->session->name, basecard->name);
r = grdrm_card_open(&cu->card, fd);
if (r < 0)
- log_debug("grdrm: %s/%s: cannot open: %s",
- basecard->session->name, basecard->name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
+ basecard->session->name, basecard->name);
}
if (out)
@@ -2724,8 +2738,8 @@ static int managed_card_pause_device_fn(sd_bus *bus,
}
if (r < 0)
- log_debug("grdrm: %s/%s: cannot send PauseDeviceComplete: %s",
- session->name, cm->card.base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot send PauseDeviceComplete: %m",
+ session->name, cm->card.base.name);
}
return 0;
@@ -2771,15 +2785,15 @@ static int managed_card_resume_device_fn(sd_bus *bus,
* and our code works fine this way. */
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0) {
- log_debug("grdrm: %s/%s: cannot duplicate fd: %m",
- session->name, cm->card.base.name);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot duplicate fd: %m",
+ session->name, cm->card.base.name);
return 0;
}
r = grdrm_card_open(&cm->card, fd);
if (r < 0) {
- log_debug("grdrm: %s/%s: cannot open: %s",
- session->name, cm->card.base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
+ session->name, cm->card.base.name);
return 0;
}
}
@@ -2863,15 +2877,15 @@ static int managed_card_take_device_fn(sd_bus *bus,
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0) {
- log_debug("grdrm: %s/%s: cannot duplicate fd: %m",
- session->name, cm->card.base.name);
+ log_debug_errno(errno, "grdrm: %s/%s: cannot duplicate fd: %m",
+ session->name, cm->card.base.name);
return 0;
}
r = grdrm_card_open(&cm->card, fd);
if (r < 0) {
- log_debug("grdrm: %s/%s: cannot open: %s",
- session->name, cm->card.base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot open: %m",
+ session->name, cm->card.base.name);
return 0;
}
@@ -2912,8 +2926,8 @@ static void managed_card_take_device(managed_card *cm) {
return;
error:
- log_debug("grdrm: %s/%s: cannot send TakeDevice request: %s",
- session->name, cm->card.base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot send TakeDevice request: %m",
+ session->name, cm->card.base.name);
}
static void managed_card_release_device(managed_card *cm) {
@@ -2955,8 +2969,8 @@ static void managed_card_release_device(managed_card *cm) {
}
if (r < 0 && r != -ENOTCONN)
- log_debug("grdrm: %s/%s: cannot send ReleaseDevice: %s",
- session->name, cm->card.base.name, strerror(-r));
+ log_debug_errno(r, "grdrm: %s/%s: cannot send ReleaseDevice: %m",
+ session->name, cm->card.base.name);
}
static int managed_card_new(grdev_card **out, grdev_session *session, struct udev_device *ud) {
diff --git a/src/libsystemd-terminal/grdev.c b/src/libsystemd-terminal/grdev.c
index 0c21eac551..db87ede762 100644
--- a/src/libsystemd-terminal/grdev.c
+++ b/src/libsystemd-terminal/grdev.c
@@ -577,8 +577,8 @@ static bool display_cache(grdev_display *display) {
out:
if (r < 0)
- log_debug("grdev: %s/%s: cannot cache pipes: %s",
- display->session->name, display->name, strerror(-r));
+ log_debug_errno(r, "grdev: %s/%s: cannot cache pipes: %m",
+ display->session->name, display->name);
return true;
}
@@ -772,8 +772,8 @@ void grdev_pipe_schedule(grdev_pipe *pipe, uint64_t frames) {
return;
error:
- log_debug("grdev: %s/%s/%s: cannot schedule vsync timer: %s",
- pipe->card->session->name, pipe->card->name, pipe->name, strerror(-r));
+ log_debug_errno(r, "grdev: %s/%s/%s: cannot schedule vsync timer: %m",
+ pipe->card->session->name, pipe->card->name, pipe->name);
}
/*
@@ -1176,8 +1176,8 @@ void grdev_session_add_drm(grdev_session *session, struct udev_device *ud) {
r = grdev_drm_card_new(&card, session, ud);
if (r < 0) {
- log_debug("grdev: %s: cannot add DRM device for %s: %s",
- session->name, udev_device_get_syspath(ud), strerror(-r));
+ log_debug_errno(r, "grdev: %s: cannot add DRM device for %s: %m",
+ session->name, udev_device_get_syspath(ud));
return;
}
@@ -1269,8 +1269,8 @@ static void session_configure(grdev_session *session) {
} else if (!display) {
r = grdev_display_new(&display, session, pipe->name);
if (r < 0) {
- log_debug("grdev: %s/%s: cannot create display for pipe %s: %s",
- session->name, card->name, pipe->name, strerror(-r));
+ log_debug_errno(r, "grdev: %s/%s: cannot create display for pipe %s: %m",
+ session->name, card->name, pipe->name);
continue;
}
}
diff --git a/src/libsystemd-terminal/idev-evdev.c b/src/libsystemd-terminal/idev-evdev.c
index 63fa89e47d..dfbb2d197f 100644
--- a/src/libsystemd-terminal/idev-evdev.c
+++ b/src/libsystemd-terminal/idev-evdev.c
@@ -222,8 +222,8 @@ static int idev_evdev_io(idev_evdev *evdev) {
}
if (error < 0)
- log_debug("idev-evdev: %s/%s: error on data event: %s",
- e->session->name, e->name, strerror(-error));
+ log_debug_errno(error, "idev-evdev: %s/%s: error on data event: %m",
+ e->session->name, e->name);
return error;
error:
@@ -426,15 +426,15 @@ static void unmanaged_evdev_resume(idev_element *e) {
fd = open(eu->devnode, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
if (errno != EACCES && errno != EPERM) {
- log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
- e->session->name, e->name, eu->devnode);
+ log_debug_errno(errno, "idev-evdev: %s/%s: cannot open node %s: %m",
+ e->session->name, e->name, eu->devnode);
return;
}
fd = open(eu->devnode, O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
- log_debug("idev-evdev: %s/%s: cannot open node %s: %m",
- e->session->name, e->name, eu->devnode);
+ log_debug_errno(errno, "idev-evdev: %s/%s: cannot open node %s: %m",
+ e->session->name, e->name, eu->devnode);
return;
}
@@ -448,8 +448,8 @@ static void unmanaged_evdev_resume(idev_element *e) {
r = idev_evdev_resume(&eu->evdev, fd);
if (r < 0)
- log_debug("idev-evdev: %s/%s: cannot resume: %s",
- e->session->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
+ e->session->name, e->name);
}
static void unmanaged_evdev_pause(idev_element *e) {
@@ -565,14 +565,14 @@ static int managed_evdev_take_device_fn(sd_bus *bus,
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0) {
- log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name);
+ log_debug_errno(errno, "idev-evdev: %s/%s: cannot duplicate evdev fd: %m", s->name, e->name);
return 0;
}
r = idev_evdev_resume(&em->evdev, fd);
if (r < 0)
- log_debug("idev-evdev: %s/%s: cannot resume: %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
+ s->name, e->name);
return 0;
}
@@ -621,8 +621,8 @@ static void managed_evdev_enable(idev_element *e) {
return;
error:
- log_debug("idev-evdev: %s/%s: cannot send TakeDevice request: %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot send TakeDevice request: %m",
+ s->name, e->name);
}
static void managed_evdev_disable(idev_element *e) {
@@ -679,8 +679,8 @@ static void managed_evdev_disable(idev_element *e) {
}
if (r < 0 && r != -ENOTCONN)
- log_debug("idev-evdev: %s/%s: cannot send ReleaseDevice: %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot send ReleaseDevice: %m",
+ s->name, e->name);
}
static void managed_evdev_resume(idev_element *e, int fd) {
@@ -698,15 +698,15 @@ static void managed_evdev_resume(idev_element *e, int fd) {
fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (fd < 0) {
- log_debug("idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
- s->name, e->name);
+ log_debug_errno(errno, "idev-evdev: %s/%s: cannot duplicate evdev fd: %m",
+ s->name, e->name);
return;
}
r = idev_evdev_resume(&em->evdev, fd);
if (r < 0)
- log_debug("idev-evdev: %s/%s: cannot resume: %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot resume: %m",
+ s->name, e->name);
return;
}
@@ -776,8 +776,8 @@ static void managed_evdev_pause(idev_element *e, const char *mode) {
}
if (r < 0)
- log_debug("idev-evdev: %s/%s: cannot send PauseDeviceComplete: %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev-evdev: %s/%s: cannot send PauseDeviceComplete: %m",
+ s->name, e->name);
}
}
diff --git a/src/libsystemd-terminal/idev-keyboard.c b/src/libsystemd-terminal/idev-keyboard.c
index 8dc1c20b14..def8ea5ebe 100644
--- a/src/libsystemd-terminal/idev-keyboard.c
+++ b/src/libsystemd-terminal/idev-keyboard.c
@@ -25,17 +25,25 @@
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-compose.h>
#include "bus-util.h"
#include "hashmap.h"
#include "idev.h"
#include "idev-internal.h"
#include "macro.h"
+#include "term-internal.h"
#include "util.h"
+typedef struct kbdtbl kbdtbl;
typedef struct kbdmap kbdmap;
typedef struct kbdctx kbdctx;
typedef struct idev_keyboard idev_keyboard;
+struct kbdtbl {
+ unsigned long ref;
+ struct xkb_compose_table *xkb_compose_table;
+};
+
struct kbdmap {
unsigned long ref;
struct xkb_keymap *xkb_keymap;
@@ -48,10 +56,12 @@ struct kbdctx {
idev_context *context;
struct xkb_context *xkb_context;
struct kbdmap *kbdmap;
+ struct kbdtbl *kbdtbl;
sd_bus_slot *slot_locale_props_changed;
sd_bus_slot *slot_locale_get_all;
+ char *locale_lang;
char *locale_x11_model;
char *locale_x11_layout;
char *locale_x11_variant;
@@ -66,8 +76,10 @@ struct idev_keyboard {
idev_device device;
kbdctx *kbdctx;
kbdmap *kbdmap;
+ kbdtbl *kbdtbl;
struct xkb_state *xkb_state;
+ struct xkb_compose_state *xkb_compose;
usec_t repeat_delay;
usec_t repeat_rate;
@@ -76,6 +88,7 @@ struct idev_keyboard {
uint32_t n_syms;
idev_data evdata;
idev_data repdata;
+ uint32_t *compose_res;
bool repeating : 1;
};
@@ -91,6 +104,60 @@ struct idev_keyboard {
static const idev_device_vtable keyboard_vtable;
static int keyboard_update_kbdmap(idev_keyboard *k);
+static int keyboard_update_kbdtbl(idev_keyboard *k);
+
+/*
+ * Keyboard Compose Tables
+ */
+
+static kbdtbl *kbdtbl_ref(kbdtbl *kt) {
+ if (kt) {
+ assert_return(kt->ref > 0, NULL);
+ ++kt->ref;
+ }
+
+ return kt;
+}
+
+static kbdtbl *kbdtbl_unref(kbdtbl *kt) {
+ if (!kt)
+ return NULL;
+
+ assert_return(kt->ref > 0, NULL);
+
+ if (--kt->ref > 0)
+ return NULL;
+
+ xkb_compose_table_unref(kt->xkb_compose_table);
+ free(kt);
+
+ return 0;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(kbdtbl*, kbdtbl_unref);
+
+static int kbdtbl_new_from_locale(kbdtbl **out, kbdctx *kc, const char *locale) {
+ _cleanup_(kbdtbl_unrefp) kbdtbl *kt = NULL;
+
+ assert_return(out, -EINVAL);
+ assert_return(locale, -EINVAL);
+
+ kt = new0(kbdtbl, 1);
+ if (!kt)
+ return -ENOMEM;
+
+ kt->ref = 1;
+
+ kt->xkb_compose_table = xkb_compose_table_new_from_locale(kc->xkb_context,
+ locale,
+ XKB_COMPOSE_COMPILE_NO_FLAGS);
+ if (!kt->xkb_compose_table)
+ return errno > 0 ? -errno : -EFAULT;
+
+ *out = kt;
+ kt = NULL;
+ return 0;
+}
/*
* Keyboard Keymaps
@@ -191,6 +258,49 @@ static int kbdmap_new_from_names(kbdmap **out,
* Keyboard Context
*/
+static int kbdctx_refresh_compose_table(kbdctx *kc, const char *lang) {
+ kbdtbl *kt;
+ idev_session *s;
+ idev_device *d;
+ Iterator i, j;
+ int r;
+
+ if (!lang)
+ lang = "C";
+
+ if (streq_ptr(kc->locale_lang, lang))
+ return 0;
+
+ r = free_and_strdup(&kc->locale_lang, lang);
+ if (r < 0)
+ return r;
+
+ log_debug("idev-keyboard: new default compose table: [ %s ]", lang);
+
+ r = kbdtbl_new_from_locale(&kt, kc, lang);
+ if (r < 0) {
+ /* TODO: We need to catch the case where no compose-file is
+ * available. xkb doesn't tell us so far.. so we must not treat
+ * it as a hard-failure but just continue. Preferably, we want
+ * xkb to tell us exactly whether compilation failed or whether
+ * there is no compose file available for this locale. */
+ log_debug_errno(r, "idev-keyboard: cannot load compose-table for '%s': %m",
+ lang);
+ r = 0;
+ kt = NULL;
+ }
+
+ kbdtbl_unref(kc->kbdtbl);
+ kc->kbdtbl = kt;
+
+ HASHMAP_FOREACH(s, kc->context->session_map, i)
+ HASHMAP_FOREACH(d, s->device_map, j)
+ if (idev_is_keyboard(d))
+ keyboard_update_kbdtbl(keyboard_from_device(d));
+
+ return 0;
+}
+
static void move_str(char **dest, char **src) {
free(*dest);
*dest = *src;
@@ -222,11 +332,8 @@ static int kbdctx_refresh_keymap(kbdctx *kc) {
/* TODO: add a fallback keymap that's compiled-in */
r = kbdmap_new_from_names(&km, kc, kc->last_x11_model, kc->last_x11_layout,
kc->last_x11_variant, kc->last_x11_options);
- if (r < 0) {
- log_debug("idev-keyboard: cannot create keymap from locale1: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "idev-keyboard: cannot create keymap from locale1: %m");
kbdmap_unref(kc->kbdmap);
kc->kbdmap = km;
@@ -239,7 +346,41 @@ static int kbdctx_refresh_keymap(kbdctx *kc) {
return 0;
}
+static int kbdctx_set_locale(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+ kbdctx *kc = userdata;
+ const char *s, *ctype = NULL, *lang = NULL;
+ int r;
+
+ r = sd_bus_message_enter_container(m, 'a', "s");
+ if (r < 0)
+ goto error;
+
+ while ((r = sd_bus_message_read(m, "s", &s)) > 0) {
+ if (!ctype)
+ ctype = startswith(s, "LC_CTYPE=");
+ if (!lang)
+ lang = startswith(s, "LANG=");
+ }
+
+ if (r < 0)
+ goto error;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ goto error;
+
+ kbdctx_refresh_compose_table(kc, ctype ? : lang);
+ r = 0;
+
+error:
+ if (r < 0)
+ log_debug_errno(r, "idev-keyboard: cannot parse locale property from locale1: %m");
+
+ return r;
+}
+
static const struct bus_properties_map kbdctx_locale_map[] = {
+ { "Locale", "as", kbdctx_set_locale, 0 },
{ "X11Model", "s", NULL, offsetof(kbdctx, locale_x11_model) },
{ "X11Layout", "s", NULL, offsetof(kbdctx, locale_x11_layout) },
{ "X11Variant", "s", NULL, offsetof(kbdctx, locale_x11_variant) },
@@ -304,8 +445,7 @@ static int kbdctx_query_locale(kbdctx *kc) {
return 0;
error:
- log_debug("idev-keyboard: cannot send GetAll to locale1: %s", strerror(-r));
- return r;
+ return log_debug_errno(r, "idev-keyboard: cannot send GetAll to locale1: %m");
}
static int kbdctx_locale_props_changed_fn(sd_bus *bus,
@@ -336,8 +476,7 @@ static int kbdctx_locale_props_changed_fn(sd_bus *bus,
return 0;
error:
- log_debug("idev-keyboard: cannot handle PropertiesChanged from locale1: %s", strerror(-r));
- return r;
+ return log_debug_errno(r, "idev-keyboard: cannot handle PropertiesChanged from locale1: %m");
}
static int kbdctx_setup_bus(kbdctx *kc) {
@@ -352,14 +491,33 @@ static int kbdctx_setup_bus(kbdctx *kc) {
"path='/org/freedesktop/locale1'",
kbdctx_locale_props_changed_fn,
kc);
- if (r < 0) {
- log_debug("idev-keyboard: cannot setup locale1 link: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "idev-keyboard: cannot setup locale1 link: %m");
return kbdctx_query_locale(kc);
}
+static void kbdctx_log_fn(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
+ char buf[LINE_MAX];
+ int sd_lvl;
+
+ if (lvl >= XKB_LOG_LEVEL_DEBUG)
+ sd_lvl = LOG_DEBUG;
+ else if (lvl >= XKB_LOG_LEVEL_INFO)
+ sd_lvl = LOG_INFO;
+ else if (lvl >= XKB_LOG_LEVEL_WARNING)
+ sd_lvl = LOG_INFO; /* most XKB warnings really are informational */
+ else if (lvl >= XKB_LOG_LEVEL_ERROR)
+ sd_lvl = LOG_ERR;
+ else if (lvl >= XKB_LOG_LEVEL_CRITICAL)
+ sd_lvl = LOG_CRIT;
+ else
+ sd_lvl = LOG_CRIT;
+
+ snprintf(buf, sizeof(buf), "idev-xkb: %s", format);
+ log_internalv(sd_lvl, 0, __FILE__, __LINE__, __func__, buf, args);
+}
+
static kbdctx *kbdctx_ref(kbdctx *kc) {
assert_return(kc, NULL);
assert_return(kc->ref > 0, NULL);
@@ -385,8 +543,10 @@ static kbdctx *kbdctx_unref(kbdctx *kc) {
free(kc->locale_x11_variant);
free(kc->locale_x11_layout);
free(kc->locale_x11_model);
+ free(kc->locale_lang);
kc->slot_locale_get_all = sd_bus_slot_unref(kc->slot_locale_get_all);
kc->slot_locale_props_changed = sd_bus_slot_unref(kc->slot_locale_props_changed);
+ kc->kbdtbl = kbdtbl_unref(kc->kbdtbl);
kc->kbdmap = kbdmap_unref(kc->kbdmap);
xkb_context_unref(kc->xkb_context);
hashmap_remove_value(kc->context->data_map, KBDCTX_KEY, kc);
@@ -412,14 +572,21 @@ static int kbdctx_new(kbdctx **out, idev_context *c) {
kc->context = c;
errno = 0;
- kc->xkb_context = xkb_context_new(0);
+ kc->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!kc->xkb_context)
return errno > 0 ? -errno : -EFAULT;
+ xkb_context_set_log_fn(kc->xkb_context, kbdctx_log_fn);
+ xkb_context_set_log_level(kc->xkb_context, XKB_LOG_LEVEL_DEBUG);
+
r = kbdctx_refresh_keymap(kc);
if (r < 0)
return r;
+ r = kbdctx_refresh_compose_table(kc, NULL);
+ if (r < 0)
+ return r;
+
if (c->sysbus) {
r = kbdctx_setup_bus(kc);
if (r < 0)
@@ -474,12 +641,85 @@ static int keyboard_raise_data(idev_keyboard *k, idev_data *data) {
r = idev_session_raise_device_data(d->session, d, data);
if (r < 0)
- log_debug("idev-keyboard: %s/%s: error while raising data event: %s",
- d->session->name, d->name, strerror(-r));
+ log_debug_errno(r, "idev-keyboard: %s/%s: error while raising data event: %m",
+ d->session->name, d->name);
return r;
}
+static int keyboard_resize_bufs(idev_keyboard *k, uint32_t n_syms) {
+ uint32_t *t;
+
+ if (n_syms <= k->n_syms)
+ return 0;
+
+ t = realloc(k->compose_res, sizeof(*t) * n_syms);
+ if (!t)
+ return -ENOMEM;
+ k->compose_res = t;
+
+ t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
+ if (!t)
+ return -ENOMEM;
+ k->evdata.keyboard.keysyms = t;
+
+ t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
+ if (!t)
+ return -ENOMEM;
+ k->evdata.keyboard.codepoints = t;
+
+ t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
+ if (!t)
+ return -ENOMEM;
+ k->repdata.keyboard.keysyms = t;
+
+ t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
+ if (!t)
+ return -ENOMEM;
+ k->repdata.keyboard.codepoints = t;
+
+ k->n_syms = n_syms;
+ return 0;
+}
+
+static unsigned int keyboard_read_compose(idev_keyboard *k, const xkb_keysym_t **out) {
+ _cleanup_free_ char *t = NULL;
+ term_utf8 u8 = { };
+ char buf[256], *p;
+ size_t flen = 0;
+ int i, r;
+
+ r = xkb_compose_state_get_utf8(k->xkb_compose, buf, sizeof(buf));
+ if (r >= (int)sizeof(buf)) {
+ t = malloc(r + 1);
+ if (!t)
+ return 0;
+
+ xkb_compose_state_get_utf8(k->xkb_compose, t, r + 1);
+ p = t;
+ } else {
+ p = buf;
+ }
+
+ for (i = 0; i < r; ++i) {
+ uint32_t *ucs;
+ size_t len, j;
+
+ len = term_utf8_decode(&u8, &ucs, p[i]);
+ if (len > 0) {
+ r = keyboard_resize_bufs(k, flen + len);
+ if (r < 0)
+ return 0;
+
+ for (j = 0; j < len; ++j)
+ k->compose_res[flen++] = ucs[j];
+ }
+ }
+
+ *out = k->compose_res;
+ return flen;
+}
+
static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
int r;
@@ -496,6 +736,8 @@ static void keyboard_arm(idev_keyboard *k, usec_t usecs) {
static int keyboard_repeat_timer_fn(sd_event_source *source, uint64_t usec, void *userdata) {
idev_keyboard *k = userdata;
+ /* never feed REPEAT keys into COMPOSE */
+
keyboard_arm(k, k->repeat_rate);
return keyboard_raise_data(k, &k->repdata);
}
@@ -529,6 +771,14 @@ int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
if (r < 0)
return r;
+ r = keyboard_update_kbdtbl(k);
+ if (r < 0)
+ return r;
+
+ r = keyboard_resize_bufs(k, 8);
+ if (r < 0)
+ return r;
+
r = sd_event_add_time(s->context->event,
&k->repeat_timer,
CLOCK_MONOTONIC,
@@ -557,12 +807,15 @@ int idev_keyboard_new(idev_device **out, idev_session *s, const char *name) {
static void keyboard_free(idev_device *d) {
idev_keyboard *k = keyboard_from_device(d);
+ xkb_compose_state_unref(k->xkb_compose);
xkb_state_unref(k->xkb_state);
free(k->repdata.keyboard.codepoints);
free(k->repdata.keyboard.keysyms);
free(k->evdata.keyboard.codepoints);
free(k->evdata.keyboard.keysyms);
+ free(k->compose_res);
k->repeat_timer = sd_event_source_unref(k->repeat_timer);
+ k->kbdtbl = kbdtbl_unref(k->kbdtbl);
k->kbdmap = kbdmap_unref(k->kbdmap);
k->kbdctx = kbdctx_unref(k->kbdctx);
free(k);
@@ -600,34 +853,13 @@ static int keyboard_fill(idev_keyboard *k,
const uint32_t *keysyms) {
idev_data_keyboard *kev;
uint32_t i;
+ int r;
assert(dst == &k->evdata || dst == &k->repdata);
- if (n_syms > k->n_syms) {
- uint32_t *t;
-
- t = realloc(k->evdata.keyboard.keysyms, sizeof(*t) * n_syms);
- if (!t)
- return -ENOMEM;
- k->evdata.keyboard.keysyms = t;
-
- t = realloc(k->evdata.keyboard.codepoints, sizeof(*t) * n_syms);
- if (!t)
- return -ENOMEM;
- k->evdata.keyboard.codepoints = t;
-
- t = realloc(k->repdata.keyboard.keysyms, sizeof(*t) * n_syms);
- if (!t)
- return -ENOMEM;
- k->repdata.keyboard.keysyms = t;
-
- t = realloc(k->repdata.keyboard.codepoints, sizeof(*t) * n_syms);
- if (!t)
- return -ENOMEM;
- k->repdata.keyboard.codepoints = t;
-
- k->n_syms = n_syms;
- }
+ r = keyboard_resize_bufs(k, n_syms);
+ if (r < 0)
+ return r;
dst->type = IDEV_DATA_KEYBOARD;
dst->resync = resync;
@@ -647,8 +879,6 @@ static int keyboard_fill(idev_keyboard *k,
}
for (i = 0; i < IDEV_KBDMOD_CNT; ++i) {
- int r;
-
if (k->kbdmap->modmap[i] == XKB_MOD_INVALID)
continue;
@@ -715,8 +945,8 @@ static void keyboard_repeat(idev_keyboard *k) {
r = keyboard_fill(k, repdata, false, evkbd->keycode, KBDKEY_REPEAT, num, keysyms);
if (r < 0) {
- log_debug("idev-keyboard: %s/%s: cannot set key-repeat: %s",
- d->session->name, d->name, strerror(-r));
+ log_debug_errno(r, "idev-keyboard: %s/%s: cannot set key-repeat: %m",
+ d->session->name, d->name);
k->repeating = false;
keyboard_arm(k, 0);
} else {
@@ -740,8 +970,8 @@ static void keyboard_repeat(idev_keyboard *k) {
r = keyboard_fill(k, repdata, false, repkbd->keycode, KBDKEY_REPEAT, num, keysyms);
if (r < 0) {
- log_debug("idev-keyboard: %s/%s: cannot update key-repeat: %s",
- d->session->name, d->name, strerror(-r));
+ log_debug_errno(r, "idev-keyboard: %s/%s: cannot update key-repeat: %m",
+ d->session->name, d->name);
k->repeating = false;
keyboard_arm(k, 0);
}
@@ -751,6 +981,7 @@ static void keyboard_repeat(idev_keyboard *k) {
static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
struct input_event *ev = &data->evdev.event;
enum xkb_state_component compch;
+ enum xkb_compose_status cstatus;
const xkb_keysym_t *keysyms;
idev_device *d = &k->device;
int num, r;
@@ -775,6 +1006,52 @@ static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
goto error;
}
+ if (k->xkb_compose && ev->value == KBDKEY_DOWN) {
+ if (num == 1 && !data->resync) {
+ xkb_compose_state_feed(k->xkb_compose, keysyms[0]);
+ cstatus = xkb_compose_state_get_status(k->xkb_compose);
+ } else {
+ cstatus = XKB_COMPOSE_CANCELLED;
+ }
+
+ switch (cstatus) {
+ case XKB_COMPOSE_NOTHING:
+ /* keep produced keysyms and forward unchanged */
+ break;
+ case XKB_COMPOSE_COMPOSING:
+ /* consumed by compose-state, drop keysym */
+ keysyms = NULL;
+ num = 0;
+ break;
+ case XKB_COMPOSE_COMPOSED:
+ /* compose-state produced sth, replace keysym */
+ num = keyboard_read_compose(k, &keysyms);
+ xkb_compose_state_reset(k->xkb_compose);
+ break;
+ case XKB_COMPOSE_CANCELLED:
+ /* canceled compose, reset, forward cancellation sym */
+ xkb_compose_state_reset(k->xkb_compose);
+ break;
+ }
+ } else if (k->xkb_compose &&
+ num == 1 &&
+ keysyms[0] == XKB_KEY_Multi_key &&
+ !data->resync &&
+ ev->value == KBDKEY_UP) {
+ /* Reset compose state on Multi-Key UP events. This effectively
+ * requires you to hold the key during the whole sequence. I
+ * think it's pretty handy to avoid accidental
+ * Compose-sequences, but this may break Compose for disabled
+ * people. We really need to make this opional! (TODO) */
+ xkb_compose_state_reset(k->xkb_compose);
+ }
+
+ if (ev->value == KBDKEY_UP) {
+ /* never produce keysyms for UP */
+ keysyms = NULL;
+ num = 0;
+ }
+
r = keyboard_fill(k, &k->evdata, data->resync, ev->code, ev->value, num, keysyms);
if (r < 0)
goto error;
@@ -783,8 +1060,8 @@ static int keyboard_feed_evdev(idev_keyboard *k, idev_data *data) {
return keyboard_raise_data(k, &k->evdata);
error:
- log_debug("idev-keyboard: %s/%s: cannot handle event: %s",
- d->session->name, d->name, strerror(-r));
+ log_debug_errno(r, "idev-keyboard: %s/%s: cannot handle event: %m",
+ d->session->name, d->name);
k->repeating = false;
keyboard_arm(k, 0);
return 0;
@@ -844,9 +1121,41 @@ static int keyboard_update_kbdmap(idev_keyboard *k) {
return 0;
error:
- log_debug("idev-keyboard: %s/%s: cannot adopt new keymap: %s",
- d->session->name, d->name, strerror(-r));
- return r;
+ return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new keymap: %m",
+ d->session->name, d->name);
+}
+
+static int keyboard_update_kbdtbl(idev_keyboard *k) {
+ idev_device *d = &k->device;
+ struct xkb_compose_state *compose = NULL;
+ kbdtbl *kt;
+ int r;
+
+ assert(k);
+
+ kt = k->kbdctx->kbdtbl;
+ if (kt == k->kbdtbl)
+ return 0;
+
+ if (kt) {
+ errno = 0;
+ compose = xkb_compose_state_new(kt->xkb_compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
+ if (!compose) {
+ r = errno > 0 ? -errno : -EFAULT;
+ goto error;
+ }
+ }
+
+ kbdtbl_unref(k->kbdtbl);
+ k->kbdtbl = kbdtbl_ref(kt);
+ xkb_compose_state_unref(k->xkb_compose);
+ k->xkb_compose = compose;
+
+ return 0;
+
+error:
+ return log_debug_errno(r, "idev-keyboard: %s/%s: cannot adopt new compose table: %m",
+ d->session->name, d->name);
}
static const idev_device_vtable keyboard_vtable = {
diff --git a/src/libsystemd-terminal/idev.c b/src/libsystemd-terminal/idev.c
index e979b608b6..989683f39a 100644
--- a/src/libsystemd-terminal/idev.c
+++ b/src/libsystemd-terminal/idev.c
@@ -351,8 +351,8 @@ static int session_add_device(idev_session *s, idev_device *d) {
error:
if (r < 0)
- log_debug("idev: %s: error while adding device '%s': %s",
- s->name, d->name, strerror(-r));
+ log_debug_errno(r, "idev: %s: error while adding device '%s': %m",
+ s->name, d->name);
return r;
}
@@ -372,8 +372,8 @@ static int session_remove_device(idev_session *s, idev_device *d) {
idev_device_disable(d);
if (error < 0)
- log_debug("idev: %s: error while removing device '%s': %s",
- s->name, d->name, strerror(-error));
+ log_debug_errno(error, "idev: %s: error while removing device '%s': %m",
+ s->name, d->name);
idev_device_free(d);
return error;
}
@@ -420,8 +420,8 @@ static int session_remove_element(idev_session *s, idev_element *e) {
element_disable(e);
if (error < 0)
- log_debug("idev: %s: error while removing element '%s': %s",
- s->name, e->name, strerror(-r));
+ log_debug_errno(r, "idev: %s: error while removing element '%s': %m",
+ s->name, e->name);
idev_element_free(e);
return error;
}
diff --git a/src/libsystemd-terminal/modeset.c b/src/libsystemd-terminal/modeset.c
index f5be38e4fa..6e13432d68 100644
--- a/src/libsystemd-terminal/modeset.c
+++ b/src/libsystemd-terminal/modeset.c
@@ -146,16 +146,12 @@ static int modeset_new(Modeset **out) {
return log_oom();
r = sd_pid_get_session(getpid(), &m->session);
- if (r < 0) {
- log_error("Cannot retrieve logind session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot retrieve logind session: %m");
r = sd_session_get_seat(m->session, &m->seat);
- if (r < 0) {
- log_error("Cannot retrieve seat of logind session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot retrieve seat of logind session: %m");
m->my_tty = is_my_tty(m->session);
m->managed = m->my_tty && geteuid() > 0;
@@ -309,17 +305,13 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event
name,
modeset_grdev_fn,
m);
- if (r < 0) {
- log_error("Cannot create grdev session: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot create grdev session: %m");
if (m->managed) {
r = sysview_session_take_control(ev->session_add.session);
- if (r < 0) {
- log_error("Cannot request session control: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot request session control: %m");
}
grdev_session_enable(m->grdev_session);
@@ -358,16 +350,12 @@ static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event
break;
case SYSVIEW_EVENT_SESSION_CONTROL:
r = ev->session_control.error;
- if (r < 0) {
- log_error("Cannot acquire session control: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot acquire session control: %m");
r = ioctl(1, KDSKBMODE, K_UNICODE);
- if (r < 0) {
- log_error("Cannot set K_UNICODE on stdout: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Cannot set K_UNICODE on stdout: %m");
break;
}
@@ -480,7 +468,7 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- srand(time(NULL));
+ initialize_srand();
r = parse_argv(argc, argv);
if (r <= 0)
diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c
index 93c06bea83..78efc9d7c0 100644
--- a/src/libsystemd-terminal/subterm.c
+++ b/src/libsystemd-terminal/subterm.c
@@ -102,10 +102,8 @@ static int output_winch(Output *o) {
assert_return(o, -EINVAL);
r = ioctl(o->fd, TIOCGWINSZ, &wsz);
- if (r < 0) {
- log_error("error: cannot read window-size: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "error: cannot read window-size: %m");
if (wsz.ws_col != o->width || wsz.ws_row != o->height) {
o->width = wsz.ws_col;
@@ -119,16 +117,14 @@ static int output_winch(Output *o) {
}
static int output_flush(Output *o) {
- ssize_t len;
+ int r;
if (o->n_obuf < 1)
return 0;
- len = loop_write(o->fd, o->obuf, o->n_obuf, false);
- if (len < 0) {
- log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
- return len;
- }
+ r = loop_write(o->fd, o->obuf, o->n_obuf, false);
+ if (r < 0)
+ return log_error_errno(r, "error: cannot write to TTY: %m");
o->n_obuf = 0;
@@ -156,10 +152,8 @@ static int output_write(Output *o, const void *buf, size_t size) {
return r;
len = loop_write(o->fd, buf, size, false);
- if (len < 0) {
- log_error("error: cannot write to TTY (%zd): %s", len, strerror(-len));
- return len;
- }
+ if (len < 0)
+ return log_error_errno(len, "error: cannot write to TTY (%zd): %m", len);
return 0;
}
@@ -612,12 +606,12 @@ static int terminal_winch_fn(sd_event_source *source, const struct signalfd_sigi
if (t->pty) {
r = pty_resize(t->pty, t->output->in_width, t->output->in_height);
if (r < 0)
- log_error("error: pty_resize() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: pty_resize() (%d): %m", r);
}
r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
if (r < 0)
- log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: term_screen_resize() (%d): %m", r);
terminal_dirty(t);
@@ -656,10 +650,8 @@ static int terminal_write_tmp(Terminal *t) {
if (t->pty) {
for (i = 0; i < num; ++i) {
r = pty_write(t->pty, vec[i].iov_base, vec[i].iov_len);
- if (r < 0) {
- log_error("error: cannot write to PTY (%d): %s", r, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "error: cannot write to PTY (%d): %m", r);
}
}
@@ -713,7 +705,7 @@ static int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, voi
if (errno == EAGAIN || errno == EINTR)
return 0;
- log_error("error: cannot read from TTY (%d): %m", -errno);
+ log_error_errno(errno, "error: cannot read from TTY (%d): %m", -errno);
return -errno;
}
@@ -725,10 +717,8 @@ static int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, voi
n_str = term_utf8_decode(&t->utf8, &str, buf[i]);
for (j = 0; j < n_str; ++j) {
type = term_parser_feed(t->parser, &seq, str[j]);
- if (type < 0) {
- log_error("error: term_parser_feed() (%d): %s", type, strerror(-type));
- return type;
- }
+ if (type < 0)
+ return log_error_errno(type, "error: term_parser_feed() (%d): %m", type);
if (!t->is_menu) {
r = terminal_push_tmp(t, str[j]);
@@ -777,10 +767,8 @@ static int terminal_pty_fn(Pty *pty, void *userdata, unsigned int event, const v
break;
case PTY_DATA:
r = term_screen_feed_text(t->screen, ptr, size);
- if (r < 0) {
- log_error("error: term_screen_feed_text() (%d): %s", r, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "error: term_screen_feed_text() (%d): %m", r);
terminal_dirty(t);
break;
@@ -832,16 +820,12 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) {
assert_return(out, -EINVAL);
r = tcgetattr(in_fd, &in_attr);
- if (r < 0) {
- log_error("error: tcgetattr() (%d): %m", -errno);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "error: tcgetattr() (%d): %m", -errno);
r = tcgetattr(out_fd, &out_attr);
- if (r < 0) {
- log_error("error: tcgetattr() (%d): %m", -errno);
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "error: tcgetattr() (%d): %m", -errno);
t = new0(Terminal, 1);
if (!t)
@@ -857,49 +841,49 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) {
r = tcsetattr(t->in_fd, TCSANOW, &in_attr);
if (r < 0) {
- log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: tcsetattr() (%d): %m", r);
goto error;
}
r = tcsetattr(t->out_fd, TCSANOW, &out_attr);
if (r < 0) {
- log_error("error: tcsetattr() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: tcsetattr() (%d): %m", r);
goto error;
}
r = sd_event_default(&t->event);
if (r < 0) {
- log_error("error: sd_event_default() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_default() (%d): %m", r);
goto error;
}
r = sigprocmask_many(SIG_BLOCK, SIGINT, SIGQUIT, SIGTERM, SIGWINCH, SIGCHLD, -1);
if (r < 0) {
- log_error("error: sigprocmask_many() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sigprocmask_many() (%d): %m", r);
goto error;
}
r = sd_event_add_signal(t->event, NULL, SIGINT, NULL, NULL);
if (r < 0) {
- log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r);
goto error;
}
r = sd_event_add_signal(t->event, NULL, SIGQUIT, NULL, NULL);
if (r < 0) {
- log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r);
goto error;
}
r = sd_event_add_signal(t->event, NULL, SIGTERM, NULL, NULL);
if (r < 0) {
- log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r);
goto error;
}
r = sd_event_add_signal(t->event, NULL, SIGWINCH, terminal_winch_fn, t);
if (r < 0) {
- log_error("error: sd_event_add_signal() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_add_signal() (%d): %m", r);
goto error;
}
@@ -907,7 +891,7 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) {
t->is_dirty = true;
r = sd_event_add_time(t->event, &t->frame_timer, CLOCK_MONOTONIC, 0, 0, terminal_frame_timer_fn, t);
if (r < 0) {
- log_error("error: sd_event_add_time() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: sd_event_add_time() (%d): %m", r);
goto error;
}
@@ -929,7 +913,7 @@ static int terminal_new(Terminal **out, int in_fd, int out_fd) {
r = term_screen_resize(t->screen, t->output->in_width, t->output->in_height);
if (r < 0) {
- log_error("error: term_screen_resize() (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: term_screen_resize() (%d): %m", r);
goto error;
}
@@ -951,10 +935,9 @@ static int terminal_run(Terminal *t) {
assert_return(t, -EINVAL);
pid = pty_fork(&t->pty, t->event, terminal_pty_fn, t, t->output->in_width, t->output->in_height);
- if (pid < 0) {
- log_error("error: cannot fork PTY (%d): %s", pid, strerror(-pid));
- return pid;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(pid, "error: cannot fork PTY (%d): %m", pid);
+ else if (pid == 0) {
/* child */
char **argv = (char*[]){
@@ -966,7 +949,7 @@ static int terminal_run(Terminal *t) {
setenv("COLORTERM", "systemd-subterm", 1);
execve(argv[0], argv, environ);
- log_error("error: cannot exec %s (%d): %m", argv[0], -errno);
+ log_error_errno(errno, "error: cannot exec %s (%d): %m", argv[0], -errno);
_exit(1);
}
@@ -993,7 +976,7 @@ int main(int argc, char *argv[]) {
out:
if (r < 0)
- log_error("error: terminal failed (%d): %s", r, strerror(-r));
+ log_error_errno(r, "error: terminal failed (%d): %m", r);
terminal_free(t);
return -r;
}
diff --git a/src/libsystemd-terminal/sysview.c b/src/libsystemd-terminal/sysview.c
index 70a6ca726c..9ee32db1bc 100644
--- a/src/libsystemd-terminal/sysview.c
+++ b/src/libsystemd-terminal/sysview.c
@@ -295,8 +295,8 @@ static int session_take_control_fn(sd_bus *bus,
r = context_raise_session_control(session->seat->context, session, error);
if (r < 0)
- log_debug("sysview: callback failed while signalling session control '%d' on session '%s': %s",
- error, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while signalling session control '%d' on session '%s': %m",
+ error, session->name);
return 0;
}
@@ -365,8 +365,8 @@ void sysview_session_release_control(sysview_session *session) {
r = sd_bus_send(session->seat->context->sysbus, m, NULL);
if (r < 0 && r != -ENOTCONN)
- log_debug("sysview: %s: cannot send ReleaseControl: %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: %s: cannot send ReleaseControl: %m",
+ session->name);
}
/*
@@ -604,8 +604,8 @@ static void context_add_device(sysview_context *c, sysview_device *device) {
r = context_raise_session_attach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while attaching device '%s' to session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while attaching device '%s' to session '%s': %m",
+ device->name, session->name);
}
}
@@ -625,8 +625,8 @@ static void context_remove_device(sysview_context *c, sysview_device *device) {
r = context_raise_session_detach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while detaching device '%s' from session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while detaching device '%s' from session '%s': %m",
+ device->name, session->name);
}
sysview_device_free(device);
@@ -648,8 +648,8 @@ static void context_change_device(sysview_context *c, sysview_device *device, st
r = context_raise_session_refresh(c, session, device, ud);
if (r < 0)
- log_debug("sysview: callback failed while changing device '%s' on session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while changing device '%s' on session '%s': %m",
+ device->name, session->name);
}
}
@@ -683,8 +683,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
session->public = true;
r = context_raise_session_add(c, session);
if (r < 0) {
- log_debug("sysview: callback failed while adding session '%s': %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while adding session '%s': %m",
+ session->name);
session->public = false;
goto error;
}
@@ -692,8 +692,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
HASHMAP_FOREACH(device, seat->device_map, i) {
r = context_raise_session_attach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while attaching device '%s' to new session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while attaching device '%s' to new session '%s': %m",
+ device->name, session->name);
}
}
@@ -701,8 +701,8 @@ static void context_add_session(sysview_context *c, sysview_seat *seat, const ch
error:
if (r < 0)
- log_debug("sysview: error while adding session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: error while adding session '%s': %m",
+ id);
}
static void context_remove_session(sysview_context *c, sysview_session *session) {
@@ -719,15 +719,15 @@ static void context_remove_session(sysview_context *c, sysview_session *session)
HASHMAP_FOREACH(device, session->seat->device_map, i) {
r = context_raise_session_detach(c, session, device);
if (r < 0)
- log_debug("sysview: callback failed while detaching device '%s' from old session '%s': %s",
- device->name, session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while detaching device '%s' from old session '%s': %m",
+ device->name, session->name);
}
session->public = false;
r = context_raise_session_remove(c, session);
if (r < 0)
- log_debug("sysview: callback failed while removing session '%s': %s",
- session->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while removing session '%s': %m",
+ session->name);
}
if (!session->custom)
@@ -756,8 +756,8 @@ static void context_add_seat(sysview_context *c, const char *id) {
seat->public = true;
r = context_raise_seat_add(c, seat);
if (r < 0) {
- log_debug("sysview: callback failed while adding seat '%s': %s",
- seat->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while adding seat '%s': %m",
+ seat->name);
seat->public = false;
}
@@ -765,8 +765,8 @@ static void context_add_seat(sysview_context *c, const char *id) {
error:
if (r < 0)
- log_debug("sysview: error while adding seat '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: error while adding seat '%s': %m",
+ id);
}
static void context_remove_seat(sysview_context *c, sysview_seat *seat) {
@@ -789,8 +789,8 @@ static void context_remove_seat(sysview_context *c, sysview_seat *seat) {
seat->public = false;
r = context_raise_seat_remove(c, seat);
if (r < 0)
- log_debug("sysview: callback failed while removing seat '%s': %s",
- seat->name, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while removing seat '%s': %m",
+ seat->name);
}
sysview_seat_free(seat);
@@ -975,11 +975,9 @@ static int context_ud_hotplug(sysview_context *c, struct udev_device *d) {
return 0;
r = device_new_ud(&device, seat, type, d);
- if (r < 0) {
- log_debug("sysview: cannot create device for udev-device '%s': %s",
- syspath, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot create device for udev-device '%s': %m",
+ syspath);
context_add_device(c, device);
}
@@ -1083,8 +1081,8 @@ static int context_ud_scan(sysview_context *c) {
d = udev_device_new_from_syspath(c->ud, name);
if (!d) {
r = errno > 0 ? -errno : -EFAULT;
- log_debug("sysview: cannot create udev-device for %s: %s",
- name, strerror(-r));
+ log_debug_errno(r, "sysview: cannot create udev-device for %s: %m",
+ name);
continue;
}
@@ -1102,11 +1100,8 @@ static int context_ld_seat_new(sysview_context *c, sd_bus_message *signal) {
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SeatNew from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SeatNew from logind: %m");
context_add_seat(c, id);
return 0;
@@ -1118,11 +1113,8 @@ static int context_ld_seat_removed(sysview_context *c, sd_bus_message *signal) {
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SeatRemoved from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SeatRemoved from logind: %m");
seat = sysview_find_seat(c, id);
if (!seat)
@@ -1140,11 +1132,8 @@ static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SessionNew from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SessionNew from logind: %m");
/*
* As the dbus message didn't contain enough information, we
@@ -1177,17 +1166,16 @@ static int context_ld_session_new(sysview_context *c, sd_bus_message *signal) {
r = context_raise_session_filter(c, id, seatid, username, uid);
if (r < 0)
- log_debug("sysview: callback failed while filtering session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while filtering session '%s': %m",
+ id);
else if (r > 0)
context_add_session(c, seat, id);
return 0;
error:
- log_debug("sysview: failed retrieving information for new session '%s': %s",
- id, strerror(-r));
- return r;
+ return log_debug_errno(r, "sysview: failed retrieving information for new session '%s': %m",
+ id);
}
static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal) {
@@ -1196,11 +1184,8 @@ static int context_ld_session_removed(sysview_context *c, sd_bus_message *signal
int r;
r = sd_bus_message_read(signal, "so", &id, &path);
- if (r < 0) {
- log_debug("sysview: cannot parse SessionRemoved from logind: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: cannot parse SessionRemoved from logind: %m");
session = sysview_find_session(c, id);
if (!session)
@@ -1299,9 +1284,7 @@ static int context_ld_list_seats_fn(sd_bus *bus,
return 0;
error:
- log_debug("sysview: erroneous ListSeats response from logind: %s",
- strerror(-r));
- return r;
+ return log_debug_errno(r, "sysview: erroneous ListSeats response from logind: %m");
}
static int context_ld_list_sessions_fn(sd_bus *bus,
@@ -1344,8 +1327,8 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
if (seat) {
r = context_raise_session_filter(c, id, seatid, username, uid);
if (r < 0)
- log_debug("sysview: callback failed while filtering session '%s': %s",
- id, strerror(-r));
+ log_debug_errno(r, "sysview: callback failed while filtering session '%s': %m",
+ id);
else if (r > 0)
context_add_session(c, seat, id);
}
@@ -1365,9 +1348,7 @@ static int context_ld_list_sessions_fn(sd_bus *bus,
return 0;
error:
- log_debug("sysview: erroneous ListSessions response from logind: %s",
- strerror(-r));
- return r;
+ return log_debug_errno(r, "sysview: erroneous ListSessions response from logind: %m");
}
static int context_ld_scan(sysview_context *c) {
@@ -1497,19 +1478,15 @@ static int context_scan_fn(sd_event_source *s, void *userdata) {
if (!c->scanned) {
r = context_ld_scan(c);
- if (r < 0) {
- log_debug("sysview: logind scan failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: logind scan failed: %m");
}
/* skip device scans if no sessions are available */
if (hashmap_size(c->session_map) > 0) {
r = context_ud_scan(c);
- if (r < 0) {
- log_debug("sysview: udev scan failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "sysview: udev scan failed: %m");
HASHMAP_FOREACH(seat, c->seat_map, i)
seat->scanned = true;
diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c
index acd7cc966a..51d93765e4 100644
--- a/src/libsystemd-terminal/term-screen.c
+++ b/src/libsystemd-terminal/term-screen.c
@@ -549,7 +549,6 @@ static int screen_LF(term_screen *screen, const term_seq *seq);
static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
term_char_t ch = TERM_CHAR_NULL;
- uint32_t c;
if (screen->state.cursor_x + 1 == screen->page->width
&& screen->flags & TERM_FLAG_PENDING_WRAP
@@ -560,8 +559,7 @@ static int screen_GRAPHIC(term_screen *screen, const term_seq *seq) {
screen_cursor_clear_wrap(screen);
- c = screen_map(screen, seq->terminator);
- ch = term_char_merge(ch, screen_map(screen, c));
+ ch = term_char_merge(ch, screen_map(screen, seq->terminator));
term_page_write(screen->page, screen->state.cursor_x, screen->state.cursor_y, ch, 1, &screen->state.attr, screen->age, false);
if (screen->state.cursor_x + 1 == screen->page->width)
diff --git a/src/libsystemd/libsystemd.sym.m4 b/src/libsystemd/libsystemd.sym.m4
index ab11448bb9..de8bec3098 100644
--- a/src/libsystemd/libsystemd.sym.m4
+++ b/src/libsystemd/libsystemd.sym.m4
@@ -179,7 +179,7 @@ global:
sd_bus_set_anonymous;
sd_bus_set_trusted;
sd_bus_set_monitor;
- sd_bus_set_name;
+ sd_bus_set_description;
sd_bus_negotiate_fds;
sd_bus_negotiate_timestamp;
sd_bus_negotiate_creds;
@@ -190,9 +190,9 @@ global:
sd_bus_unref;
sd_bus_is_open;
sd_bus_can_send;
- sd_bus_get_server_id;
+ sd_bus_get_bus_id;
sd_bus_get_owner_creds;
- sd_bus_get_name;
+ sd_bus_get_description;
sd_bus_send;
sd_bus_send_to;
sd_bus_call;
@@ -223,6 +223,8 @@ global:
sd_bus_slot_get_bus;
sd_bus_slot_get_userdata;
sd_bus_slot_set_userdata;
+ sd_bus_slot_get_description;
+ sd_bus_slot_set_description;
sd_bus_slot_get_current_message;
sd_bus_message_new_signal;
sd_bus_message_new_method_call;
@@ -252,6 +254,7 @@ global:
sd_bus_message_get_realtime_usec;
sd_bus_message_get_seqnum;
sd_bus_message_get_creds;
+ sd_bus_message_is_empty;
sd_bus_message_is_signal;
sd_bus_message_is_method_call;
sd_bus_message_is_method_error;
@@ -315,7 +318,6 @@ global:
sd_bus_creds_get_uid;
sd_bus_creds_get_gid;
sd_bus_creds_get_pid;
- sd_bus_creds_get_pid_starttime;
sd_bus_creds_get_tid;
sd_bus_creds_get_comm;
sd_bus_creds_get_tid_comm;
@@ -336,7 +338,7 @@ global:
sd_bus_creds_get_audit_login_uid;
sd_bus_creds_get_unique_name;
sd_bus_creds_get_well_known_names;
- sd_bus_creds_get_connection_name;
+ sd_bus_creds_get_description;
sd_bus_error_free;
sd_bus_error_set;
sd_bus_error_setf;
@@ -387,8 +389,8 @@ global:
sd_event_get_watchdog;
sd_event_source_ref;
sd_event_source_unref;
- sd_event_source_set_name;
- sd_event_source_get_name;
+ sd_event_source_set_description;
+ sd_event_source_get_description;
sd_event_source_set_prepare;
sd_event_source_get_pending;
sd_event_source_get_priority;
diff --git a/src/libsystemd/sd-bus/PORTING-DBUS1 b/src/libsystemd/sd-bus/PORTING-DBUS1
index 81e94132b3..2dedb28bcf 100644
--- a/src/libsystemd/sd-bus/PORTING-DBUS1
+++ b/src/libsystemd/sd-bus/PORTING-DBUS1
@@ -14,11 +14,11 @@ GVariant compatible marshaler to your library first.
After you have done that: here's the basic principle how kdbus works:
-You connect to a bus by opening its bus node in /dev/kdbus/. All
+You connect to a bus by opening its bus node in /sys/fs/kdbus/. All
buses have a device node there, it starts with a numeric UID of the
owner of the bus, followed by a dash and a string identifying the
-bus. The system bus is thus called /dev/kdbus/0-system, and for user
-buses the device node is /dev/kdbus/1000-user (if 1000 is your user
+bus. The system bus is thus called /sys/fs/kdbus/0-system, and for user
+buses the device node is /sys/fs/kdbus/1000-user (if 1000 is your user
id).
(Before we proceed, please always keep a copy of libsystemd next
@@ -496,12 +496,12 @@ parameter.
Client libraries should use the following connection string when
connecting to the system bus:
- kernel:path=/dev/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket
+ kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket
This will ensure that kdbus is preferred over the legacy AF_UNIX
socket, but compatibility is kept. For the user bus use:
- kernel:path=/dev/kdbus/$UID-user/bus;unix:path=$XDG_RUNTIME_DIR/bus
+ kernel:path=/sys/fs/kdbus/$UID-user/bus;unix:path=$XDG_RUNTIME_DIR/bus
With $UID replaced by the callers numer user ID, and $XDG_RUNTIME_DIR
following the XDG basedir spec.
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
new file mode 100644
index 0000000000..3dc00b5e4a
--- /dev/null
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -0,0 +1,76 @@
+/*-*- 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 <errno.h>
+
+#include "sd-bus.h"
+#include "bus-error.h"
+#include "bus-common-errors.h"
+
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT, ENOENT),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_UNIT_FOR_PID, ESRCH),
+ SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_EXISTS, EEXIST),
+ SD_BUS_ERROR_MAP(BUS_ERROR_LOAD_FAILED, EIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_JOB_FAILED, EREMOTEIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_JOB, ENOENT),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NOT_SUBSCRIBED, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_ALREADY_SUBSCRIBED, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_ONLY_BY_DEPENDENCY, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ENOSYS),
+ SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM),
+ SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED),
+ SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN),
+
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_MACHINE_FOR_PID, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_MACHINE_EXISTS, EEXIST),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRIVATE_NETWORKING, ENOSYS),
+
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SESSION, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SESSION_FOR_PID, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_USER, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_USER_FOR_PID, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SEAT, ENXIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_SESSION_NOT_ON_SEAT, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NOT_IN_CONTROL, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_IS_TAKEN, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_DEVICE_NOT_TAKEN, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_OPERATION_IN_PROGRESS, EINPROGRESS),
+ SD_BUS_ERROR_MAP(BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, ENOSYS),
+
+ SD_BUS_ERROR_MAP(BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED, EALREADY),
+
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_PROCESS, ESRCH),
+
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, EIO),
+ SD_BUS_ERROR_MAP(BUS_ERROR_INVALID_REPLY, EINVAL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_RR, ENOENT),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_RESOURCES, ENOMEM),
+ SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLOCK),
+ SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED),
+
+ SD_BUS_ERROR_MAP_END
+};
diff --git a/src/shared/bus-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 504ab1f796..5b7f41ef19 100644
--- a/src/shared/bus-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -21,6 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-bus.h"
+#include "bus-error.h"
+
#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
#define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID"
#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists"
@@ -67,3 +70,5 @@
#define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop"
#define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted"
#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError."
+
+BUS_ERROR_MAP_ELF_USE(bus_common_errors);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 5a052d455e..813c97f650 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -62,7 +62,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags
size = offsetof(struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(l);
n = alloca0_align(size, 8);
n->size = size;
- kdbus_translate_request_name_flags(flags, (uint64_t *) &n->flags);
+ n->flags = request_name_flags_to_kdbus(flags);
n->items[0].size = KDBUS_ITEM_HEADER_SIZE + l;
n->items[0].type = KDBUS_ITEM_NAME;
@@ -223,23 +223,6 @@ _public_ int sd_bus_release_name(sd_bus *bus, const char *name) {
return bus_release_name_dbus1(bus, name);
}
-static int kernel_cmd_free(sd_bus *bus, uint64_t offset)
-{
- struct kdbus_cmd_free cmd;
- int r;
-
- assert(bus);
-
- cmd.flags = 0;
- cmd.offset = offset;
-
- r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
struct kdbus_cmd_name_list cmd = {};
struct kdbus_name_list *name_list;
@@ -278,8 +261,8 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
}
KDBUS_ITEM_FOREACH(item, name, items)
- if (item->type == KDBUS_ITEM_NAME)
- entry_name = item->str;
+ if (item->type == KDBUS_ITEM_OWNED_NAME)
+ entry_name = item->name.name;
if (entry_name && service_name_is_valid(entry_name)) {
r = strv_extend(x, entry_name);
@@ -293,7 +276,7 @@ static int kernel_get_list(sd_bus *bus, uint64_t flags, char ***x) {
r = 0;
fail:
- kernel_cmd_free(bus, cmd.offset);
+ bus_kernel_cmd_free(bus, cmd.offset);
return r;
}
@@ -392,46 +375,87 @@ _public_ int sd_bus_list_names(sd_bus *bus, char ***acquired, char ***activatabl
return bus_list_names_dbus1(bus, acquired, activatable);
}
-static int bus_populate_creds_from_items(sd_bus *bus,
- struct kdbus_info *info,
- uint64_t mask,
- sd_bus_creds *c) {
+static int bus_populate_creds_from_items(
+ sd_bus *bus,
+ struct kdbus_info *info,
+ uint64_t mask,
+ sd_bus_creds *c) {
struct kdbus_item *item;
uint64_t m;
int r;
+ assert(bus);
+ assert(info);
+ assert(c);
+
KDBUS_ITEM_FOREACH(item, info, items) {
switch (item->type) {
+ case KDBUS_ITEM_PIDS:
+
+ if (mask & SD_BUS_CREDS_PID && item->pids.pid > 0) {
+ c->pid = (pid_t) item->pids.pid;
+ c->mask |= SD_BUS_CREDS_PID;
+ }
+
+ if (mask & SD_BUS_CREDS_TID && item->pids.tid > 0) {
+ c->tid = (pid_t) item->pids.tid;
+ c->mask |= SD_BUS_CREDS_TID;
+ }
+
+ break;
+
case KDBUS_ITEM_CREDS:
- m = (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID | SD_BUS_CREDS_PID) & mask;
- if (m) {
+ if (mask & SD_BUS_CREDS_UID && (uid_t) item->creds.uid != UID_INVALID) {
c->uid = (uid_t) item->creds.uid;
- c->pid = (pid_t) item->creds.pid;
+ c->mask |= SD_BUS_CREDS_UID;
+ }
+
+ if (mask & SD_BUS_CREDS_EUID && (uid_t) item->creds.euid != UID_INVALID) {
+ c->euid = (uid_t) item->creds.euid;
+ c->mask |= SD_BUS_CREDS_EUID;
+ }
+
+ if (mask & SD_BUS_CREDS_SUID && (uid_t) item->creds.suid != UID_INVALID) {
+ c->suid = (uid_t) item->creds.suid;
+ c->mask |= SD_BUS_CREDS_SUID;
+ }
+
+ if (mask & SD_BUS_CREDS_FSUID && (uid_t) item->creds.fsuid != UID_INVALID) {
+ c->fsuid = (uid_t) item->creds.fsuid;
+ c->mask |= SD_BUS_CREDS_FSUID;
+ }
+
+ if (mask & SD_BUS_CREDS_GID && (gid_t) item->creds.gid != GID_INVALID) {
c->gid = (gid_t) item->creds.gid;
- c->mask |= m;
+ c->mask |= SD_BUS_CREDS_GID;
}
- if (mask & SD_BUS_CREDS_TID && item->creds.tid > 0) {
- c->tid = (pid_t) item->creds.tid;
- c->mask |= SD_BUS_CREDS_TID;
+ if (mask & SD_BUS_CREDS_EGID && (gid_t) item->creds.egid != GID_INVALID) {
+ c->egid = (gid_t) item->creds.egid;
+ c->mask |= SD_BUS_CREDS_EGID;
+ }
+
+ if (mask & SD_BUS_CREDS_SGID && (gid_t) item->creds.sgid != GID_INVALID) {
+ c->sgid = (gid_t) item->creds.sgid;
+ c->mask |= SD_BUS_CREDS_SGID;
}
- if (mask & SD_BUS_CREDS_PID_STARTTIME && item->creds.starttime > 0) {
- c->pid_starttime = item->creds.starttime;
- c->mask |= SD_BUS_CREDS_PID_STARTTIME;
+ if (mask & SD_BUS_CREDS_FSGID && (gid_t) item->creds.fsgid != GID_INVALID) {
+ c->fsgid = (gid_t) item->creds.fsgid;
+ c->mask |= SD_BUS_CREDS_FSGID;
}
break;
case KDBUS_ITEM_PID_COMM:
if (mask & SD_BUS_CREDS_COMM) {
- c->comm = strdup(item->str);
- if (!c->comm)
- return -ENOMEM;
+ r = free_and_strdup(&c->comm, item->str);
+ if (r < 0)
+ return r;
c->mask |= SD_BUS_CREDS_COMM;
}
@@ -439,9 +463,9 @@ static int bus_populate_creds_from_items(sd_bus *bus,
case KDBUS_ITEM_TID_COMM:
if (mask & SD_BUS_CREDS_TID_COMM) {
- c->tid_comm = strdup(item->str);
- if (!c->tid_comm)
- return -ENOMEM;
+ r = free_and_strdup(&c->tid_comm, item->str);
+ if (r < 0)
+ return r;
c->mask |= SD_BUS_CREDS_TID_COMM;
}
@@ -449,9 +473,9 @@ static int bus_populate_creds_from_items(sd_bus *bus,
case KDBUS_ITEM_EXE:
if (mask & SD_BUS_CREDS_EXE) {
- c->exe = strdup(item->str);
- if (!c->exe)
- return -ENOMEM;
+ r = free_and_strdup(&c->exe, item->str);
+ if (r < 0)
+ return r;
c->mask |= SD_BUS_CREDS_EXE;
}
@@ -459,7 +483,7 @@ static int bus_populate_creds_from_items(sd_bus *bus,
case KDBUS_ITEM_CMDLINE:
if (mask & SD_BUS_CREDS_CMDLINE) {
- c->cmdline_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+ c->cmdline_size = item->size - offsetof(struct kdbus_item, data);
c->cmdline = memdup(item->data, c->cmdline_size);
if (!c->cmdline)
return -ENOMEM;
@@ -474,17 +498,17 @@ static int bus_populate_creds_from_items(sd_bus *bus,
SD_BUS_CREDS_SESSION | SD_BUS_CREDS_OWNER_UID) & mask;
if (m) {
- c->cgroup = strdup(item->str);
- if (!c->cgroup)
- return -ENOMEM;
+ r = free_and_strdup(&c->cgroup, item->str);
+ if (r < 0)
+ return r;
r = bus_get_root_path(bus);
if (r < 0)
return r;
- c->cgroup_root = strdup(bus->cgroup_root);
- if (!c->cgroup_root)
- return -ENOMEM;
+ r = free_and_strdup(&c->cgroup_root, bus->cgroup_root);
+ if (r < 0)
+ return r;
c->mask |= m;
}
@@ -506,25 +530,27 @@ static int bus_populate_creds_from_items(sd_bus *bus,
case KDBUS_ITEM_SECLABEL:
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
- c->label = strdup(item->str);
- if (!c->label)
- return -ENOMEM;
+ r = free_and_strdup(&c->label, item->str);
+ if (r < 0)
+ return r;
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
break;
case KDBUS_ITEM_AUDIT:
- m = (SD_BUS_CREDS_AUDIT_SESSION_ID | SD_BUS_CREDS_AUDIT_LOGIN_UID) & mask;
+ if (mask & SD_BUS_CREDS_AUDIT_SESSION_ID && (uint32_t) item->audit.sessionid != (uint32_t) -1) {
+ c->audit_session_id = (uint32_t) item->audit.sessionid;
+ c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
+ }
- if (m) {
- c->audit_session_id = item->audit.sessionid;
- c->audit_login_uid = item->audit.loginuid;
- c->mask |= m;
+ if (mask & SD_BUS_CREDS_AUDIT_LOGIN_UID && (uid_t) item->audit.loginuid != UID_INVALID) {
+ c->audit_login_uid = (uid_t) item->audit.loginuid;
+ c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
break;
- case KDBUS_ITEM_NAME:
+ case KDBUS_ITEM_OWNED_NAME:
if ((mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) && service_name_is_valid(item->name.name)) {
r = strv_extend(&c->well_known_names, item->name.name);
if (r < 0)
@@ -534,13 +560,33 @@ static int bus_populate_creds_from_items(sd_bus *bus,
}
break;
- case KDBUS_ITEM_CONN_NAME:
- if ((mask & SD_BUS_CREDS_CONNECTION_NAME)) {
- c->conn_name = strdup(item->str);
- if (!c->conn_name)
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ if (mask & SD_BUS_CREDS_DESCRIPTION) {
+ r = free_and_strdup(&c->description, item->str);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_DESCRIPTION;
+ }
+ break;
+
+ case KDBUS_ITEM_AUXGROUPS:
+ if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ size_t n;
+ uid_t *g;
+
+ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+
+ n = (item->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
+ g = newdup(gid_t, item->data32, n);
+ if (!g)
return -ENOMEM;
- c->mask |= SD_BUS_CREDS_CONNECTION_NAME;
+ free(c->supplementary_gids);
+ c->supplementary_gids = g;
+ c->n_supplementary_gids = n;
+
+ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
break;
}
@@ -549,10 +595,11 @@ static int bus_populate_creds_from_items(sd_bus *bus,
return 0;
}
-static int bus_get_name_creds_kdbus(
+int bus_get_name_creds_kdbus(
sd_bus *bus,
const char *name,
uint64_t mask,
+ bool allow_activator,
sd_bus_creds **creds) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
@@ -579,7 +626,20 @@ static int bus_get_name_creds_kdbus(
}
cmd->size = size;
- kdbus_translate_attach_flags(mask, (uint64_t*) &cmd->flags);
+ cmd->flags = attach_flags_to_kdbus(mask);
+
+ /* If augmentation is on, and the bus doesn't didn't allow us
+ * to get the bits we want, then ask for the PID/TID so that we
+ * can read the rest from /proc. */
+ if ((mask & SD_BUS_CREDS_AUGMENT) &&
+ (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
+ cmd->flags |= KDBUS_ATTACH_PIDS;
r = ioctl(bus->input_fd, KDBUS_CMD_CONN_INFO, cmd);
if (r < 0)
@@ -588,7 +648,7 @@ static int bus_get_name_creds_kdbus(
conn_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd->offset);
/* Non-activated names are considered not available */
- if (conn_info->flags & KDBUS_HELLO_ACTIVATOR) {
+ if (!allow_activator && (conn_info->flags & KDBUS_HELLO_ACTIVATOR)) {
if (name[0] == ':')
r = -ENXIO;
else
@@ -611,10 +671,21 @@ static int bus_get_name_creds_kdbus(
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
+ /* If KDBUS_ITEM_OWNED_NAME is requested then we'll get 0 of
+ them in case the service has no names. This does not mean
+ however that the list of owned names could not be
+ acquired. Hence, let's explicitly clarify that the data is
+ complete. */
+ c->mask |= mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
+
r = bus_populate_creds_from_items(bus, conn_info, mask, c);
if (r < 0)
goto fail;
+ r = bus_creds_add_more(c, mask, 0, 0);
+ if (r < 0)
+ goto fail;
+
if (creds) {
*creds = c;
c = NULL;
@@ -623,7 +694,7 @@ static int bus_get_name_creds_kdbus(
r = 0;
fail:
- kernel_cmd_free(bus, cmd->offset);
+ bus_kernel_cmd_free(bus, cmd->offset);
return r;
}
@@ -673,11 +744,16 @@ static int bus_get_name_creds_dbus1(
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
- if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_GID|
- SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
- SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
- SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
- SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)) {
+ if ((mask & SD_BUS_CREDS_PID) ||
+ ((mask & SD_BUS_CREDS_AUGMENT) &&
+ (mask & (SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))) {
+
uint32_t u;
r = sd_bus_call_method(
@@ -733,6 +809,7 @@ static int bus_get_name_creds_dbus1(
}
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const void *p = NULL;
size_t sz = 0;
@@ -742,22 +819,24 @@ static int bus_get_name_creds_dbus1(
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetConnectionSELinuxSecurityContext",
- NULL,
+ &error,
&reply,
"s",
unique ? unique : name);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_array(reply, 'y', &p, &sz);
- if (r < 0)
- return r;
+ if (r < 0) {
+ if (!sd_bus_error_has_name(&error, "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"))
+ return r;
+ } else {
+ r = sd_bus_message_read_array(reply, 'y', &p, &sz);
+ if (r < 0)
+ return r;
- c->label = strndup(p, sz);
- if (!c->label)
- return -ENOMEM;
+ c->label = strndup(p, sz);
+ if (!c->label)
+ return -ENOMEM;
- c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+ c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+ }
}
r = bus_creds_add_more(c, mask, pid, 0);
@@ -781,7 +860,7 @@ _public_ int sd_bus_get_name_creds(
assert_return(bus, -EINVAL);
assert_return(name, -EINVAL);
- assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
assert_return(mask == 0 || creds, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(service_name_is_valid(name), -EINVAL);
@@ -791,23 +870,63 @@ _public_ int sd_bus_get_name_creds(
return -ENOTCONN;
if (bus->is_kernel)
- return bus_get_name_creds_kdbus(bus, name, mask, creds);
+ return bus_get_name_creds_kdbus(bus, name, mask, false, creds);
else
return bus_get_name_creds_dbus1(bus, name, mask, creds);
}
-_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
+static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
+ struct kdbus_cmd_info cmd = {
+ .size = sizeof(struct kdbus_cmd_info)
+ };
+ struct kdbus_info *creator_info;
pid_t pid = 0;
int r;
- assert_return(bus, -EINVAL);
- assert_return(mask <= _SD_BUS_CREDS_ALL, -ENOTSUP);
- assert_return(ret, -EINVAL);
- assert_return(!bus_pid_changed(bus), -ECHILD);
+ c = bus_creds_new();
+ if (!c)
+ return -ENOMEM;
- if (!BUS_IS_OPEN(bus->state))
- return -ENOTCONN;
+ cmd.flags = attach_flags_to_kdbus(mask);
+
+ /* If augmentation is on, and the bus doesn't didn't allow us
+ * to get the bits we want, then ask for the PID/TID so that we
+ * can read the rest from /proc. */
+ if ((mask & SD_BUS_CREDS_AUGMENT) &&
+ (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)))
+ cmd.flags |= KDBUS_ATTACH_PIDS;
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
+ if (r < 0)
+ return -errno;
+
+ creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
+
+ r = bus_populate_creds_from_items(bus, creator_info, mask, c);
+ bus_kernel_cmd_free(bus, cmd.offset);
+ if (r < 0)
+ return r;
+
+ r = bus_creds_add_more(c, mask, pid, 0);
+ if (r < 0)
+ return r;
+
+ *ret = c;
+ c = NULL;
+ return 0;
+}
+
+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;
+ int r;
if (!bus->ucred_valid && !isempty(bus->label))
return -ENODATA;
@@ -817,11 +936,20 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
return -ENOMEM;
if (bus->ucred_valid) {
- pid = c->pid = bus->ucred.pid;
- c->uid = bus->ucred.uid;
- c->gid = bus->ucred.gid;
+ if (bus->ucred.pid > 0) {
+ pid = c->pid = bus->ucred.pid;
+ c->mask |= SD_BUS_CREDS_PID & mask;
+ }
+
+ if (bus->ucred.uid != UID_INVALID) {
+ c->uid = bus->ucred.uid;
+ c->mask |= SD_BUS_CREDS_UID & mask;
+ }
- c->mask |= (SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID) & mask;
+ if (bus->ucred.gid != GID_INVALID) {
+ c->gid = bus->ucred.gid;
+ c->mask |= SD_BUS_CREDS_GID & mask;
+ }
}
if (!isempty(bus->label) && (mask & SD_BUS_CREDS_SELINUX_CONTEXT)) {
@@ -832,33 +960,30 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
- if (bus->is_kernel) {
- struct kdbus_cmd_info cmd = {};
- struct kdbus_info *creator_info;
-
- cmd.size = sizeof(cmd);
- r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
- if (r < 0)
- return -errno;
-
- creator_info = (struct kdbus_info *) ((uint8_t *) bus->kdbus_buffer + cmd.offset);
-
- r = bus_populate_creds_from_items(bus, creator_info, mask, c);
- kernel_cmd_free(bus, cmd.offset);
-
- if (r < 0)
- return r;
- } else {
- r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0)
- return r;
- }
+ r = bus_creds_add_more(c, mask, pid, 0);
+ if (r < 0)
+ return r;
*ret = c;
c = NULL;
return 0;
}
+_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
+ assert_return(bus, -EINVAL);
+ assert_return((mask & ~SD_BUS_CREDS_AUGMENT) <= _SD_BUS_CREDS_ALL, -ENOTSUP);
+ assert_return(ret, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (!BUS_IS_OPEN(bus->state))
+ return -ENOTCONN;
+
+ if (bus->is_kernel)
+ return bus_get_owner_creds_kdbus(bus, mask, ret);
+ else
+ return bus_get_owner_creds_dbus1(bus, mask, ret);
+}
+
static int add_name_change_match(sd_bus *bus,
uint64_t cookie,
const char *name,
@@ -1049,6 +1174,10 @@ int bus_add_match_internal_kernel(
assert(bus);
+ /* Monitor streams don't support matches, make this a NOP */
+ if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ return 0;
+
bloom = alloca0(bus->bloom_size);
sz = ALIGN8(offsetof(struct kdbus_cmd_match, items));
@@ -1261,6 +1390,10 @@ int bus_remove_match_internal_kernel(
assert(bus);
+ /* Monitor streams don't support matches, make this a NOP */
+ if (bus->hello_flags & KDBUS_HELLO_MONITOR)
+ return 0;
+
zero(m);
m.size = offsetof(struct kdbus_cmd_match, items);
m.cookie = cookie;
diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h
index aa290edac7..5009ca8e61 100644
--- a/src/libsystemd/sd-bus/bus-control.h
+++ b/src/libsystemd/sd-bus/bus-control.h
@@ -29,3 +29,5 @@ int bus_remove_match_internal(sd_bus *bus, const char *match, uint64_t cookie);
int bus_add_match_internal_kernel(sd_bus *bus, struct bus_match_component *components, unsigned n_components, uint64_t cookie);
int bus_remove_match_internal_kernel(sd_bus *bus, uint64_t cookie);
+
+int bus_get_name_creds_kdbus(sd_bus *bus, const char *name, uint64_t mask, bool allow_activator, sd_bus_creds **creds);
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 8081a2f9c0..ae0f4fa217 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -476,6 +476,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
uid_t our_uid;
+ bool know_caps = false;
int r;
assert_return(call, -EINVAL);
@@ -486,21 +487,21 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
if (!BUS_IS_OPEN(call->bus->state))
return -ENOTCONN;
- /* We only trust the effective capability set if this is
- * kdbus. On classic dbus1 we cannot retrieve the value
- * without races. Since this function is supposed to be useful
- * for authentication decision we hence avoid requesting and
- * using that information. */
- if (call->bus->is_kernel && capability >= 0) {
- r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
+ if (capability >= 0) {
+ r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
if (r < 0)
return r;
+ /* Note that not even on kdbus we might have the caps
+ * field, due to faked identities, or namespace
+ * translation issues. */
r = sd_bus_creds_has_effective_cap(creds, capability);
if (r > 0)
return 1;
+ if (r == 0)
+ know_caps = true;
} else {
- r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID, &creds);
+ r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
if (r < 0)
return r;
}
@@ -508,10 +509,14 @@ _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability)
/* Now, check the UID, but only if the capability check wasn't
* sufficient */
our_uid = getuid();
- if (our_uid != 0 || !call->bus->is_kernel || capability < 0) {
+ if (our_uid != 0 || !know_caps || capability < 0) {
uid_t sender_uid;
- r = sd_bus_creds_get_uid(creds, &sender_uid);
+ /* Try to use the EUID, if we have it. */
+ r = sd_bus_creds_get_euid(creds, &sender_uid);
+ if (r < 0)
+ r = sd_bus_creds_get_uid(creds, &sender_uid);
+
if (r >= 0) {
/* Sender has same UID as us, then let's grant access */
if (sender_uid == our_uid)
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index 26c25452bb..9978ddfa38 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -49,10 +49,16 @@ void bus_creds_done(sd_bus_creds *c) {
free(c->unit);
free(c->user_unit);
free(c->slice);
- free(c->unescaped_conn_name);
+ free(c->unescaped_description);
+
+ free(c->well_known_names); /* note that this is an strv, but
+ * we only free the array, not the
+ * strings the array points to. The
+ * full strv we only free if
+ * c->allocated is set, see
+ * below. */
strv_free(c->cmdline_array);
- strv_free(c->well_known_names);
}
_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
@@ -83,8 +89,6 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
c->n_ref--;
if (c->n_ref == 0) {
- bus_creds_done(c);
-
free(c->comm);
free(c->tid_comm);
free(c->exe);
@@ -94,7 +98,14 @@ _public_ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c) {
free(c->label);
free(c->unique_name);
free(c->cgroup_root);
- free(c->conn_name);
+ free(c->description);
+ free(c->supplementary_gids);
+
+ strv_free(c->well_known_names);
+ c->well_known_names = NULL;
+
+ bus_creds_done(c);
+
free(c);
}
} else {
@@ -141,7 +152,7 @@ _public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t m
if (!c)
return -ENOMEM;
- r = bus_creds_add_more(c, mask, pid, 0);
+ r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
if (r < 0) {
sd_bus_creds_unref(c);
return r;
@@ -169,6 +180,40 @@ _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
return 0;
}
+_public_ int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid) {
+ assert_return(c, -EINVAL);
+ assert_return(euid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_EUID))
+ return -ENODATA;
+
+ *euid = c->euid;
+ return 0;
+}
+
+_public_ int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid) {
+ assert_return(c, -EINVAL);
+ assert_return(suid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_SUID))
+ return -ENODATA;
+
+ *suid = c->suid;
+ return 0;
+}
+
+
+_public_ int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid) {
+ assert_return(c, -EINVAL);
+ assert_return(fsuid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_FSUID))
+ return -ENODATA;
+
+ *fsuid = c->fsuid;
+ return 0;
+}
+
_public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
assert_return(c, -EINVAL);
assert_return(gid, -EINVAL);
@@ -180,6 +225,51 @@ _public_ int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid) {
return 0;
}
+
+_public_ int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid) {
+ assert_return(c, -EINVAL);
+ assert_return(egid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_EGID))
+ return -ENODATA;
+
+ *egid = c->egid;
+ return 0;
+}
+
+_public_ int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid) {
+ assert_return(c, -EINVAL);
+ assert_return(sgid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_SGID))
+ return -ENODATA;
+
+ *sgid = c->sgid;
+ return 0;
+}
+
+_public_ int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid) {
+ assert_return(c, -EINVAL);
+ assert_return(fsgid, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_FSGID))
+ return -ENODATA;
+
+ *fsgid = c->fsgid;
+ return 0;
+}
+
+_public_ int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids) {
+ assert_return(c, -EINVAL);
+ assert_return(gids, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS))
+ return -ENODATA;
+
+ *gids = c->supplementary_gids;
+ return (int) c->n_supplementary_gids;
+}
+
_public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
assert_return(c, -EINVAL);
assert_return(pid, -EINVAL);
@@ -204,18 +294,6 @@ _public_ int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid) {
return 0;
}
-_public_ int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec) {
- assert_return(c, -EINVAL);
- assert_return(usec, -EINVAL);
-
- if (!(c->mask & SD_BUS_CREDS_PID_STARTTIME))
- return -ENODATA;
-
- assert(c->pid_starttime > 0);
- *usec = c->pid_starttime;
- return 0;
-}
-
_public_ int sd_bus_creds_get_selinux_context(sd_bus_creds *c, const char **ret) {
assert_return(c, -EINVAL);
@@ -461,26 +539,48 @@ _public_ int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***well_kno
if (!(c->mask & SD_BUS_CREDS_WELL_KNOWN_NAMES))
return -ENODATA;
+ /* As a special hack we return the bus driver as well-known
+ * names list when this is requested. */
+ if (c->well_known_names_driver) {
+ static const char* const wkn[] = {
+ "org.freedesktop.DBus",
+ NULL
+ };
+
+ *well_known_names = (char**) wkn;
+ return 0;
+ }
+
+ if (c->well_known_names_local) {
+ static const char* const wkn[] = {
+ "org.freedesktop.DBus.Local",
+ NULL
+ };
+
+ *well_known_names = (char**) wkn;
+ return 0;
+ }
+
*well_known_names = c->well_known_names;
return 0;
}
-_public_ int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **ret) {
+_public_ int sd_bus_creds_get_description(sd_bus_creds *c, const char **ret) {
assert_return(c, -EINVAL);
assert_return(ret, -EINVAL);
- if (!(c->mask & SD_BUS_CREDS_CONNECTION_NAME))
+ if (!(c->mask & SD_BUS_CREDS_DESCRIPTION))
return -ENODATA;
- assert(c->conn_name);
+ assert(c->description);
- if (!c->unescaped_conn_name) {
- c->unescaped_conn_name = bus_label_unescape(c->conn_name);
- if (!c->unescaped_conn_name)
+ if (!c->unescaped_description) {
+ c->unescaped_description = bus_label_unescape(c->description);
+ if (!c->unescaped_description)
return -ENOMEM;
}
- *ret = c->unescaped_conn_name;
+ *ret = c->unescaped_description;
return 0;
}
@@ -581,6 +681,9 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
assert(c);
assert(c->allocated);
+ if (!(mask & SD_BUS_CREDS_AUGMENT))
+ return 0;
+
missing = mask & ~c->mask;
if (missing == 0)
return 0;
@@ -596,139 +699,182 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (pid <= 0)
return 0;
- if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_GID |
+ if (pid > 0) {
+ c->pid = pid;
+ c->mask |= SD_BUS_CREDS_PID;
+ }
+
+ if (tid > 0) {
+ c->tid = tid;
+ c->mask |= SD_BUS_CREDS_TID;
+ }
+
+ if (missing & (SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
+ SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS |
SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS |
SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) {
_cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX];
const char *p;
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
- if (!f)
- return errno == ENOENT ? -ESRCH : -errno;
+ if (!f) {
+ if (errno == ENOENT)
+ return -ESRCH;
+ else if (errno != EPERM && errno != EACCES)
+ return -errno;
+ } else {
+ char line[LINE_MAX];
+
+ FOREACH_LINE(line, f, return -errno) {
+ truncate_nl(line);
+
+ if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) {
+ p = startswith(line, "Uid:");
+ if (p) {
+ unsigned long uid, euid, suid, fsuid;
+
+ p += strspn(p, WHITESPACE);
+ if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4)
+ return -EIO;
+
+ c->uid = (uid_t) uid;
+ c->euid = (uid_t) euid;
+ c->suid = (uid_t) suid;
+ c->fsuid = (uid_t) fsuid;
+ c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID);
+ continue;
+ }
+ }
- FOREACH_LINE(line, f, return -errno) {
- truncate_nl(line);
+ if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) {
+ p = startswith(line, "Gid:");
+ if (p) {
+ unsigned long gid, egid, sgid, fsgid;
+
+ p += strspn(p, WHITESPACE);
+ if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4)
+ return -EIO;
+
+ c->gid = (gid_t) gid;
+ c->egid = (gid_t) egid;
+ c->sgid = (gid_t) sgid;
+ c->fsgid = (gid_t) fsgid;
+ c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID);
+ continue;
+ }
+ }
- if (missing & SD_BUS_CREDS_UID) {
- p = startswith(line, "Uid:");
- if (p) {
- unsigned long uid;
+ if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ p = startswith(line, "Groups:");
+ if (p) {
+ size_t allocated = 0;
- p += strspn(p, WHITESPACE);
- if (sscanf(p, "%lu", &uid) != 1)
- return -EIO;
+ for (;;) {
+ unsigned long g;
+ int n = 0;
- c->uid = (uid_t) uid;
- c->mask |= SD_BUS_CREDS_UID;
- continue;
- }
- }
+ p += strspn(p, WHITESPACE);
+ if (*p == 0)
+ break;
- if (missing & SD_BUS_CREDS_GID) {
- p = startswith(line, "Gid:");
- if (p) {
- unsigned long gid;
+ if (sscanf(p, "%lu%n", &g, &n) != 1)
+ return -EIO;
- p += strspn(p, WHITESPACE);
- if (sscanf(p, "%lu", &gid) != 1)
- return -EIO;
+ if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1))
+ return -ENOMEM;
- c->gid = (uid_t) gid;
- c->mask |= SD_BUS_CREDS_GID;
- continue;
+ c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g;
+ p += n;
+ }
+
+ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
+ continue;
+ }
}
- }
- if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
- p = startswith(line, "CapEff:");
- if (p) {
- r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
- if (r < 0)
- return r;
+ if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) {
+ p = startswith(line, "CapEff:");
+ if (p) {
+ r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p);
+ if (r < 0)
+ return r;
- c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
- continue;
+ c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS;
+ continue;
+ }
}
- }
- if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
- p = startswith(line, "CapPrm:");
- if (p) {
- r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
- if (r < 0)
- return r;
+ if (missing & SD_BUS_CREDS_PERMITTED_CAPS) {
+ p = startswith(line, "CapPrm:");
+ if (p) {
+ r = parse_caps(c, CAP_OFFSET_PERMITTED, p);
+ if (r < 0)
+ return r;
- c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
- continue;
+ c->mask |= SD_BUS_CREDS_PERMITTED_CAPS;
+ continue;
+ }
}
- }
- if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
- p = startswith(line, "CapInh:");
- if (p) {
- r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
- if (r < 0)
- return r;
+ if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) {
+ p = startswith(line, "CapInh:");
+ if (p) {
+ r = parse_caps(c, CAP_OFFSET_INHERITABLE, p);
+ if (r < 0)
+ return r;
- c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
- continue;
+ c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS;
+ continue;
+ }
}
- }
- if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
- p = startswith(line, "CapBnd:");
- if (p) {
- r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
- if (r < 0)
- return r;
+ if (missing & SD_BUS_CREDS_BOUNDING_CAPS) {
+ p = startswith(line, "CapBnd:");
+ if (p) {
+ r = parse_caps(c, CAP_OFFSET_BOUNDING, p);
+ if (r < 0)
+ return r;
- c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
- continue;
+ c->mask |= SD_BUS_CREDS_BOUNDING_CAPS;
+ continue;
+ }
}
}
}
}
- if (missing & (SD_BUS_CREDS_PID_STARTTIME)) {
- unsigned long long st;
-
- r = get_starttime_of_pid(pid, &st);
- if (r < 0)
- return r;
-
- c->pid_starttime = ((usec_t) st * USEC_PER_SEC) / (usec_t) sysconf(_SC_CLK_TCK);
- c->mask |= SD_BUS_CREDS_PID_STARTTIME;
- }
-
if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
const char *p;
p = procfs_file_alloca(pid, "attr/current");
r = read_one_line_file(p, &c->label);
- if (r < 0 && r != -ENOENT && r != -EINVAL)
- return r;
- else if (r >= 0)
+ if (r < 0) {
+ if (r != -ENOENT && r != -EINVAL && r != -EPERM && r != -EACCES)
+ return r;
+ } else
c->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
if (missing & SD_BUS_CREDS_COMM) {
r = get_process_comm(pid, &c->comm);
- if (r < 0)
- return r;
-
- c->mask |= SD_BUS_CREDS_COMM;
+ if (r < 0) {
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ } else
+ c->mask |= SD_BUS_CREDS_COMM;
}
if (missing & SD_BUS_CREDS_EXE) {
r = get_process_exe(pid, &c->exe);
- if (r < 0)
- return r;
-
- c->mask |= SD_BUS_CREDS_EXE;
+ if (r < 0) {
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ } else
+ c->mask |= SD_BUS_CREDS_EXE;
}
if (missing & SD_BUS_CREDS_CMDLINE) {
@@ -736,14 +882,18 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
p = procfs_file_alloca(pid, "cmdline");
r = read_full_file(p, &c->cmdline, &c->cmdline_size);
- if (r < 0)
- return r;
-
- if (c->cmdline_size == 0) {
- free(c->cmdline);
- c->cmdline = NULL;
- } else
- c->mask |= SD_BUS_CREDS_CMDLINE;
+ if (r < 0) {
+ if (r == -ENOENT)
+ return -ESRCH;
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ } else {
+ if (c->cmdline_size == 0) {
+ free(c->cmdline);
+ c->cmdline = NULL;
+ } else
+ c->mask |= SD_BUS_CREDS_CMDLINE;
+ }
}
if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
@@ -753,38 +903,45 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
- if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
-
- c->mask |= SD_BUS_CREDS_TID_COMM;
+ if (r < 0) {
+ if (r == -ENOENT)
+ return -ESRCH;
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ } else
+ c->mask |= SD_BUS_CREDS_TID_COMM;
}
if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
r = cg_pid_get_path(NULL, pid, &c->cgroup);
- if (r < 0)
- return r;
-
- r = cg_get_root_path(&c->cgroup_root);
- if (r < 0)
- return r;
-
- c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
+ if (r < 0) {
+ if (r != -EPERM && r != -EACCES)
+ return r;
+ } else {
+ r = cg_get_root_path(&c->cgroup_root);
+ if (r < 0)
+ return r;
+
+ c->mask |= missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID);
+ }
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
r = audit_session_from_pid(pid, &c->audit_session_id);
- if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
- return r;
- else if (r >= 0)
+ if (r < 0) {
+ if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ return r;
+ } else
c->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
}
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
- if (r < 0 && r != -ENOTSUP && r != -ENXIO && r != -ENOENT)
- return r;
- else if (r >= 0)
+ if (r < 0) {
+ if (r != -ENOTSUP && r != -ENXIO && r != -ENOENT && r != -EPERM && r != -EACCES)
+ return r;
+ } else
c->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
}
@@ -798,8 +955,9 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
assert(c);
assert(ret);
- if ((mask & ~c->mask) == 0) {
- /* There's already all data we need. */
+ if ((mask & ~c->mask) == 0 || (!(mask & SD_BUS_CREDS_AUGMENT))) {
+ /* There's already all data we need, or augmentation
+ * wasn't turned on. */
*ret = sd_bus_creds_ref(c);
return 0;
@@ -816,11 +974,49 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= SD_BUS_CREDS_UID;
}
+ if (c->mask & mask & SD_BUS_CREDS_EUID) {
+ n->euid = c->euid;
+ n->mask |= SD_BUS_CREDS_EUID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_SUID) {
+ n->suid = c->suid;
+ n->mask |= SD_BUS_CREDS_SUID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_FSUID) {
+ n->fsuid = c->fsuid;
+ n->mask |= SD_BUS_CREDS_FSUID;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_GID) {
n->gid = c->gid;
n->mask |= SD_BUS_CREDS_GID;
}
+ if (c->mask & mask & SD_BUS_CREDS_EGID) {
+ n->egid = c->egid;
+ n->mask |= SD_BUS_CREDS_EGID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_SGID) {
+ n->sgid = c->sgid;
+ n->mask |= SD_BUS_CREDS_SGID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_FSGID) {
+ n->fsgid = c->fsgid;
+ n->mask |= SD_BUS_CREDS_FSGID;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ n->supplementary_gids = newdup(gid_t, c->supplementary_gids, c->n_supplementary_gids);
+ if (!n->supplementary_gids)
+ return -ENOMEM;
+ n->n_supplementary_gids = c->n_supplementary_gids;
+ n->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_PID) {
n->pid = c->pid;
n->mask |= SD_BUS_CREDS_PID;
@@ -831,11 +1027,6 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= SD_BUS_CREDS_TID;
}
- if (c->mask & mask & SD_BUS_CREDS_PID_STARTTIME) {
- n->pid_starttime = c->pid_starttime;
- n->mask |= SD_BUS_CREDS_PID_STARTTIME;
- }
-
if (c->mask & mask & SD_BUS_CREDS_COMM) {
n->comm = strdup(c->comm);
if (!n->comm)
@@ -890,11 +1081,17 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= c->mask & mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS);
}
+ if (c->mask & mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
+ n->label = strdup(c->label);
+ if (!n->label)
+ return -ENOMEM;
+ n->mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_AUDIT_SESSION_ID) {
n->audit_session_id = c->audit_session_id;
n->mask |= SD_BUS_CREDS_AUDIT_SESSION_ID;
}
-
if (c->mask & mask & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
n->audit_login_uid = c->audit_login_uid;
n->mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID;
@@ -904,12 +1101,21 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->unique_name = strdup(c->unique_name);
if (!n->unique_name)
return -ENOMEM;
+ n->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
if (c->mask & mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
n->well_known_names = strv_copy(c->well_known_names);
if (!n->well_known_names)
return -ENOMEM;
+ n->mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
+ }
+
+ if (c->mask & mask & SD_BUS_CREDS_DESCRIPTION) {
+ n->description = strdup(c->description);
+ if (!n->description)
+ return -ENOMEM;
+ n->mask |= SD_BUS_CREDS_DESCRIPTION;
}
/* Get more data */
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 81b852a596..48453e2afd 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -32,9 +32,18 @@ struct sd_bus_creds {
uint64_t mask;
uid_t uid;
+ uid_t euid;
+ uid_t suid;
+ uid_t fsuid;
gid_t gid;
+ gid_t egid;
+ gid_t sgid;
+ gid_t fsgid;
+
+ gid_t *supplementary_gids;
+ unsigned n_supplementary_gids;
+
pid_t pid;
- usec_t pid_starttime;
pid_t tid;
char *comm;
@@ -62,10 +71,12 @@ struct sd_bus_creds {
char *unique_name;
char **well_known_names;
+ bool well_known_names_driver:1;
+ bool well_known_names_local:1;
char *cgroup_root;
- char *conn_name, *unescaped_conn_name;
+ char *description, *unescaped_description;
};
sd_bus_creds* bus_creds_new(void);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 8b70b20e80..33d0ed2df6 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -23,27 +23,42 @@
#include "capability.h"
#include "strv.h"
#include "audit.h"
+#include "macro.h"
+#include "cap-list.h"
#include "bus-message.h"
#include "bus-internal.h"
#include "bus-type.h"
#include "bus-dump.h"
-static char *indent(unsigned level) {
+static char *indent(unsigned level, unsigned flags) {
char *p;
+ unsigned n, i = 0;
- p = new(char, 2 + level + 1);
+ n = 0;
+
+ if (flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY && level > 0)
+ level -= 1;
+
+ if (flags & BUS_MESSAGE_DUMP_WITH_HEADER)
+ n += 2;
+
+ p = new(char, n + level*8 + 1);
if (!p)
return NULL;
- p[0] = p[1] = ' ';
- memset(p + 2, '\t', level);
- p[2 + level] = 0;
+ if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
+ p[i++] = ' ';
+ p[i++] = ' ';
+ }
+
+ memset(p + i, ' ', level*8);
+ p[i + level*8] = 0;
return p;
}
-int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
+int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
unsigned level = 1;
int r;
@@ -52,7 +67,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
if (!f)
f = stdout;
- if (with_header) {
+ if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
fprintf(f,
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%lli",
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
@@ -107,16 +122,15 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
fputs("\n", f);
- bus_creds_dump(&m->creds, f);
+ bus_creds_dump(&m->creds, f, true);
}
- r = sd_bus_message_rewind(m, true);
- if (r < 0) {
- log_error("Failed to rewind: %s", strerror(-r));
- return r;
- }
+ r = sd_bus_message_rewind(m, !(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY));
+ if (r < 0)
+ return log_error_errno(r, "Failed to rewind: %m");
- fprintf(f, " MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
+ if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
+ fprintf(f, "%sMESSAGE \"%s\" {\n", indent(0, flags), strempty(m->root_container.signature));
for (;;) {
_cleanup_free_ char *prefix = NULL;
@@ -136,24 +150,20 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
} basic;
r = sd_bus_message_peek_type(m, &type, &contents);
- if (r < 0) {
- log_error("Failed to peek type: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to peek type: %m");
if (r == 0) {
if (level <= 1)
break;
r = sd_bus_message_exit_container(m);
- if (r < 0) {
- log_error("Failed to exit container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to exit container: %m");
level--;
- prefix = indent(level);
+ prefix = indent(level, flags);
if (!prefix)
return log_oom();
@@ -161,16 +171,14 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
continue;
}
- prefix = indent(level);
+ prefix = indent(level, flags);
if (!prefix)
return log_oom();
if (bus_type_is_container(type) > 0) {
r = sd_bus_message_enter_container(m, type, contents);
- if (r < 0) {
- log_error("Failed to enter container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enter container: %m");
if (type == SD_BUS_TYPE_ARRAY)
fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
@@ -187,10 +195,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
}
r = sd_bus_message_read_basic(m, type, &basic);
- if (r < 0) {
- log_error("Failed to get basic: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get basic: %m");
assert(r > 0);
@@ -253,7 +259,9 @@ int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
}
}
- fprintf(f, " };\n\n");
+ if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
+ fprintf(f, "%s};\n\n", indent(0, flags));
+
return 0;
}
@@ -261,6 +269,7 @@ static void dump_capabilities(
sd_bus_creds *c,
FILE *f,
const char *name,
+ bool terse,
int (*has)(sd_bus_creds *c, int capability)) {
unsigned long i, last_cap;
@@ -277,20 +286,18 @@ static void dump_capabilities(
if (r < 0)
return;
- fprintf(f, " %s=", name);
+ fprintf(f, "%s%s=%s", terse ? " " : "", name, terse ? "" : ansi_highlight());
last_cap = cap_last_cap();
for (;;) {
if (r > 0) {
- _cleanup_cap_free_charp_ char *t;
if (n > 0)
fputc(' ', f);
if (n % 4 == 3)
- fputs("\n ", f);
+ fprintf(f, terse ? "\n " : "\n ");
- t = cap_to_name(i);
- fprintf(f, "%s", t);
+ fprintf(f, "%s", strna(capability_to_name(i)));
n++;
}
@@ -303,14 +310,18 @@ static void dump_capabilities(
}
fputs("\n", f);
+
+ if (!terse)
+ fputs(ansi_highlight_off(), f);
}
-int bus_creds_dump(sd_bus_creds *c, FILE *f) {
+int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
uid_t owner, audit_loginuid;
uint32_t audit_sessionid;
char **cmdline = NULL, **well_known = NULL;
+ const char *prefix, *color, *suffix;
int r;
assert(c);
@@ -318,45 +329,76 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f) {
if (!f)
f = stdout;
+ if (terse) {
+ prefix = " ";
+ suffix = "";
+ color = "";
+ } else {
+ const char *off;
+
+ prefix = "";
+ color = ansi_highlight();
+
+ off = ansi_highlight_off();
+ suffix = strappenda(off, "\n");
+ }
+
if (c->mask & SD_BUS_CREDS_PID)
- fprintf(f, " PID="PID_FMT, c->pid);
- if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
- fprintf(f, " PIDStartTime="USEC_FMT, c->pid_starttime);
+ fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
if (c->mask & SD_BUS_CREDS_TID)
- fprintf(f, " TID="PID_FMT, c->tid);
+ fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
+
+ if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))))
+ fputs("\n", f);
+
if (c->mask & SD_BUS_CREDS_UID)
- fprintf(f, " UID="UID_FMT, c->uid);
+ fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
+ if (c->mask & SD_BUS_CREDS_EUID)
+ fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
+ if (c->mask & SD_BUS_CREDS_SUID)
+ fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
+ if (c->mask & SD_BUS_CREDS_FSUID)
+ fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
r = sd_bus_creds_get_owner_uid(c, &owner);
if (r >= 0)
- fprintf(f, " OwnerUID="UID_FMT, owner);
+ fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
if (c->mask & SD_BUS_CREDS_GID)
- fprintf(f, " GID="GID_FMT, c->gid);
+ fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
+ if (c->mask & SD_BUS_CREDS_EGID)
+ fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
+ if (c->mask & SD_BUS_CREDS_SGID)
+ fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
+ if (c->mask & SD_BUS_CREDS_FSGID)
+ fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
+
+ if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ unsigned i;
+
+ fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
+ for (i = 0; i < c->n_supplementary_gids; i++)
+ fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
+ fprintf(f, "%s", suffix);
+ }
- if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
+ if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
fputs("\n", f);
- if (c->mask & SD_BUS_CREDS_EXE)
- fprintf(f, " Exe=%s", c->exe);
if (c->mask & SD_BUS_CREDS_COMM)
- fprintf(f, " Comm=%s", c->comm);
+ fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
if (c->mask & SD_BUS_CREDS_TID_COMM)
- fprintf(f, " TIDComm=%s", c->tid_comm);
-
- if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
- fputs("\n", f);
-
- if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
- fprintf(f, " Label=%s", c->label);
- if (c->mask & SD_BUS_CREDS_CONNECTION_NAME)
- fprintf(f, " ConnectionName=%s", c->conn_name);
+ fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
+ if (c->mask & SD_BUS_CREDS_EXE)
+ fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
- if (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_CONNECTION_NAME))
+ if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
fputs("\n", f);
if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
char **i;
- fputs(" CommandLine={", f);
+ fprintf(f, "%sCommandLine=%s", prefix, color);
STRV_FOREACH(i, cmdline) {
if (i != cmdline)
fputc(' ', f);
@@ -364,46 +406,54 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f) {
fputs(*i, f);
}
- fputs("}\n", f);
+ fprintf(f, "%s", suffix);
}
+ if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
+ fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
+ if (c->mask & SD_BUS_CREDS_DESCRIPTION)
+ fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
+
+ if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
+ fputs("\n", f);
+
if (c->mask & SD_BUS_CREDS_CGROUP)
- fprintf(f, " CGroup=%s", c->cgroup);
+ fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
sd_bus_creds_get_unit(c, &u);
if (u)
- fprintf(f, " Unit=%s", u);
+ fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
sd_bus_creds_get_user_unit(c, &uu);
if (uu)
- fprintf(f, " UserUnit=%s", uu);
+ fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
sd_bus_creds_get_slice(c, &sl);
if (sl)
- fprintf(f, " Slice=%s", sl);
+ fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
sd_bus_creds_get_session(c, &s);
if (s)
- fprintf(f, " Session=%s", s);
+ fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
- if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
+ if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
fputs("\n", f);
if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
audit_loginuid_is_set = true;
- fprintf(f, " AuditLoginUID="UID_FMT, audit_loginuid);
+ fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
}
if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
audit_sessionid_is_set = true;
- fprintf(f, " AuditSessionID=%"PRIu32, audit_sessionid);
+ fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
}
- if (audit_loginuid_is_set || audit_sessionid_is_set)
+ if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
fputs("\n", f);
if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
- fprintf(f, " UniqueName=%s", c->unique_name);
+ fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
char **i;
- fputs(" WellKnownNames={", f);
+ fprintf(f, "%sWellKnownNames=%s", prefix, color);
STRV_FOREACH(i, well_known) {
if (i != well_known)
fputc(' ', f);
@@ -411,16 +461,111 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f) {
fputs(*i, f);
}
- fputc('}', f);
+ fprintf(f, "%s", suffix);
}
- if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
+ if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
fputc('\n', f);
- dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
- dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
- dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
- dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
+ dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
+ dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
+ dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
+ dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
+
+ return 0;
+}
+
+/*
+ * For details about the file format, see:
+ *
+ * http://wiki.wireshark.org/Development/LibpcapFileFormat
+ */
+
+typedef struct _packed_ pcap_hdr_s {
+ uint32_t magic_number; /* magic number */
+ uint16_t version_major; /* major version number */
+ uint16_t version_minor; /* minor version number */
+ int32_t thiszone; /* GMT to local correction */
+ uint32_t sigfigs; /* accuracy of timestamps */
+ uint32_t snaplen; /* max length of captured packets, in octets */
+ uint32_t network; /* data link type */
+} pcap_hdr_t ;
+
+typedef struct _packed_ pcaprec_hdr_s {
+ uint32_t ts_sec; /* timestamp seconds */
+ uint32_t ts_usec; /* timestamp microseconds */
+ uint32_t incl_len; /* number of octets of packet saved in file */
+ uint32_t orig_len; /* actual length of packet */
+} pcaprec_hdr_t;
+
+int bus_pcap_header(size_t snaplen, FILE *f) {
+
+ pcap_hdr_t hdr = {
+ .magic_number = 0xa1b2c3d4U,
+ .version_major = 2,
+ .version_minor = 4,
+ .thiszone = 0, /* UTC */
+ .sigfigs = 0,
+ .network = 231, /* D-Bus */
+ };
+
+ if (!f)
+ f = stdout;
+
+ assert(snaplen > 0);
+ assert((size_t) (uint32_t) snaplen == snaplen);
+
+ hdr.snaplen = (uint32_t) snaplen;
+
+ fwrite(&hdr, 1, sizeof(hdr), f);
+ fflush(f);
+
+ return 0;
+}
+
+int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
+ struct bus_body_part *part;
+ pcaprec_hdr_t hdr = {};
+ struct timeval tv;
+ unsigned i;
+ size_t w;
+
+ if (!f)
+ f = stdout;
+
+ assert(m);
+ assert(snaplen > 0);
+ assert((size_t) (uint32_t) snaplen == snaplen);
+
+ if (m->realtime != 0)
+ timeval_store(&tv, m->realtime);
+ else
+ assert_se(gettimeofday(&tv, NULL) >= 0);
+
+ hdr.ts_sec = tv.tv_sec;
+ hdr.ts_usec = tv.tv_usec;
+ hdr.orig_len = BUS_MESSAGE_SIZE(m);
+ hdr.incl_len = MIN(hdr.orig_len, snaplen);
+
+ /* write the pcap header */
+ fwrite(&hdr, 1, sizeof(hdr), f);
+
+ /* write the dbus header */
+ w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
+ fwrite(m->header, 1, w, f);
+ snaplen -= w;
+
+ /* write the dbus body */
+ MESSAGE_FOREACH_PART(part, i, m) {
+ if (snaplen <= 0)
+ break;
+
+ w = MIN(part->size, snaplen);
+ fwrite(part->data, 1, w, f);
+ snaplen -= w;
+ }
+
+ fflush(f);
return 0;
}
diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h
index bb1d25dc42..d2522edeba 100644
--- a/src/libsystemd/sd-bus/bus-dump.h
+++ b/src/libsystemd/sd-bus/bus-dump.h
@@ -26,6 +26,14 @@
#include "sd-bus.h"
-int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header);
+enum {
+ BUS_MESSAGE_DUMP_WITH_HEADER = 1,
+ BUS_MESSAGE_DUMP_SUBTREE_ONLY = 2,
+};
-int bus_creds_dump(sd_bus_creds *c, FILE *f);
+int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags);
+
+int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse);
+
+int bus_pcap_header(size_t snaplen, FILE *f);
+int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f);
diff --git a/src/libsystemd/sd-bus/bus-error-mapping.gperf b/src/libsystemd/sd-bus/bus-error-mapping.gperf
deleted file mode 100644
index 59eaa3554b..0000000000
--- a/src/libsystemd/sd-bus/bus-error-mapping.gperf
+++ /dev/null
@@ -1,50 +0,0 @@
-%{
-#include <errno.h>
-#include "bus-error.h"
-%}
-name_error_mapping;
-%null_strings
-%language=ANSI-C
-%define slot-name name
-%define hash-function-name bus_error_mapping_hash
-%define lookup-function-name bus_error_mapping_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-org.freedesktop.DBus.Error.Failed, EACCES
-org.freedesktop.DBus.Error.NoMemory, ENOMEM
-org.freedesktop.DBus.Error.ServiceUnknown, EHOSTUNREACH
-org.freedesktop.DBus.Error.NameHasNoOwner, ENXIO
-org.freedesktop.DBus.Error.NoReply, ETIMEDOUT
-org.freedesktop.DBus.Error.IOError, EIO
-org.freedesktop.DBus.Error.BadAddress, EADDRNOTAVAIL
-org.freedesktop.DBus.Error.NotSupported, ENOTSUP
-org.freedesktop.DBus.Error.LimitsExceeded, ENOBUFS
-org.freedesktop.DBus.Error.AccessDenied, EACCES
-org.freedesktop.DBus.Error.AuthFailed, EACCES
-org.freedesktop.DBus.Error.InteractiveAuthorizationRequired EACCES
-org.freedesktop.DBus.Error.NoServer, EHOSTDOWN
-org.freedesktop.DBus.Error.Timeout, ETIMEDOUT
-org.freedesktop.DBus.Error.NoNetwork, ENONET
-org.freedesktop.DBus.Error.AddressInUse, EADDRINUSE
-org.freedesktop.DBus.Error.Disconnected, ECONNRESET
-org.freedesktop.DBus.Error.InvalidArgs, EINVAL
-org.freedesktop.DBus.Error.FileNotFound, ENOENT
-org.freedesktop.DBus.Error.FileExists, EEXIST
-org.freedesktop.DBus.Error.UnknownMethod, EBADR
-org.freedesktop.DBus.Error.UnknownObject, EBADR
-org.freedesktop.DBus.Error.UnknownInterface, EBADR
-org.freedesktop.DBus.Error.UnknownProperty, EBADR
-org.freedesktop.DBus.Error.PropertyReadOnly, EROFS
-org.freedesktop.DBus.Error.UnixProcessIdUnknown, ESRCH
-org.freedesktop.DBus.Error.InvalidSignature, EINVAL
-org.freedesktop.DBus.Error.InconsistentMessage, EBADMSG
-#
-org.freedesktop.DBus.Error.TimedOut, ETIMEDOUT
-org.freedesktop.DBus.Error.MatchRuleInvalid, EINVAL
-org.freedesktop.DBus.Error.InvalidFileContent, EINVAL
-org.freedesktop.DBus.Error.MatchRuleNotFound, ENOENT
-org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown, ESRCH
-org.freedesktop.DBus.Error.ObjectPathInUse, EBUSY
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index af83c12d53..2955d9dd2b 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -32,13 +32,56 @@
#include "sd-bus.h"
#include "bus-error.h"
-#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
-#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoMemory", ENOMEM),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ServiceUnknown", EHOSTUNREACH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NameHasNoOwner", ENXIO),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoReply", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.IOError", EIO),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.BadAddress", EADDRNOTAVAIL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NotSupported", ENOTSUP),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.LimitsExceeded", ENOBUFS),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AccessDenied", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AuthFailed", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InteractiveAuthorizationRequired", EACCES),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoServer", EHOSTDOWN),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Timeout", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.NoNetwork", ENONET),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.AddressInUse", EADDRINUSE),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Disconnected", ECONNRESET),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidArgs", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileNotFound", ENOENT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.FileExists", EEXIST),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownMethod", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownObject", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownInterface", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnknownProperty", EBADR),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.PropertyReadOnly", EROFS),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.UnixProcessIdUnknown", ESRCH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidSignature", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InconsistentMessage", EBADMSG),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.TimedOut", ETIMEDOUT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleInvalid", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.InvalidFileContent", EINVAL),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.MatchRuleNotFound", ENOENT),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown", ESRCH),
+ SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.ObjectPathInUse", EBUSY),
+ SD_BUS_ERROR_MAP_END
+};
+
+/* GCC maps this magically to the beginning and end of the BUS_ERROR_MAP section */
+extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
+
+/* Additional maps registered with sd_bus_error_add_map() are in this
+ * NULL terminated array */
+static const sd_bus_error_map **additional_error_maps = NULL;
static int bus_error_name_to_errno(const char *name) {
+ const sd_bus_error_map **map, *m;
const char *p;
int r;
- const name_error_mapping *m;
if (!name)
return EINVAL;
@@ -52,9 +95,37 @@ static int bus_error_name_to_errno(const char *name) {
return r;
}
- m = bus_error_mapping_lookup(name, strlen(name));
- if (m)
- return m->code;
+ if (additional_error_maps) {
+ for (map = additional_error_maps; *map; map++) {
+ for (m = *map;; m++) {
+ /* For additional error maps the end marker is actually the end marker */
+ if (m->code == BUS_ERROR_MAP_END_MARKER)
+ break;
+
+ if (streq(m->name, name))
+ return m->code;
+ }
+ }
+ }
+
+ m = __start_BUS_ERROR_MAP;
+ while (m < __stop_BUS_ERROR_MAP) {
+ /* For magic ELF error maps, the end marker might
+ * appear in the middle of things, since multiple maps
+ * might appear in the same section. Hence, let's skip
+ * over it, but realign the pointer to the netx 8byte
+ * boundary, which is the selected alignment for the
+ * arrays. */
+ if (m->code == BUS_ERROR_MAP_END_MARKER) {
+ m = ALIGN8_PTR(m+1);
+ continue;
+ }
+
+ if (streq(m->name, name))
+ return m->code;
+
+ m++;
+ }
return EIO;
}
@@ -398,6 +469,7 @@ _public_ int sd_bus_error_set_errno(sd_bus_error *e, int error) {
}
int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) {
+ PROTECT_ERRNO;
int r;
if (error < 0)
@@ -431,8 +503,9 @@ int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_lis
if (format) {
char *m;
- /* First, let's try to fill in the supplied message */
+ /* Then, let's try to fill in the supplied message */
+ errno = error; /* Make sure that %m resolves to the specified error */
r = vasprintf(&m, format, ap);
if (r >= 0) {
@@ -504,3 +577,31 @@ const char *bus_error_message(const sd_bus_error *e, int error) {
return strerror(error);
}
+
+_public_ int sd_bus_error_add_map(const sd_bus_error_map *map) {
+ const sd_bus_error_map **maps = NULL;
+ unsigned n = 0;
+
+ assert_return(map, -EINVAL);
+
+ if (additional_error_maps) {
+ for (;; n++) {
+ if (additional_error_maps[n] == NULL)
+ break;
+
+ if (additional_error_maps[n] == map)
+ return 0;
+ }
+ }
+
+ maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2);
+ if (!maps)
+ return -ENOMEM;
+
+
+ maps[n] = map;
+ maps[n+1] = NULL;
+
+ additional_error_maps = maps;
+ return 1;
+}
diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h
index cf0ad9d545..fb0199c948 100644
--- a/src/libsystemd/sd-bus/bus-error.h
+++ b/src/libsystemd/sd-bus/bus-error.h
@@ -26,17 +26,40 @@
#include "sd-bus.h"
#include "macro.h"
-struct name_error_mapping {
- const char* name;
- int code;
-};
-typedef struct name_error_mapping name_error_mapping;
-
-const name_error_mapping* bus_error_mapping_lookup(const char *str, unsigned int len);
-
bool bus_error_is_dirty(sd_bus_error *e);
const char *bus_error_message(const sd_bus_error *e, int error);
int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_list ap) _printf_(3,0);
int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_list ap) _printf_(3,0);
+
+#define BUS_ERROR_OOM SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_MEMORY, "Out of memory")
+#define BUS_ERROR_FAILED SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FAILED, "Operation failed")
+
+/*
+ * There are two ways to register error maps with the error translation
+ * logic: by using BUS_ERROR_MAP_ELF_REGISTER, which however only
+ * works when linked into the same ELF module, or via
+ * sd_bus_error_add_map() which is the official, external API, that
+ * works from any module.
+ *
+ * Note that BUS_ERROR_MAP_ELF_REGISTER has to be used as decorator in
+ * the bus error table, and BUS_ERROR_MAP_ELF_USE has to be used at
+ * least once per compilation unit (i.e. per library), to ensure that
+ * the error map is really added to the final binary.
+ */
+
+#define BUS_ERROR_MAP_ELF_REGISTER \
+ __attribute__ ((__section__("BUS_ERROR_MAP"))) \
+ __attribute__ ((__used__)) \
+ __attribute__ ((aligned(8)))
+
+#define BUS_ERROR_MAP_ELF_USE(errors) \
+ extern const sd_bus_error_map errors[]; \
+ __attribute__ ((used)) static const sd_bus_error_map * const CONCATENATE(errors ## _copy_, __COUNTER__) = errors;
+
+/* We use something exotic as end marker, to ensure people build the
+ * maps using the macsd-ros. */
+#define BUS_ERROR_MAP_END_MARKER -'x'
+
+BUS_ERROR_MAP_ELF_USE(bus_standard_errors);
diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c
index 0bea8cac49..91b288cd25 100644
--- a/src/libsystemd/sd-bus/bus-internal.c
+++ b/src/libsystemd/sd-bus/bus-internal.c
@@ -166,6 +166,26 @@ bool service_name_is_valid(const char *p) {
return true;
}
+char* service_name_startswith(const char *a, const char *b) {
+ const char *p;
+
+ if (!service_name_is_valid(a) ||
+ !service_name_is_valid(b))
+ return NULL;
+
+ p = startswith(a, b);
+ if (!p)
+ return NULL;
+
+ if (*p == 0)
+ return (char*) p;
+
+ if (*p == '.')
+ return (char*) p + 1;
+
+ return NULL;
+}
+
bool member_name_is_valid(const char *p) {
const char *q;
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 57247d7df9..977b3407ba 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -142,6 +142,7 @@ struct sd_bus_slot {
void *userdata;
BusSlotType type:5;
bool floating:1;
+ char *description;
LIST_FIELDS(sd_bus_slot, slots);
@@ -205,6 +206,7 @@ struct sd_bus {
bool nodes_modified:1;
bool trusted:1;
bool fake_creds_valid:1;
+ bool fake_pids_valid:1;
bool manual_peer_interface:1;
bool is_system:1;
bool is_user:1;
@@ -305,11 +307,12 @@ struct sd_bus {
pid_t tid;
struct kdbus_creds fake_creds;
+ struct kdbus_pids fake_pids;
char *fake_label;
char *cgroup_root;
- char *connection_name;
+ char *description;
size_t bloom_size;
unsigned bloom_n_hash;
@@ -339,6 +342,7 @@ struct sd_bus {
bool interface_name_is_valid(const char *p) _pure_;
bool service_name_is_valid(const char *p) _pure_;
+char* service_name_startswith(const char *a, const char *b);
bool member_name_is_valid(const char *p) _pure_;
bool object_path_is_valid(const char *p) _pure_;
char *object_path_startswith(const char *a, const char *b) _pure_;
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index 0327614742..752c63adb3 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -31,6 +31,9 @@
#include "util.h"
#include "strv.h"
+#include "memfd-util.h"
+#include "cgroup-util.h"
+#include "fileio.h"
#include "bus-internal.h"
#include "bus-message.h"
@@ -38,7 +41,6 @@
#include "bus-bloom.h"
#include "bus-util.h"
#include "bus-label.h"
-#include "cgroup-util.h"
#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
@@ -76,7 +78,7 @@ static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz)
*d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
}
-static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
+static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) {
assert(d);
assert(memfd >= 0);
assert(sz > 0);
@@ -85,6 +87,7 @@ static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
(*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
(*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
(*d)->memfd.fd = memfd;
+ (*d)->memfd.start = start;
(*d)->memfd.size = sz;
*d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
@@ -133,6 +136,32 @@ static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
*d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
}
+static void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
+ char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+ char *e;
+
+ assert(data);
+ assert(size > 0);
+ assert(i < 64);
+ assert(t);
+
+ e = stpcpy(buf, "arg");
+ if (i < 10)
+ *(e++) = '0' + (char) i;
+ else {
+ *(e++) = '0' + (char) (i / 10);
+ *(e++) = '0' + (char) (i % 10);
+ }
+
+ *e = 0;
+ bloom_add_pair(data, size, n_hash, buf, t);
+
+ strcpy(e, "-dot-prefix");
+ bloom_add_prefixes(data, size, n_hash, buf, t, '.');
+ strcpy(e, "-slash-prefix");
+ bloom_add_prefixes(data, size, n_hash, buf, t, '/');
+}
+
static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
void *data;
unsigned i;
@@ -162,39 +191,42 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter
return r;
for (i = 0; i < 64; i++) {
+ const char *t, *contents;
char type;
- const char *t;
- char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
- char *e;
- r = sd_bus_message_peek_type(m, &type, NULL);
+ r = sd_bus_message_peek_type(m, &type, &contents);
if (r < 0)
return r;
- if (type != SD_BUS_TYPE_STRING &&
- type != SD_BUS_TYPE_OBJECT_PATH &&
- type != SD_BUS_TYPE_SIGNATURE)
- break;
+ if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
- r = sd_bus_message_read_basic(m, type, &t);
- if (r < 0)
- return r;
+ /* The bloom filter includes simple strings of any kind */
+ r = sd_bus_message_read_basic(m, type, &t);
+ if (r < 0)
+ return r;
- e = stpcpy(buf, "arg");
- if (i < 10)
- *(e++) = '0' + (char) i;
- else {
- *(e++) = '0' + (char) (i / 10);
- *(e++) = '0' + (char) (i % 10);
- }
+ add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
+ } if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) {
- *e = 0;
- bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t);
+ /* As well as array of simple strings of any kinds */
+ r = sd_bus_message_enter_container(m, type, contents);
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0)
+ add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
- strcpy(e, "-dot-prefix");
- bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.');
- strcpy(e, "-slash-prefix");
- bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/');
+ } else
+ /* Stop adding to bloom filter as soon as we
+ * run into the first argument we cannot add
+ * to it. */
+ break;
}
return 0;
@@ -203,6 +235,7 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter
static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
struct bus_body_part *part;
struct kdbus_item *d;
+ const char *destination;
bool well_known;
uint64_t unique;
size_t sz, dl;
@@ -218,8 +251,10 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
if (m->kdbus)
return 0;
- if (m->destination) {
- r = bus_kernel_parse_unique_name(m->destination, &unique);
+ destination = m->destination ?: m->destination_ptr;
+
+ if (destination) {
+ r = bus_kernel_parse_unique_name(destination, &unique);
if (r < 0)
return r;
@@ -229,12 +264,10 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
sz = offsetof(struct kdbus_msg, items);
- assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
- ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
-
/* Add in fixed header, fields header and payload */
- sz += (1 + m->n_body_parts) *
- ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
+ sz += (1 + m->n_body_parts) * ALIGN8(offsetof(struct kdbus_item, vec) +
+ MAX(sizeof(struct kdbus_vec),
+ sizeof(struct kdbus_memfd)));
/* Add space for bloom filter */
sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) +
@@ -243,7 +276,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
/* Add in well-known destination header */
if (well_known) {
- dl = strlen(m->destination);
+ dl = strlen(destination);
sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
}
@@ -263,16 +296,23 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
m->kdbus->flags =
((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
- m->kdbus->dst_id =
- well_known ? 0 :
- m->destination ? unique : KDBUS_DST_ID_BROADCAST;
+
+ if (well_known)
+ /* verify_destination_id will usually be 0, which makes the kernel driver only look
+ * at the provided well-known name. Otherwise, the kernel will make sure the provided
+ * destination id matches the owner of the provided weel-known-name, and fail if they
+ * differ. Currently, this is only needed for bus-proxyd. */
+ m->kdbus->dst_id = m->verify_destination_id;
+ else
+ m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST;
+
m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
m->kdbus->cookie = (uint64_t) m->header->serial;
m->kdbus->priority = m->priority;
- if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) {
+ if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
m->kdbus->cookie_reply = m->reply_cookie;
- } else {
+ else {
struct timespec now;
assert_se(clock_gettime(CLOCK_MONOTONIC_COARSE, &now) == 0);
@@ -283,7 +323,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
d = m->kdbus->items;
if (well_known)
- append_destination(&d, m->destination, dl);
+ append_destination(&d, destination, dl);
append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
@@ -298,11 +338,11 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
continue;
}
- if (part->memfd >= 0 && part->sealed && m->destination) {
+ if (part->memfd >= 0 && part->sealed && destination) {
/* Try to send a memfd, if the part is
* sealed and this is not a broadcast. Since we can only */
- append_payload_memfd(&d, part->memfd, part->size);
+ append_payload_memfd(&d, part->memfd, part->memfd_offset, part->size);
continue;
}
@@ -337,6 +377,15 @@ fail:
return r;
}
+static void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
+ assert(bus);
+ assert(m);
+
+ m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
+ m->creds.well_known_names_driver = true;
+ m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+}
+
static void unset_memfds(struct sd_bus_message *m) {
struct bus_body_part *part;
unsigned i;
@@ -372,7 +421,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
case KDBUS_ITEM_PAYLOAD_OFF:
if (!h) {
- h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
+ h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
if (!bus_header_is_complete(h, d->vec.size))
return -EBADMSG;
@@ -464,11 +513,11 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
if (idx >= begin_body) {
if (!part->is_zero)
- part->data = (uint8_t *)k + d->vec.offset;
+ part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
part->size = d->vec.size;
} else {
if (!part->is_zero)
- part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
+ part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
part->size = d->vec.size - (begin_body - idx);
}
@@ -494,6 +543,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
}
part->memfd = d->memfd.fd;
+ part->memfd_offset = d->memfd.start;
part->size = d->memfd.size;
part->sealed = true;
@@ -501,28 +551,70 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
break;
}
- case KDBUS_ITEM_CREDS:
- /* UID/GID/PID are always valid */
- m->creds.uid = (uid_t) d->creds.uid;
- m->creds.gid = (gid_t) d->creds.gid;
- m->creds.pid = (pid_t) d->creds.pid;
- m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
-
- /* The PID starttime/TID might be missing
- * however, when the data is faked by some
- * data bus proxy and it lacks that
- * information about the real client since
- * SO_PEERCRED is used for that */
-
- if (d->creds.starttime > 0) {
- m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
- m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
+ case KDBUS_ITEM_PIDS:
+
+ /* The PID/TID might be missing, when the data
+ * is faked by some data bus proxy and it
+ * lacks that information about the real
+ * client since SO_PEERCRED is used for
+ * that. */
+
+ if (d->pids.pid > 0) {
+ m->creds.pid = (pid_t) d->pids.pid;
+ m->creds.mask |= SD_BUS_CREDS_PID & bus->creds_mask;
}
- if (d->creds.tid > 0) {
- m->creds.tid = (pid_t) d->creds.tid;
+ if (d->pids.tid > 0) {
+ m->creds.tid = (pid_t) d->pids.tid;
m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
}
+
+ break;
+
+ case KDBUS_ITEM_CREDS:
+
+ /* EUID/SUID/FSUID/EGID/SGID/FSGID might be missing too (see above). */
+
+ if ((uid_t) d->creds.uid != UID_INVALID) {
+ m->creds.uid = (uid_t) d->creds.uid;
+ m->creds.mask |= SD_BUS_CREDS_UID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.euid != UID_INVALID) {
+ m->creds.euid = (uid_t) d->creds.euid;
+ m->creds.mask |= SD_BUS_CREDS_EUID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.suid != UID_INVALID) {
+ m->creds.suid = (uid_t) d->creds.suid;
+ m->creds.mask |= SD_BUS_CREDS_SUID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->creds.fsuid != UID_INVALID) {
+ m->creds.fsuid = (uid_t) d->creds.fsuid;
+ m->creds.mask |= SD_BUS_CREDS_FSUID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.gid != GID_INVALID) {
+ m->creds.gid = (gid_t) d->creds.gid;
+ m->creds.mask |= SD_BUS_CREDS_GID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.egid != GID_INVALID) {
+ m->creds.egid = (gid_t) d->creds.egid;
+ m->creds.mask |= SD_BUS_CREDS_EGID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.sgid != GID_INVALID) {
+ m->creds.sgid = (gid_t) d->creds.sgid;
+ m->creds.mask |= SD_BUS_CREDS_SGID & bus->creds_mask;
+ }
+
+ if ((gid_t) d->creds.fsgid != GID_INVALID) {
+ m->creds.fsgid = (gid_t) d->creds.fsgid;
+ m->creds.mask |= SD_BUS_CREDS_FSGID & bus->creds_mask;
+ }
+
break;
case KDBUS_ITEM_TIMESTAMP:
@@ -569,9 +661,15 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
break;
case KDBUS_ITEM_AUDIT:
- m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
- m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
- m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
+ if ((uint32_t) d->audit.sessionid != (uint32_t) -1) {
+ m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_SESSION_ID & bus->creds_mask;
+ }
+
+ if ((uid_t) d->audit.loginuid != UID_INVALID) {
+ m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
+ m->creds.mask |= SD_BUS_CREDS_AUDIT_LOGIN_UID & bus->creds_mask;
+ }
break;
case KDBUS_ITEM_CAPS:
@@ -581,24 +679,58 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
break;
case KDBUS_ITEM_DST_NAME:
- if (!service_name_is_valid(d->str))
- return -EBADMSG;
+ if (!service_name_is_valid(d->str)) {
+ r = -EBADMSG;
+ goto fail;
+ }
destination = d->str;
break;
- case KDBUS_ITEM_NAME:
- if (!service_name_is_valid(d->name.name))
- return -EBADMSG;
-
- r = strv_extend(&m->creds.well_known_names, d->name.name);
- if (r < 0)
+ case KDBUS_ITEM_OWNED_NAME:
+ if (!service_name_is_valid(d->name.name)) {
+ r = -EBADMSG;
goto fail;
+ }
+
+ if (bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES) {
+ char **wkn;
+ size_t n;
+
+ /* We just extend the array here, but
+ * do not allocate the strings inside
+ * of it, instead we just point to our
+ * buffer directly. */
+ n = strv_length(m->creds.well_known_names);
+ wkn = realloc(m->creds.well_known_names, (n + 2) * sizeof(char*));
+ if (!wkn) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ wkn[n] = d->name.name;
+ wkn[n+1] = NULL;
+ m->creds.well_known_names = wkn;
+
+ m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES;
+ }
break;
- case KDBUS_ITEM_CONN_NAME:
- m->creds.conn_name = d->str;
- m->creds.mask |= SD_BUS_CREDS_CONNECTION_NAME & bus->creds_mask;
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ m->creds.description = d->str;
+ m->creds.mask |= SD_BUS_CREDS_DESCRIPTION & bus->creds_mask;
+ break;
+
+ case KDBUS_ITEM_AUXGROUPS:
+
+ if (bus->creds_mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
+ assert_cc(sizeof(gid_t) == sizeof(uint32_t));
+
+ m->creds.n_supplementary_gids = (d->size - offsetof(struct kdbus_item, data32)) / sizeof(uint32_t);
+ m->creds.supplementary_gids = (gid_t*) d->data32;
+ m->creds.mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
+ }
+
break;
case KDBUS_ITEM_FDS:
@@ -610,13 +742,45 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
}
}
+ /* If we requested the list of well-known names to be appended
+ * and the sender had none no item for it will be
+ * attached. However, this does *not* mean that we the kernel
+ * didn't want to provide this information to us. Hence, let's
+ * explicitly mark this information as available if it was
+ * requested. */
+ m->creds.mask |= bus->creds_mask & SD_BUS_CREDS_WELL_KNOWN_NAMES;
+
r = bus_message_parse_fields(m);
if (r < 0)
goto fail;
+ /* Refuse messages if kdbus and dbus1 cookie doesn't match up */
+ if ((uint64_t) m->header->serial != k->cookie) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse messages where the reply flag doesn't match up */
+ if (!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) != !!(k->flags & KDBUS_MSG_FLAGS_EXPECT_REPLY)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse reply messages where the reply cookie doesn't match up */
+ if ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) && m->reply_cookie != k->cookie_reply) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
+ /* Refuse messages where the autostart flag doesn't match up */
+ if (!(m->header->flags & BUS_MESSAGE_NO_AUTO_START) != !(k->flags & KDBUS_MSG_FLAGS_NO_AUTO_START)) {
+ r = -EBADMSG;
+ goto fail;
+ }
+
/* Override information from the user header with data from the kernel */
if (k->src_id == KDBUS_SRC_ID_KERNEL)
- m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
+ bus_message_set_sender_driver(bus, m);
else {
snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
m->sender = m->creds.unique_name = m->sender_buffer;
@@ -665,8 +829,8 @@ int bus_kernel_take_fd(sd_bus *b) {
b->use_memfd = 1;
- if (b->connection_name) {
- g = bus_label_escape(b->connection_name);
+ if (b->description) {
+ g = bus_label_escape(b->description);
if (!g)
return -ENOMEM;
@@ -699,8 +863,8 @@ int bus_kernel_take_fd(sd_bus *b) {
name = g;
}
- b->connection_name = bus_label_unescape(name);
- if (!b->connection_name)
+ b->description = bus_label_unescape(name);
+ if (!b->description)
return -ENOMEM;
}
@@ -712,6 +876,9 @@ int bus_kernel_take_fd(sd_bus *b) {
if (b->fake_creds_valid)
sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds));
+ if (b->fake_pids_valid)
+ sz += ALIGN8(offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids));
+
if (b->fake_label) {
l = strlen(b->fake_label);
sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
@@ -720,13 +887,14 @@ int bus_kernel_take_fd(sd_bus *b) {
hello = alloca0_align(sz, 8);
hello->size = sz;
hello->flags = b->hello_flags;
- hello->attach_flags = b->attach_flags;
+ hello->attach_flags_send = _KDBUS_ATTACH_ANY;
+ hello->attach_flags_recv = b->attach_flags;
hello->pool_size = KDBUS_POOL_SIZE;
item = hello->items;
item->size = offsetof(struct kdbus_item, str) + m + 1;
- item->type = KDBUS_ITEM_CONN_NAME;
+ item->type = KDBUS_ITEM_CONN_DESCRIPTION;
memcpy(item->str, name, m + 1);
item = KDBUS_ITEM_NEXT(item);
@@ -738,6 +906,14 @@ int bus_kernel_take_fd(sd_bus *b) {
item = KDBUS_ITEM_NEXT(item);
}
+ if (b->fake_pids_valid) {
+ item->size = offsetof(struct kdbus_item, pids) + sizeof(struct kdbus_pids);
+ item->type = KDBUS_ITEM_PIDS;
+ item->pids = b->fake_pids;
+
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
if (b->fake_label) {
item->size = offsetof(struct kdbus_item, str) + l + 1;
item->type = KDBUS_ITEM_SECLABEL;
@@ -802,25 +978,37 @@ int bus_kernel_connect(sd_bus *b) {
return bus_kernel_take_fd(b);
}
+int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset) {
+ struct kdbus_cmd_free cmd = {
+ .flags = 0,
+ .offset = offset,
+ };
+ int r;
+
+ assert(bus);
+ assert(bus->is_kernel);
+
+ r = ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
- struct kdbus_cmd_free cmd;
struct kdbus_item *d;
assert(bus);
assert(k);
- cmd.flags = 0;
- cmd.offset = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
-
KDBUS_ITEM_FOREACH(d, k, items) {
-
if (d->type == KDBUS_ITEM_FDS)
close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
safe_close(d->memfd.fd);
}
- (void) ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
+ bus_kernel_cmd_free(bus, (uint8_t*) k - (uint8_t*) bus->kdbus_buffer);
}
int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) {
@@ -908,7 +1096,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
/* Anybody can send us invalid messages, let's just drop them. */
if (r == -EBADMSG || r == -EPROTOTYPE)
- log_debug("Ignoring invalid message: %s", strerror(-r));
+ log_debug_errno(r, "Ignoring invalid message: %m");
else
return r;
}
@@ -940,7 +1128,7 @@ static int push_name_owner_changed(sd_bus *bus, const char *name, const char *ol
if (r < 0)
return r;
- m->sender = "org.freedesktop.DBus";
+ bus_message_set_sender_driver(bus, m);
r = bus_seal_synthetic_message(bus, m);
if (r < 0)
@@ -1009,7 +1197,7 @@ static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *
if (r < 0)
return r;
- m->sender = "org.freedesktop.DBus";
+ bus_message_set_sender_driver(bus, m);
r = bus_seal_synthetic_message(bus, m);
if (r < 0)
@@ -1078,6 +1266,11 @@ int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
if (errno == EAGAIN)
return 0;
+ if (errno == EOVERFLOW) {
+ log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs);
+ return 0;
+ }
+
return -errno;
}
@@ -1087,7 +1280,7 @@ int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
/* Anybody can send us invalid messages, let's just drop them. */
if (r == -EBADMSG || r == -EPROTOTYPE) {
- log_debug("Ignoring invalid message: %s", strerror(-r));
+ log_debug_errno(r, "Ignoring invalid message: %m");
r = 0;
}
@@ -1118,20 +1311,13 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
if (bus->n_memfd_cache <= 0) {
- _cleanup_free_ char *g = NULL;
int r;
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
- assert(bus->connection_name);
-
- g = bus_label_escape(bus->connection_name);
- if (!g)
- return -ENOMEM;
-
- r = memfd_create(g, MFD_ALLOW_SEALING);
+ r = memfd_new(bus->description);
if (r < 0)
- return -errno;
+ return r;
*address = NULL;
*mapped = 0;
@@ -1188,7 +1374,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si
/* If overly long, let's return a bit to the OS */
if (mapped > max_mapped) {
- assert_se(ftruncate(fd, max_mapped) >= 0);
+ assert_se(memfd_set_size(fd, max_mapped) >= 0);
assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0);
c->mapped = c->allocated = max_mapped;
} else {
@@ -1208,11 +1394,9 @@ void bus_kernel_flush_memfd(sd_bus *b) {
close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
}
-int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
+uint64_t request_name_flags_to_kdbus(uint64_t flags) {
uint64_t f = 0;
- assert(kdbus_flags);
-
if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
f |= KDBUS_NAME_ALLOW_REPLACEMENT;
@@ -1222,18 +1406,19 @@ int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
if (flags & SD_BUS_NAME_QUEUE)
f |= KDBUS_NAME_QUEUE;
- *kdbus_flags = f;
- return 0;
+ return f;
}
-int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
+uint64_t attach_flags_to_kdbus(uint64_t mask) {
uint64_t m = 0;
- assert(kdbus_mask);
-
- if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
+ if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID))
m |= KDBUS_ATTACH_CREDS;
+ if (mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))
+ m |= KDBUS_ATTACH_PIDS;
+
if (mask & SD_BUS_CREDS_COMM)
m |= KDBUS_ATTACH_PID_COMM;
@@ -1261,38 +1446,42 @@ int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
m |= KDBUS_ATTACH_NAMES;
- if (mask & SD_BUS_CREDS_CONNECTION_NAME)
- m |= KDBUS_ATTACH_CONN_NAME;
+ if (mask & SD_BUS_CREDS_DESCRIPTION)
+ m |= KDBUS_ATTACH_CONN_DESCRIPTION;
- *kdbus_mask = m;
- return 0;
+ if (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS)
+ m |= KDBUS_ATTACH_AUXGROUPS;
+
+ return m;
}
int bus_kernel_create_bus(const char *name, bool world, char **s) {
struct kdbus_cmd_make *make;
struct kdbus_item *n;
+ size_t l;
int fd;
assert(name);
assert(s);
- fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
+ fd = open("/sys/fs/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
- make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
- offsetof(struct kdbus_item, data64) + sizeof(uint64_t) +
- offsetof(struct kdbus_item, str) +
- DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1),
+ l = strlen(name);
+ make = alloca0_align(offsetof(struct kdbus_cmd_make, items) +
+ ALIGN8(offsetof(struct kdbus_item, bloom_parameter) + sizeof(struct kdbus_bloom_parameter)) +
+ ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)) +
+ ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1),
8);
make->size = offsetof(struct kdbus_cmd_make, items);
+ /* Set the bloom parameters */
n = make->items;
n->size = offsetof(struct kdbus_item, bloom_parameter) +
sizeof(struct kdbus_bloom_parameter);
n->type = KDBUS_ITEM_BLOOM_PARAMETER;
-
n->bloom_parameter.size = DEFAULT_BLOOM_SIZE;
n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH;
@@ -1301,6 +1490,15 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
make->size += ALIGN8(n->size);
+ /* The busses we create make no restrictions on what metadata
+ * peers can read from incoming messages. */
+ n = KDBUS_ITEM_NEXT(n);
+ n->type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
+ n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
+ n->data64[0] = _KDBUS_ATTACH_ANY;
+ make->size += ALIGN8(n->size);
+
+ /* Set the a good name */
n = KDBUS_ITEM_NEXT(n);
sprintf(n->str, UID_FMT "-%s", getuid(), name);
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
@@ -1317,7 +1515,7 @@ int bus_kernel_create_bus(const char *name, bool world, char **s) {
if (s) {
char *p;
- p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
+ p = strjoin("/sys/fs/kdbus/", n->str, "/bus", NULL);
if (!p) {
safe_close(fd);
return -ENOMEM;
@@ -1397,20 +1595,29 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) {
int fd;
size_t len;
- len = strlen("/dev/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1;
+ assert(bus);
+
+ len = strlen("/sys/fs/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1;
if (path) {
- p = malloc(len);
+ p = new(char, len);
if (!p)
return -ENOMEM;
- *path = p;
} else
- p = alloca(len);
- sprintf(p, "/dev/kdbus/" UID_FMT "-%s/bus", getuid(), bus);
+ p = newa(char, len);
+
+ sprintf(p, "/sys/fs/kdbus/" UID_FMT "-%s/bus", getuid(), bus);
fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
+ if (fd < 0) {
+ if (path)
+ free(p);
+
return -errno;
+ }
+
+ if (path)
+ *path = p;
return fd;
}
@@ -1419,25 +1626,25 @@ int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char *
_cleanup_free_ char *path = NULL;
struct kdbus_cmd_make *make;
struct kdbus_item *n;
- size_t size;
+ const char *name;
int fd;
fd = bus_kernel_open_bus_fd(bus_name, &path);
if (fd < 0)
return fd;
- size = ALIGN8(offsetof(struct kdbus_cmd_make, items));
- size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(ep_name) + 1);
-
- make = alloca0_align(size, 8);
- make->size = size;
+ make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items)) +
+ ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + strlen(ep_name) + 1),
+ 8);
+ make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items));
make->flags = KDBUS_MAKE_ACCESS_WORLD;
n = make->items;
-
+ sprintf(n->str, UID_FMT "-%s", getuid(), ep_name);
+ n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
n->type = KDBUS_ITEM_MAKE_NAME;
- n->size = offsetof(struct kdbus_item, str) + strlen(ep_name) + 1;
- strcpy(n->str, ep_name);
+ make->size += ALIGN8(n->size);
+ name = n->str;
if (ioctl(fd, KDBUS_CMD_ENDPOINT_MAKE, make) < 0) {
safe_close(fd);
@@ -1447,7 +1654,7 @@ int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char *
if (ep_path) {
char *p;
- p = strjoin(dirname(path), "/", ep_name, NULL);
+ p = strjoin(dirname(path), "/", name, NULL);
if (!p) {
safe_close(fd);
return -ENOMEM;
@@ -1527,7 +1734,7 @@ int bus_kernel_make_starter(
if (world_policy >= 0)
policy_cnt++;
- size = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
+ size = offsetof(struct kdbus_cmd_hello, items) +
ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) +
policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
@@ -1562,7 +1769,8 @@ int bus_kernel_make_starter(
(activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) |
(accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0);
hello->pool_size = KDBUS_POOL_SIZE;
- hello->attach_flags = _KDBUS_ATTACH_ALL;
+ hello->attach_flags_send = _KDBUS_ATTACH_ANY;
+ hello->attach_flags_recv = _KDBUS_ATTACH_ANY;
if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0)
return -errno;
@@ -1578,77 +1786,122 @@ int bus_kernel_make_starter(
return fd;
}
-int bus_kernel_create_domain(const char *name, char **s) {
- struct kdbus_cmd_make *make;
- struct kdbus_item *n;
- int fd;
+int bus_kernel_try_close(sd_bus *bus) {
+ assert(bus);
+ assert(bus->is_kernel);
- assert(name);
- assert(s);
+ if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
+ return -errno;
- fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
+ return 0;
+}
+
+int bus_kernel_drop_one(int fd) {
+ struct kdbus_cmd_recv recv = {
+ .flags = KDBUS_RECV_DROP
+ };
+
+ assert(fd >= 0);
+
+ if (ioctl(fd, KDBUS_CMD_MSG_RECV, &recv) < 0)
return -errno;
- make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
- offsetof(struct kdbus_item, str) +
- strlen(name) + 1),
- 8);
+ return 0;
+}
- n = make->items;
- strcpy(n->str, name);
- n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
- n->type = KDBUS_ITEM_MAKE_NAME;
+int bus_kernel_realize_attach_flags(sd_bus *bus) {
+ struct kdbus_cmd_update *update;
+ struct kdbus_item *n;
- make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size);
- make->flags = KDBUS_MAKE_ACCESS_WORLD;
+ assert(bus);
+ assert(bus->is_kernel);
- if (ioctl(fd, KDBUS_CMD_DOMAIN_MAKE, make) < 0) {
- safe_close(fd);
+ update = alloca0_align(offsetof(struct kdbus_cmd_update, items) +
+ ALIGN8(offsetof(struct kdbus_item, data64) + sizeof(uint64_t)),
+ 8);
+
+ n = update->items;
+ n->type = KDBUS_ITEM_ATTACH_FLAGS_RECV;
+ n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
+ n->data64[0] = bus->attach_flags;
+
+ update->size =
+ offsetof(struct kdbus_cmd_update, items) +
+ ALIGN8(n->size);
+
+ if (ioctl(bus->input_fd, KDBUS_CMD_CONN_UPDATE, update) < 0)
return -errno;
- }
- /* The higher 32bit of the flags field are considered
- * 'incompatible flags'. Refuse them all for now. */
- if (make->flags > 0xFFFFFFFFULL) {
- safe_close(fd);
- return -ENOTSUP;
- }
+ return 0;
+}
- if (s) {
- char *p;
+int bus_kernel_fix_attach_mask(void) {
+ _cleanup_free_ char *mask = NULL;
+ uint64_t m = (uint64_t) -1;
+ char buf[2+16+2];
+ int r;
- p = strappend("/dev/kdbus/domain/", name);
- if (!p) {
- safe_close(fd);
- return -ENOMEM;
- }
+ /* By default we don't want any kdbus metadata fields to be
+ * suppressed, hence we reset the kernel mask for it to
+ * (uint64_t) -1. This is overridable via a kernel command
+ * line option, however. */
- *s = p;
+ r = get_proc_cmdline_key("systemd.kdbus_attach_flags_mask=", &mask);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to read kernel command line: %m");
+
+ if (mask) {
+ const char *p = mask;
+
+ if (startswith(p, "0x"))
+ p += 2;
+
+ if (sscanf(p, "%" PRIx64, &m) != 1)
+ log_warning("Couldn't parse systemd.kdbus_attach_flags_mask= kernel command line parameter.");
}
- return fd;
+ sprintf(buf, "0x%" PRIx64 "\n", m);
+ r = write_string_file("/sys/module/kdbus/parameters/attach_flags_mask", buf);
+ if (r < 0)
+ return log_full_errno(
+ IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to write kdbus attach mask: %m");
+
+ return 0;
}
-int bus_kernel_try_close(sd_bus *bus) {
+int bus_kernel_get_bus_name(sd_bus *bus, char **name) {
+ struct kdbus_cmd_info cmd = {
+ .size = sizeof(struct kdbus_cmd_info),
+ };
+ struct kdbus_info *info;
+ struct kdbus_item *item;
+ char *n = NULL;
+ int r;
+
assert(bus);
+ assert(name);
assert(bus->is_kernel);
- if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
+ r = ioctl(bus->input_fd, KDBUS_CMD_BUS_CREATOR_INFO, &cmd);
+ if (r < 0)
return -errno;
- return 0;
-}
+ info = (struct kdbus_info*) ((uint8_t*) bus->kdbus_buffer + cmd.offset);
-int bus_kernel_drop_one(int fd) {
- struct kdbus_cmd_recv recv = {
- .flags = KDBUS_RECV_DROP
- };
+ KDBUS_ITEM_FOREACH(item, info, items)
+ if (item->type == KDBUS_ITEM_MAKE_NAME) {
+ r = free_and_strdup(&n, item->str);
+ break;
+ }
- assert(fd >= 0);
+ bus_kernel_cmd_free(bus, cmd.offset);
- if (ioctl(fd, KDBUS_CMD_MSG_RECV, &recv) < 0)
- return -errno;
+ if (r < 0)
+ return r;
+ if (!n)
+ return -EIO;
+ *name = n;
return 0;
}
diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h
index f1d832a764..2152f62d12 100644
--- a/src/libsystemd/sd-bus/bus-kernel.h
+++ b/src/libsystemd/sd-bus/bus-kernel.h
@@ -71,7 +71,6 @@ int bus_kernel_make_starter(int fd, const char *name, bool activating, bool acce
int bus_kernel_create_bus(const char *name, bool world, char **s);
int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **path);
-int bus_kernel_create_domain(const char *name, char **s);
int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep);
@@ -82,9 +81,17 @@ void bus_kernel_flush_memfd(sd_bus *bus);
int bus_kernel_parse_unique_name(const char *s, uint64_t *id);
-int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
-int kdbus_translate_attach_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags);
+uint64_t request_name_flags_to_kdbus(uint64_t sd_bus_flags);
+uint64_t attach_flags_to_kdbus(uint64_t sd_bus_flags);
int bus_kernel_try_close(sd_bus *bus);
int bus_kernel_drop_one(int fd);
+
+int bus_kernel_realize_attach_flags(sd_bus *bus);
+
+int bus_kernel_fix_attach_mask(void);
+
+int bus_kernel_get_bus_name(sd_bus *bus, char **name);
+
+int bus_kernel_cmd_free(sd_bus *bus, uint64_t offset);
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index 18afe0f12a..3a31aa0ebf 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -134,6 +134,7 @@ static bool value_node_test(
enum bus_match_node_type parent_type,
uint8_t value_u8,
const char *value_str,
+ char **value_strv,
sd_bus_message *m) {
assert(node);
@@ -179,17 +180,46 @@ static bool value_node_test(
case BUS_MATCH_INTERFACE:
case BUS_MATCH_MEMBER:
case BUS_MATCH_PATH:
- case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
- return streq_ptr(node->value.str, value_str);
+ case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST: {
+ char **i;
- case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
- return namespace_simple_pattern(node->value.str, value_str);
+ if (value_str)
+ return streq_ptr(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (streq_ptr(node->value.str, *i))
+ return true;
+
+ return false;
+ }
+
+ case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST: {
+ char **i;
+
+ if (value_str)
+ return namespace_simple_pattern(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (namespace_simple_pattern(node->value.str, *i))
+ return true;
+ return false;
+ }
case BUS_MATCH_PATH_NAMESPACE:
return path_simple_pattern(node->value.str, value_str);
- case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
- return path_complex_pattern(node->value.str, value_str);
+ case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST: {
+ char **i;
+
+ if (value_str)
+ return path_complex_pattern(node->value.str, value_str);
+
+ STRV_FOREACH(i, value_strv)
+ if (path_complex_pattern(node->value.str, *i))
+ return true;
+
+ return false;
+ }
default:
assert_not_reached("Invalid node type");
@@ -235,7 +265,7 @@ int bus_match_run(
struct bus_match_node *node,
sd_bus_message *m) {
-
+ _cleanup_strv_free_ char **test_strv = NULL;
const char *test_str = NULL;
uint8_t test_u8 = 0;
int r;
@@ -343,15 +373,15 @@ int bus_match_run(
break;
case BUS_MATCH_ARG ... BUS_MATCH_ARG_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG, &test_str, &test_strv);
break;
case BUS_MATCH_ARG_PATH ... BUS_MATCH_ARG_PATH_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_PATH, &test_str, &test_strv);
break;
case BUS_MATCH_ARG_NAMESPACE ... BUS_MATCH_ARG_NAMESPACE_LAST:
- test_str = bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE);
+ (void) bus_message_get_arg(m, node->type - BUS_MATCH_ARG_NAMESPACE, &test_str, &test_strv);
break;
default:
@@ -365,7 +395,20 @@ int bus_match_run(
if (test_str)
found = hashmap_get(node->compare.children, test_str);
- else if (node->type == BUS_MATCH_MESSAGE_TYPE)
+ else if (test_strv) {
+ char **i;
+
+ STRV_FOREACH(i, test_strv) {
+ found = hashmap_get(node->compare.children, *i);
+ if (found) {
+ r = bus_match_run(bus, found, m);
+ if (r != 0)
+ return r;
+ }
+ }
+
+ found = NULL;
+ } else if (node->type == BUS_MATCH_MESSAGE_TYPE)
found = hashmap_get(node->compare.children, UINT_TO_PTR(test_u8));
else
found = NULL;
@@ -381,7 +424,7 @@ int bus_match_run(
/* No hash table, so let's iterate manually... */
for (c = node->child; c; c = c->next) {
- if (!value_node_test(c, node->type, test_u8, test_str, m))
+ if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m))
continue;
r = bus_match_run(bus, c, m);
@@ -537,7 +580,7 @@ static int bus_match_find_compare_value(
else if (BUS_MATCH_CAN_HASH(t))
n = hashmap_get(c->compare.children, value_str);
else {
- for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next)
+ for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next)
;
}
@@ -748,6 +791,9 @@ int bus_match_parse(
bool escaped = false, quoted;
uint8_t u;
+ /* Avahi's match rules appear to include whitespace, skip over it */
+ p += strspn(p, " ");
+
eq = strchr(p, '=');
if (!eq)
return -EINVAL;
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 1362a60f08..06d8d770fd 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -28,7 +28,7 @@
#include "strv.h"
#include "time-util.h"
#include "cgroup-util.h"
-#include "memfd.h"
+#include "memfd-util.h"
#include "sd-bus.h"
#include "bus-message.h"
@@ -69,13 +69,13 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
else {
if (part->mapped > 0)
- assert_se(munmap(part->data, part->mapped) == 0);
+ assert_se(munmap(part->mmap_begin, part->mapped) == 0);
safe_close(part->memfd);
}
} else if (part->munmap_this)
- munmap(part->data, part->mapped);
+ munmap(part->mmap_begin, part->mapped);
else if (part->free_this)
free(part->data);
@@ -148,6 +148,11 @@ static void message_free(sd_bus_message *m) {
if (m->iovec != m->iovec_fixed)
free(m->iovec);
+ if (m->destination_ptr) {
+ free(m->destination_ptr);
+ m->destination_ptr = NULL;
+ }
+
message_reset_containers(m);
free(m->root_container.signature);
free(m->root_container.offsets);
@@ -415,10 +420,20 @@ int bus_message_from_header(
m->n_fds = n_fds;
if (ucred) {
- m->creds.uid = ucred->uid;
m->creds.pid = ucred->pid;
+ m->creds.uid = ucred->uid;
m->creds.gid = ucred->gid;
- m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
+
+ /* Due to namespace translations some data might be
+ * missing from this ucred record. */
+ if (m->creds.pid > 0)
+ m->creds.mask |= SD_BUS_CREDS_PID;
+
+ if (m->creds.uid != UID_INVALID)
+ m->creds.mask |= SD_BUS_CREDS_UID;
+
+ if (m->creds.gid != GID_INVALID)
+ m->creds.mask |= SD_BUS_CREDS_GID;
}
if (label) {
@@ -1097,10 +1112,10 @@ static int part_make_space(
uint64_t new_allocated;
new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
- r = ftruncate(part->memfd, new_allocated);
+ r = memfd_set_size(part->memfd, new_allocated);
if (r < 0) {
m->poisoned = true;
- return -errno;
+ return r;
}
part->allocated = new_allocated;
@@ -1113,15 +1128,16 @@ static int part_make_space(
if (part->mapped <= 0)
n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
else
- n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
+ n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE);
if (n == MAP_FAILED) {
m->poisoned = true;
return -errno;
}
+ part->mmap_begin = part->data = n;
part->mapped = psz;
- part->data = n;
+ part->memfd_offset = 0;
}
part->munmap_this = true;
@@ -2048,6 +2064,7 @@ static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c)
assert(m);
assert(c);
+ assert(c->signature);
if (!BUS_MESSAGE_IS_GVARIANT(m))
return 0;
@@ -2487,10 +2504,11 @@ _public_ int sd_bus_message_append_array_space(
return 0;
}
-_public_ int sd_bus_message_append_array(sd_bus_message *m,
- char type,
- const void *ptr,
- size_t size) {
+_public_ int sd_bus_message_append_array(
+ sd_bus_message *m,
+ char type,
+ const void *ptr,
+ size_t size) {
int r;
void *p;
@@ -2546,26 +2564,26 @@ _public_ int sd_bus_message_append_array_iovec(
return 0;
}
-_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
- char type,
- int memfd) {
+_public_ int sd_bus_message_append_array_memfd(
+ sd_bus_message *m,
+ char type,
+ int memfd,
+ uint64_t offset,
+ uint64_t size) {
+
_cleanup_close_ int copy_fd = -1;
struct bus_body_part *part;
ssize_t align, sz;
- uint64_t size;
+ uint64_t real_size;
void *a;
int r;
- if (!m)
- return -EINVAL;
- if (memfd < 0)
- return -EINVAL;
- if (m->sealed)
- return -EPERM;
- if (!bus_type_is_trivial(type))
- return -EINVAL;
- if (m->poisoned)
- return -ESTALE;
+ assert_return(m, -EINVAL);
+ assert_return(memfd >= 0, -EINVAL);
+ assert_return(bus_type_is_trivial(type), -EINVAL);
+ assert_return(size > 0, -EINVAL);
+ assert_return(!m->sealed, -EPERM);
+ assert_return(!m->poisoned, -ESTALE);
r = memfd_set_sealed(memfd);
if (r < 0)
@@ -2575,16 +2593,24 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
if (copy_fd < 0)
return copy_fd;
- r = memfd_get_size(memfd, &size);
+ r = memfd_get_size(memfd, &real_size);
if (r < 0)
return r;
+ if (offset == 0 && size == (uint64_t) -1)
+ size = real_size;
+ else if (offset + size > real_size)
+ return -EMSGSIZE;
+
align = bus_type_get_alignment(type);
sz = bus_type_get_size(type);
assert_se(align > 0);
assert_se(sz > 0);
+ if (offset % align != 0)
+ return -EINVAL;
+
if (size % sz != 0)
return -EINVAL;
@@ -2604,6 +2630,7 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
return -ENOMEM;
part->memfd = copy_fd;
+ part->memfd_offset = offset;
part->sealed = true;
part->size = size;
copy_fd = -1;
@@ -2614,16 +2641,22 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
return sd_bus_message_close_container(m);
}
-_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd) {
+_public_ int sd_bus_message_append_string_memfd(
+ sd_bus_message *m,
+ int memfd,
+ uint64_t offset,
+ uint64_t size) {
+
_cleanup_close_ int copy_fd = -1;
struct bus_body_part *part;
struct bus_container *c;
- uint64_t size;
+ uint64_t real_size;
void *a;
int r;
assert_return(m, -EINVAL);
assert_return(memfd >= 0, -EINVAL);
+ assert_return(size > 0, -EINVAL);
assert_return(!m->sealed, -EPERM);
assert_return(!m->poisoned, -ESTALE);
@@ -2635,10 +2668,15 @@ _public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd) {
if (copy_fd < 0)
return copy_fd;
- r = memfd_get_size(memfd, &size);
+ r = memfd_get_size(memfd, &real_size);
if (r < 0)
return r;
+ if (offset == 0 && size == (uint64_t) -1)
+ size = real_size;
+ else if (offset + size > real_size)
+ return -EMSGSIZE;
+
/* We require this to be NUL terminated */
if (size == 0)
return -EINVAL;
@@ -2679,6 +2717,7 @@ _public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd) {
return -ENOMEM;
part->memfd = copy_fd;
+ part->memfd_offset = offset;
part->sealed = true;
part->size = size;
copy_fd = -1;
@@ -2820,11 +2859,12 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
/* Then, sync up real memfd size */
sz = part->size;
- if (ftruncate(part->memfd, sz) < 0)
- return -errno;
+ r = memfd_set_size(part->memfd, sz);
+ if (r < 0)
+ return r;
/* Finally, try to seal */
- if (fcntl(part->memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) >= 0)
+ if (memfd_set_sealed(part->memfd) >= 0)
part->sealed = true;
}
}
@@ -2841,7 +2881,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
int bus_body_part_map(struct bus_body_part *part) {
void *p;
- size_t psz;
+ size_t psz, shift;
assert_se(part);
@@ -2858,10 +2898,11 @@ int bus_body_part_map(struct bus_body_part *part) {
return 0;
}
- psz = PAGE_ALIGN(part->size);
+ shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
+ psz = PAGE_ALIGN(part->size + shift);
if (part->memfd >= 0)
- p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, 0);
+ p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift);
else if (part->is_zero)
p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
else
@@ -2871,7 +2912,8 @@ int bus_body_part_map(struct bus_body_part *part) {
return -errno;
part->mapped = psz;
- part->data = p;
+ part->mmap_begin = p;
+ part->data = (uint8_t*) p + shift;
part->munmap_this = true;
return 0;
@@ -2884,14 +2926,15 @@ void bus_body_part_unmap(struct bus_body_part *part) {
if (part->memfd < 0)
return;
- if (!part->data)
+ if (!part->mmap_begin)
return;
if (!part->munmap_this)
return;
- assert_se(munmap(part->data, part->mapped) == 0);
+ assert_se(munmap(part->mmap_begin, part->mapped) == 0);
+ part->mmap_begin = NULL;
part->data = NULL;
part->mapped = 0;
part->munmap_this = false;
@@ -4434,13 +4477,32 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
assert_return(m, -EINVAL);
assert_return(m->sealed, -EPERM);
- assert_return(types, -EINVAL);
- if (isempty(types))
- return 0;
+ /* If types is NULL, read exactly one element */
+ if (!types) {
+ struct bus_container *c;
+ size_t l;
+
+ if (message_end_of_signature(m))
+ return -ENXIO;
+
+ if (message_end_of_array(m, m->rindex))
+ return 0;
+
+ c = message_get_container(m);
+
+ r = signature_element_length(c->signature + c->index, &l);
+ if (r < 0)
+ return r;
+
+ types = strndupa(c->signature + c->index, l);
+ }
switch (*types) {
+ case 0: /* Nothing to drop */
+ return 0;
+
case SD_BUS_TYPE_BYTE:
case SD_BUS_TYPE_BOOLEAN:
case SD_BUS_TYPE_INT16:
@@ -5154,6 +5216,10 @@ int bus_message_parse_fields(sd_bus_message *m) {
case SD_BUS_MESSAGE_SIGNAL:
if (!m->path || !m->interface || !m->member)
return -EBADMSG;
+
+ if (m->reply_cookie != 0)
+ return -EBADMSG;
+
break;
case SD_BUS_MESSAGE_METHOD_CALL:
@@ -5161,6 +5227,9 @@ int bus_message_parse_fields(sd_bus_message *m) {
if (!m->path || !m->member)
return -EBADMSG;
+ if (m->reply_cookie != 0)
+ return -EBADMSG;
+
break;
case SD_BUS_MESSAGE_METHOD_RETURN:
@@ -5291,35 +5360,57 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
return 1;
}
-const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
- int r;
- const char *t = NULL;
+int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) {
+ const char *contents;
unsigned j;
+ char type;
+ int r;
assert(m);
+ assert(str);
+ assert(strv);
r = sd_bus_message_rewind(m, true);
if (r < 0)
- return NULL;
+ return r;
- for (j = 0; j <= i; j++) {
- char type;
+ for (j = 0;; j++) {
+ r = sd_bus_message_peek_type(m, &type, &contents);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENXIO;
+
+ /* Don't match against arguments after the first one we don't understand */
+ if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
+ !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
+ return -ENXIO;
- r = sd_bus_message_peek_type(m, &type, NULL);
+ if (j >= i)
+ break;
+
+ r = sd_bus_message_skip(m, NULL);
if (r < 0)
- return NULL;
+ return r;
+ }
- if (type != SD_BUS_TYPE_STRING &&
- type != SD_BUS_TYPE_OBJECT_PATH &&
- type != SD_BUS_TYPE_SIGNATURE)
- return NULL;
+ if (type == SD_BUS_TYPE_ARRAY) {
- r = sd_bus_message_read_basic(m, type, &t);
+ r = sd_bus_message_read_strv(m, strv);
if (r < 0)
- return NULL;
+ return r;
+
+ *str = NULL;
+
+ } else {
+ r = sd_bus_message_read_basic(m, type, str);
+ if (r < 0)
+ return r;
+
+ *strv = NULL;
}
- return t;
+ return 0;
}
bool bus_header_is_complete(struct bus_header *h, size_t size) {
@@ -5374,6 +5465,18 @@ _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complet
return strempty(c->signature);
}
+_public_ int sd_bus_message_is_empty(sd_bus_message *m) {
+ assert_return(m, -EINVAL);
+
+ return isempty(m->root_container.signature);
+}
+
+_public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
+ assert_return(m, -EINVAL);
+
+ return streq(strempty(m->root_container.signature), strempty(signature));
+}
+
_public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
bool done_something = false;
int r;
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index df792945b0..4dd280dcf0 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -52,26 +52,14 @@ struct bus_container {
char *peeked_signature;
};
-struct bus_header {
- uint8_t endian;
- uint8_t type;
- uint8_t flags;
- uint8_t version;
- uint32_t body_size;
-
- /* Note that what the bus spec calls "serial" we'll call
- "cookie" instead, because we don't want to imply that the
- cookie was in any way monotonically increasing. */
- uint32_t serial;
- uint32_t fields_size;
-} _packed_;
-
struct bus_body_part {
struct bus_body_part *next;
void *data;
+ void *mmap_begin;
size_t size;
size_t mapped;
size_t allocated;
+ uint64_t memfd_offset;
int memfd;
bool free_this:1;
bool munmap_this:1;
@@ -100,6 +88,7 @@ struct sd_bus_message {
usec_t realtime;
uint64_t seqnum;
int64_t priority;
+ uint64_t verify_destination_id;
bool sealed:1;
bool dont_send:1;
@@ -143,6 +132,7 @@ struct sd_bus_message {
char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
+ char *destination_ptr;
size_t header_offsets[_BUS_MESSAGE_HEADER_MAX];
unsigned n_header_offsets;
@@ -221,7 +211,7 @@ int bus_message_from_malloc(
const char *label,
sd_bus_message **ret);
-const char* bus_message_get_arg(sd_bus_message *m, unsigned i);
+int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv);
int bus_message_append_ap(sd_bus_message *m, const char *types, va_list ap);
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 0ab1119b58..6162d12c1d 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -617,6 +617,9 @@ static int property_get_set_callbacks_run(
return r;
} else {
+ const char *signature = NULL;
+ char type = 0;
+
if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY)
return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member);
@@ -628,6 +631,13 @@ static int property_get_set_callbacks_run(
c->last_iteration = bus->iteration_counter;
+ r = sd_bus_message_peek_type(m, &type, &signature);
+ if (r < 0)
+ return r;
+
+ if (type != 'v' || !streq(strempty(signature), strempty(c->vtable->x.property.signature)))
+ return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Incorrect parameters for property '%s', expected '%s', got '%s'.", c->member, strempty(c->vtable->x.property.signature), strempty(signature));
+
r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature);
if (r < 0)
return r;
@@ -1682,6 +1692,11 @@ static int add_object_vtable_internal(
goto fail;
}
+ if (v->flags & SD_BUS_VTABLE_PROPERTY_CONST) {
+ r = -EINVAL;
+ goto fail;
+ }
+
/* Fall through */
case _SD_BUS_VTABLE_PROPERTY: {
diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h
index 75c6ded728..6431dfbff8 100644
--- a/src/libsystemd/sd-bus/bus-protocol.h
+++ b/src/libsystemd/sd-bus/bus-protocol.h
@@ -23,6 +23,22 @@
#include <endian.h>
+/* Packet header */
+
+struct bus_header {
+ uint8_t endian;
+ uint8_t type;
+ uint8_t flags;
+ uint8_t version;
+ uint32_t body_size;
+
+ /* Note that what the bus spec calls "serial" we'll call
+ "cookie" instead, because we don't want to imply that the
+ cookie was in any way monotonically increasing. */
+ uint32_t serial;
+ uint32_t fields_size;
+} _packed_;
+
/* Endianness */
enum {
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index 568a6ed60c..8060e9882c 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -208,6 +208,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
}
bus_slot_disconnect(slot);
+ free(slot->description);
free(slot);
return NULL;
@@ -265,3 +266,18 @@ _public_ void* sd_bus_slot_get_current_userdata(sd_bus_slot *slot) {
return slot->bus->current_userdata;
}
+
+_public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description) {
+ assert_return(slot, -EINVAL);
+
+ return free_and_strdup(&slot->description, description);
+}
+
+_public_ int sd_bus_slot_get_description(sd_bus_slot *slot, char **description) {
+ assert_return(slot, -EINVAL);
+ assert_return(description, -EINVAL);
+ assert_return(slot->description, -ENXIO);
+
+ *description = slot->description;
+ return 0;
+}
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index d124d9aa13..d02994e283 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -610,10 +610,10 @@ void bus_socket_setup(sd_bus *b) {
/* Enable SO_PASSCRED + SO_PASSEC. We try this on any
* socket, just in case. */
enable = !b->bus_client;
- setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
+ (void)setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
enable = !b->bus_client && (b->attach_flags & KDBUS_ATTACH_SECLABEL);
- setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
+ (void)setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable));
/* Increase the buffers to 8 MB */
fd_inc_rcvbuf(b->input_fd, SNDBUF_SIZE);
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index f3b593d2b8..6be8310bbe 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -309,7 +309,7 @@ void bus_track_dispatch(sd_bus_track *track) {
r = track->handler(track, track->userdata);
if (r < 0)
- log_debug("Failed to process track handler: %s", strerror(-r));
+ log_debug_errno(r, "Failed to process track handler: %m");
else if (r == 0)
bus_track_add_to_queue(track);
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index 43acf5b959..0f1a89c8e1 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -521,7 +521,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
if (r < 0)
return r;
- r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_PATH);
+ r = sd_bus_set_address(bus, KERNEL_SYSTEM_BUS_ADDRESS);
if (r < 0)
return r;
@@ -574,7 +574,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
if (r < 0)
return r;
- if (asprintf(&bus->address, KERNEL_USER_BUS_FMT, getuid()) < 0)
+ if (asprintf(&bus->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid()) < 0)
return -ENOMEM;
bus->bus_client = true;
@@ -640,8 +640,15 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- if (all || !isempty(s))
- printf("%s=%s\n", name, s);
+ if (all || !isempty(s)) {
+ _cleanup_free_ char *escaped = NULL;
+
+ escaped = xescape(s, "\n");
+ if (!escaped)
+ return -ENOMEM;
+
+ printf("%s=%s\n", name, escaped);
+ }
return 1;
}
@@ -732,10 +739,16 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
return r;
while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
+ _cleanup_free_ char *escaped = NULL;
+
if (first)
printf("%s=", name);
- printf("%s%s", first ? "" : " ", str);
+ escaped = xescape(str, "\n ");
+ if (!escaped)
+ return -ENOMEM;
+
+ printf("%s%s", first ? "" : " ", escaped);
first = false;
}
@@ -1250,13 +1263,11 @@ int bus_property_get_ulong(
#endif
int bus_log_parse_error(int r) {
- log_error("Failed to parse bus message: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to parse bus message: %m");
}
int bus_log_create_error(int r) {
- log_error("Failed to create bus message: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to create bus message: %m");
}
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
@@ -1361,7 +1372,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (STR_IN_SET(field,
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
- "SendSIGHUP", "SendSIGKILL")) {
+ "SendSIGHUP", "SendSIGKILL",
+ "WakeSystem")) {
r = parse_boolean(eq);
if (r < 0) {
@@ -1522,6 +1534,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", sig);
+ } else if (streq(field, "AccuracySec")) {
+ usec_t u;
+
+ r = parse_sec(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", u);
+
} else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c
new file mode 100644
index 0000000000..15c10da7e9
--- /dev/null
+++ b/src/libsystemd/sd-bus/busctl-introspect.c
@@ -0,0 +1,793 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "util.h"
+#include "xml.h"
+#include "sd-bus-vtable.h"
+
+#include "busctl-introspect.h"
+
+#define NODE_DEPTH_MAX 16
+
+typedef struct Context {
+ const XMLIntrospectOps *ops;
+ void *userdata;
+
+ char *interface_name;
+ uint64_t interface_flags;
+
+ char *member_name;
+ char *member_signature;
+ char *member_result;
+ uint64_t member_flags;
+ bool member_writable;
+
+ const char *current;
+ void *xml_state;
+} Context;
+
+static void context_reset_member(Context *c) {
+ free(c->member_name);
+ free(c->member_signature);
+ free(c->member_result);
+
+ c->member_name = c->member_signature = c->member_result = NULL;
+ c->member_flags = 0;
+ c->member_writable = false;
+}
+
+static void context_reset_interface(Context *c) {
+ free(c->interface_name);
+ c->interface_name = NULL;
+ c->interface_flags = 0;
+
+ context_reset_member(c);
+}
+
+static int parse_xml_annotation(Context *context, uint64_t *flags) {
+
+ enum {
+ STATE_ANNOTATION,
+ STATE_NAME,
+ STATE_VALUE
+ } state = STATE_ANNOTATION;
+
+ _cleanup_free_ char *field = NULL, *value = NULL;
+
+ assert(context);
+
+ for (;;) {
+ _cleanup_free_ char *name = NULL;
+
+ int t;
+
+ t = xml_tokenize(&context->current, &name, &context->xml_state, NULL);
+ if (t < 0) {
+ log_error("XML parse error.");
+ return t;
+ }
+
+ if (t == XML_END) {
+ log_error("Premature end of XML data.");
+ return -EBADMSG;
+ }
+
+ switch (state) {
+
+ case STATE_ANNOTATION:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+
+ if (streq_ptr(name, "name"))
+ state = STATE_NAME;
+
+ else if (streq_ptr(name, "value"))
+ state = STATE_VALUE;
+
+ else {
+ log_error("Unexpected <annotation> attribute %s.", name);
+ return -EBADMSG;
+ }
+
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "annotation"))) {
+
+ if (flags) {
+ if (streq_ptr(field, "org.freedesktop.DBus.Deprecated")) {
+
+ if (streq_ptr(value, "true"))
+ *flags |= SD_BUS_VTABLE_DEPRECATED;
+
+ } else if (streq_ptr(field, "org.freedesktop.DBus.Method.NoReply")) {
+
+ if (streq_ptr(value, "true"))
+ *flags |= SD_BUS_VTABLE_METHOD_NO_REPLY;
+
+ } else if (streq_ptr(field, "org.freedesktop.DBus.Property.EmitsChangedSignal")) {
+
+ if (streq_ptr(value, "const"))
+ *flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE)) | SD_BUS_VTABLE_PROPERTY_CONST;
+ else if (streq_ptr(value, "invalidates"))
+ *flags = (*flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST)) | SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION;
+ else if (streq_ptr(value, "false"))
+ *flags = *flags & ~(SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION);
+ }
+ }
+
+ return 0;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <annotation>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free(field);
+ field = name;
+ name = NULL;
+
+ state = STATE_ANNOTATION;
+ } else {
+ log_error("Unexpected token in <annotation>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_VALUE:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free(value);
+ value = name;
+ name = NULL;
+
+ state = STATE_ANNOTATION;
+ } else {
+ log_error("Unexpected token in <annotation>. (3)");
+ return -EINVAL;
+ }
+
+ break;
+
+ default:
+ assert_not_reached("Bad state");
+ }
+ }
+}
+
+static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth) {
+
+ enum {
+ STATE_NODE,
+ STATE_NODE_NAME,
+ STATE_INTERFACE,
+ STATE_INTERFACE_NAME,
+ STATE_METHOD,
+ STATE_METHOD_NAME,
+ STATE_METHOD_ARG,
+ STATE_METHOD_ARG_NAME,
+ STATE_METHOD_ARG_TYPE,
+ STATE_METHOD_ARG_DIRECTION,
+ STATE_SIGNAL,
+ STATE_SIGNAL_NAME,
+ STATE_SIGNAL_ARG,
+ STATE_SIGNAL_ARG_NAME,
+ STATE_SIGNAL_ARG_TYPE,
+ STATE_PROPERTY,
+ STATE_PROPERTY_NAME,
+ STATE_PROPERTY_TYPE,
+ STATE_PROPERTY_ACCESS,
+ } state = STATE_NODE;
+
+ _cleanup_free_ char *node_path = NULL, *argument_type = NULL, *argument_direction = NULL;
+ const char *np = prefix;
+ int r;
+
+ assert(context);
+ assert(prefix);
+
+ if (n_depth > NODE_DEPTH_MAX) {
+ log_error("<node> depth too high.");
+ return -EINVAL;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *name = NULL;
+ int t;
+
+ t = xml_tokenize(&context->current, &name, &context->xml_state, NULL);
+ if (t < 0) {
+ log_error("XML parse error.");
+ return t;
+ }
+
+ if (t == XML_END) {
+ log_error("Premature end of XML data.");
+ return -EBADMSG;
+ }
+
+ switch (state) {
+
+ case STATE_NODE:
+ if (t == XML_ATTRIBUTE_NAME) {
+
+ if (streq_ptr(name, "name"))
+ state = STATE_NODE_NAME;
+ else {
+ log_error("Unexpected <node> attribute %s.", name);
+ return -EBADMSG;
+ }
+
+ } else if (t == XML_TAG_OPEN) {
+
+ if (streq_ptr(name, "interface"))
+ state = STATE_INTERFACE;
+ else if (streq_ptr(name, "node")) {
+
+ r = parse_xml_node(context, np, n_depth+1);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected <node> tag %s.", name);
+ return -EBADMSG;
+ }
+
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "node"))) {
+
+ if (context->ops->on_path) {
+ r = context->ops->on_path(node_path ? node_path : np, context->userdata);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <node>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_NODE_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ free(node_path);
+
+ if (name[0] == '/') {
+ node_path = name;
+ name = NULL;
+ } else {
+
+ if (endswith(prefix, "/"))
+ node_path = strappend(prefix, name);
+ else
+ node_path = strjoin(prefix, "/", name, NULL);
+ if (!node_path)
+ return log_oom();
+ }
+
+ np = node_path;
+ state = STATE_NODE;
+ } else {
+ log_error("Unexpected token in <node>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_INTERFACE:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_INTERFACE_NAME;
+ else {
+ log_error("Unexpected <interface> attribute %s.", name);
+ return -EBADMSG;
+ }
+
+ } else if (t == XML_TAG_OPEN) {
+ if (streq_ptr(name, "method"))
+ state = STATE_METHOD;
+ else if (streq_ptr(name, "signal"))
+ state = STATE_SIGNAL;
+ else if (streq_ptr(name, "property")) {
+ context->member_flags |= SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE;
+ state = STATE_PROPERTY;
+ } else if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, &context->interface_flags);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected <interface> tag %s.", name);
+ return -EINVAL;
+ }
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "interface"))) {
+
+ if (n_depth == 0) {
+ if (context->ops->on_interface) {
+ r = context->ops->on_interface(context->interface_name, context->interface_flags, context->userdata);
+ if (r < 0)
+ return r;
+ }
+
+ context_reset_interface(context);
+ }
+
+ state = STATE_NODE;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <interface>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_INTERFACE_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ if (n_depth == 0) {
+ free(context->interface_name);
+ context->interface_name = name;
+ name = NULL;
+ }
+
+ state = STATE_INTERFACE;
+ } else {
+ log_error("Unexpected token in <interface>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_METHOD_NAME;
+ else {
+ log_error("Unexpected <method> attribute %s", name);
+ return -EBADMSG;
+ }
+ } else if (t == XML_TAG_OPEN) {
+ if (streq_ptr(name, "arg"))
+ state = STATE_METHOD_ARG;
+ else if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, &context->member_flags);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected <method> tag %s.", name);
+ return -EINVAL;
+ }
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "method"))) {
+
+ if (n_depth == 0) {
+ if (context->ops->on_method) {
+ r = context->ops->on_method(context->interface_name, context->member_name, context->member_signature, context->member_result, context->member_flags, context->userdata);
+ if (r < 0)
+ return r;
+ }
+
+ context_reset_member(context);
+ }
+
+ state = STATE_INTERFACE;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <method> (1).");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ if (n_depth == 0) {
+ free(context->member_name);
+ context->member_name = name;
+ name = NULL;
+ }
+
+ state = STATE_METHOD;
+ } else {
+ log_error("Unexpected token in <method> (2).");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD_ARG:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_METHOD_ARG_NAME;
+ else if (streq_ptr(name, "type"))
+ state = STATE_METHOD_ARG_TYPE;
+ else if (streq_ptr(name, "direction"))
+ state = STATE_METHOD_ARG_DIRECTION;
+ else {
+ log_error("Unexpected method <arg> attribute %s.", name);
+ return -EBADMSG;
+ }
+ } else if (t == XML_TAG_OPEN) {
+ if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, NULL);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected method <arg> tag %s.", name);
+ return -EINVAL;
+ }
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "arg"))) {
+
+ if (n_depth == 0) {
+
+ if (argument_type) {
+ if (!argument_direction || streq(argument_direction, "in")) {
+ if (!strextend(&context->member_signature, argument_type, NULL))
+ return log_oom();
+ } else if (streq(argument_direction, "out")) {
+ if (!strextend(&context->member_result, argument_type, NULL))
+ return log_oom();
+ }
+ }
+
+ free(argument_type);
+ free(argument_direction);
+ argument_type = argument_direction = NULL;
+ }
+
+ state = STATE_METHOD;
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in method <arg>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD_ARG_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE)
+ state = STATE_METHOD_ARG;
+ else {
+ log_error("Unexpected token in method <arg>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD_ARG_TYPE:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free(argument_type);
+ argument_type = name;
+ name = NULL;
+
+ state = STATE_METHOD_ARG;
+ } else {
+ log_error("Unexpected token in method <arg>. (3)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_METHOD_ARG_DIRECTION:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free(argument_direction);
+ argument_direction = name;
+ name = NULL;
+
+ state = STATE_METHOD_ARG;
+ } else {
+ log_error("Unexpected token in method <arg>. (4)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_SIGNAL:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_SIGNAL_NAME;
+ else {
+ log_error("Unexpected <signal> attribute %s.", name);
+ return -EBADMSG;
+ }
+ } else if (t == XML_TAG_OPEN) {
+ if (streq_ptr(name, "arg"))
+ state = STATE_SIGNAL_ARG;
+ else if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, &context->member_flags);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected <signal> tag %s.", name);
+ return -EINVAL;
+ }
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "signal"))) {
+
+ if (n_depth == 0) {
+ if (context->ops->on_signal) {
+ r = context->ops->on_signal(context->interface_name, context->member_name, context->member_signature, context->member_flags, context->userdata);
+ if (r < 0)
+ return r;
+ }
+
+ context_reset_member(context);
+ }
+
+ state = STATE_INTERFACE;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <signal>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_SIGNAL_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ if (n_depth == 0) {
+ free(context->member_name);
+ context->member_name = name;
+ name = NULL;
+ }
+
+ state = STATE_SIGNAL;
+ } else {
+ log_error("Unexpected token in <signal>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+
+ case STATE_SIGNAL_ARG:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_SIGNAL_ARG_NAME;
+ else if (streq_ptr(name, "type"))
+ state = STATE_SIGNAL_ARG_TYPE;
+ else {
+ log_error("Unexpected signal <arg> attribute %s.", name);
+ return -EBADMSG;
+ }
+ } else if (t == XML_TAG_OPEN) {
+ if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, NULL);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected signal <arg> tag %s.", name);
+ return -EINVAL;
+ }
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "arg"))) {
+
+ if (argument_type) {
+ if (!strextend(&context->member_signature, argument_type, NULL))
+ return log_oom();
+
+ free(argument_type);
+ argument_type = NULL;
+ }
+
+ state = STATE_SIGNAL;
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in signal <arg> (1).");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_SIGNAL_ARG_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE)
+ state = STATE_SIGNAL_ARG;
+ else {
+ log_error("Unexpected token in signal <arg> (2).");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_SIGNAL_ARG_TYPE:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+ free(argument_type);
+ argument_type = name;
+ name = NULL;
+
+ state = STATE_SIGNAL_ARG;
+ } else {
+ log_error("Unexpected token in signal <arg> (3).");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_PROPERTY:
+
+ if (t == XML_ATTRIBUTE_NAME) {
+ if (streq_ptr(name, "name"))
+ state = STATE_PROPERTY_NAME;
+ else if (streq_ptr(name, "type"))
+ state = STATE_PROPERTY_TYPE;
+ else if (streq_ptr(name, "access"))
+ state = STATE_PROPERTY_ACCESS;
+ else {
+ log_error("Unexpected <property> attribute %s.", name);
+ return -EBADMSG;
+ }
+ } else if (t == XML_TAG_OPEN) {
+
+ if (streq_ptr(name, "annotation")) {
+ r = parse_xml_annotation(context, &context->member_flags);
+ if (r < 0)
+ return r;
+ } else {
+ log_error("Unexpected <property> tag %s.", name);
+ return -EINVAL;
+ }
+
+ } else if (t == XML_TAG_CLOSE_EMPTY ||
+ (t == XML_TAG_CLOSE && streq_ptr(name, "property"))) {
+
+ if (n_depth == 0) {
+ if (context->ops->on_property) {
+ r = context->ops->on_property(context->interface_name, context->member_name, context->member_signature, context->member_writable, context->member_flags, context->userdata);
+ if (r < 0)
+ return r;
+ }
+
+ context_reset_member(context);
+ }
+
+ state = STATE_INTERFACE;
+
+ } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token in <property>. (1)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_PROPERTY_NAME:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ if (n_depth == 0) {
+ free(context->member_name);
+ context->member_name = name;
+ name = NULL;
+ }
+ state = STATE_PROPERTY;
+ } else {
+ log_error("Unexpected token in <property>. (2)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_PROPERTY_TYPE:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ if (n_depth == 0) {
+ free(context->member_signature);
+ context->member_signature = name;
+ name = NULL;
+ }
+
+ state = STATE_PROPERTY;
+ } else {
+ log_error("Unexpected token in <property>. (3)");
+ return -EINVAL;
+ }
+
+ break;
+
+ case STATE_PROPERTY_ACCESS:
+
+ if (t == XML_ATTRIBUTE_VALUE) {
+
+ if (streq(name, "readwrite") || streq(name, "write"))
+ context->member_writable = true;
+
+ state = STATE_PROPERTY;
+ } else {
+ log_error("Unexpected token in <property>. (4)");
+ return -EINVAL;
+ }
+
+ break;
+ }
+ }
+}
+
+int parse_xml_introspect(const char *prefix, const char *xml, const XMLIntrospectOps *ops, void *userdata) {
+ Context context = {
+ .ops = ops,
+ .userdata = userdata,
+ .current = xml,
+ };
+
+ int r;
+
+ assert(prefix);
+ assert(xml);
+ assert(ops);
+
+ for (;;) {
+ _cleanup_free_ char *name = NULL;
+
+ r = xml_tokenize(&context.current, &name, &context.xml_state, NULL);
+ if (r < 0) {
+ log_error("XML parse error");
+ goto finish;
+ }
+
+ if (r == XML_END) {
+ r = 0;
+ break;
+ }
+
+ if (r == XML_TAG_OPEN) {
+
+ if (streq(name, "node")) {
+ r = parse_xml_node(&context, prefix, 0);
+ if (r < 0)
+ goto finish;
+ } else {
+ log_error("Unexpected tag '%s' in introspection data.", name);
+ r = -EBADMSG;
+ goto finish;
+ }
+ } else if (r != XML_TEXT || !in_charset(name, WHITESPACE)) {
+ log_error("Unexpected token.");
+ r = -EBADMSG;
+ goto finish;
+ }
+ }
+
+finish:
+ context_reset_interface(&context);
+
+ return r;
+}
diff --git a/src/libsystemd/sd-bus/busctl-introspect.h b/src/libsystemd/sd-bus/busctl-introspect.h
new file mode 100644
index 0000000000..9bea43717d
--- /dev/null
+++ b/src/libsystemd/sd-bus/busctl-introspect.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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>
+
+typedef struct XMLIntrospectOps {
+ int (*on_path)(const char *path, void *userdata);
+ int (*on_interface)(const char *name, uint64_t flags, void *userdata);
+ int (*on_method)(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata);
+ int (*on_signal)(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata);
+ int (*on_property)(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata);
+} XMLIntrospectOps;
+
+int parse_xml_introspect(const char *prefix, const char *xml, const XMLIntrospectOps *ops, void *userdata);
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index fdc275ce46..dd6ae865b6 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -26,12 +26,17 @@
#include "log.h"
#include "build.h"
#include "pager.h"
+#include "xml.h"
+#include "path-util.h"
#include "sd-bus.h"
#include "bus-message.h"
#include "bus-internal.h"
#include "bus-util.h"
#include "bus-dump.h"
+#include "bus-signature.h"
+#include "bus-type.h"
+#include "busctl-introspect.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -44,6 +49,15 @@ static char **arg_matches = NULL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static char *arg_host = NULL;
static bool arg_user = false;
+static size_t arg_snaplen = 4096;
+static bool arg_list = false;
+static bool arg_quiet = false;
+static bool arg_verbose = false;
+static bool arg_expect_reply = true;
+static bool arg_auto_start = true;
+static bool arg_allow_interactive_authorization = true;
+static bool arg_augment_creds = true;
+static usec_t arg_timeout = 0;
static void pager_open_if_enabled(void) {
@@ -54,6 +68,9 @@ static void pager_open_if_enabled(void) {
pager_open(false);
}
+#define NAME_IS_ACQUIRED INT_TO_PTR(1)
+#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
+
static int list_bus_names(sd_bus *bus, char **argv) {
_cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
_cleanup_free_ char **merged = NULL;
@@ -68,11 +85,12 @@ static int list_bus_names(sd_bus *bus, char **argv) {
assert(bus);
+ if (!arg_unique && !arg_acquired && !arg_activatable)
+ arg_unique = arg_acquired = arg_activatable = true;
+
r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
- if (r < 0) {
- log_error("Failed to list names: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list names: %m");
pager_open_if_enabled();
@@ -83,21 +101,17 @@ static int list_bus_names(sd_bus *bus, char **argv) {
STRV_FOREACH(i, acquired) {
max_i = MAX(max_i, strlen(*i));
- r = hashmap_put(names, *i, INT_TO_PTR(1));
- if (r < 0) {
- log_error("Failed to add to hashmap: %s", strerror(-r));
- return r;
- }
+ r = hashmap_put(names, *i, NAME_IS_ACQUIRED);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add to hashmap: %m");
}
STRV_FOREACH(i, activatable) {
max_i = MAX(max_i, strlen(*i));
- r = hashmap_put(names, *i, INT_TO_PTR(2));
- if (r < 0 && r != -EEXIST) {
- log_error("Failed to add to hashmap: %s", strerror(-r));
- return r;
- }
+ r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE);
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Failed to add to hashmap: %m");
}
merged = new(char*, hashmap_size(names) + 1);
@@ -109,7 +123,7 @@ static int list_bus_names(sd_bus *bus, char **argv) {
if (arg_legend) {
printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
- (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "CONNECTION-NAME");
+ (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "DESCRIPTION");
if (arg_show_machine)
puts(" MACHINE");
@@ -121,7 +135,7 @@ static int list_bus_names(sd_bus *bus, char **argv) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
sd_id128_t mid;
- if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
+ if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) {
/* Activatable */
printf("%-*s", (int) max_i, *i);
@@ -142,10 +156,12 @@ static int list_bus_names(sd_bus *bus, char **argv) {
printf("%-*s", (int) max_i, *i);
- r = sd_bus_get_name_creds(bus, *i,
- SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
- SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
- SD_BUS_CREDS_CONNECTION_NAME, &creds);
+ r = sd_bus_get_name_creds(
+ bus, *i,
+ (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) |
+ SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
+ SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
+ SD_BUS_CREDS_DESCRIPTION, &creds);
if (r >= 0) {
const char *unique, *session, *unit, *cn;
pid_t pid;
@@ -200,7 +216,7 @@ static int list_bus_names(sd_bus *bus, char **argv) {
else
fputs(" - ", stdout);
- r = sd_bus_creds_get_connection_name(creds, &cn);
+ r = sd_bus_creds_get_description(creds, &cn);
if (r >= 0)
printf(" %-19s", cn);
else
@@ -223,7 +239,838 @@ static int list_bus_names(sd_bus *bus, char **argv) {
return 0;
}
-static int monitor(sd_bus *bus, char *argv[]) {
+static void print_subtree(const char *prefix, const char *path, char **l) {
+ const char *vertical, *space;
+ char **n;
+
+ /* We assume the list is sorted. Let's first skip over the
+ * entry we are looking at. */
+ for (;;) {
+ if (!*l)
+ return;
+
+ if (!streq(*l, path))
+ break;
+
+ l++;
+ }
+
+ vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL));
+ space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE));
+
+ for (;;) {
+ bool has_more = false;
+
+ if (!*l || !path_startswith(*l, path))
+ break;
+
+ n = l + 1;
+ for (;;) {
+ if (!*n || !path_startswith(*n, path))
+ break;
+
+ if (!path_startswith(*n, *l)) {
+ has_more = true;
+ break;
+ }
+
+ n++;
+ }
+
+ printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
+
+ print_subtree(has_more ? vertical : space, *l, l);
+ l = n;
+ }
+}
+
+static void print_tree(const char *prefix, char **l) {
+
+ pager_open_if_enabled();
+
+ prefix = strempty(prefix);
+
+ if (arg_list) {
+ char **i;
+
+ STRV_FOREACH(i, l)
+ printf("%s%s\n", prefix, *i);
+ return;
+ }
+
+ if (strv_isempty(l)) {
+ printf("No objects discovered.\n");
+ return;
+ }
+
+ if (streq(l[0], "/") && !l[1]) {
+ printf("Only root object discovered.\n");
+ return;
+ }
+
+ print_subtree(prefix, "/", l);
+}
+
+static int on_path(const char *path, void *userdata) {
+ Set *paths = userdata;
+ int r;
+
+ assert(paths);
+
+ r = set_put_strdup(paths, path);
+ if (r < 0)
+ return log_oom();
+
+ return 0;
+}
+
+static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *paths, bool many) {
+ static const XMLIntrospectOps ops = {
+ .on_path = on_path,
+ };
+
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *xml;
+ int r;
+
+ r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+ if (r < 0) {
+ if (many)
+ printf("Failed to introspect object %s of service %s: %s\n", path, service, bus_error_message(&error, r));
+ else
+ log_error("Failed to introspect object %s of service %s: %s", path, service, bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_read(reply, "s", &xml);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return parse_xml_introspect(path, xml, &ops, paths);
+}
+
+static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool many) {
+ _cleanup_set_free_free_ Set *paths = NULL, *done = NULL, *failed = NULL;
+ _cleanup_free_ char **l = NULL;
+ char *m;
+ int r;
+
+ paths = set_new(&string_hash_ops);
+ if (!paths)
+ return log_oom();
+
+ done = set_new(&string_hash_ops);
+ if (!done)
+ return log_oom();
+
+ failed = set_new(&string_hash_ops);
+ if (!failed)
+ return log_oom();
+
+ m = strdup("/");
+ if (!m)
+ return log_oom();
+
+ r = set_put(paths, m);
+ if (r < 0) {
+ free(m);
+ return log_oom();
+ }
+
+ for (;;) {
+ _cleanup_free_ char *p = NULL;
+ int q;
+
+ p = set_steal_first(paths);
+ if (!p)
+ break;
+
+ if (set_contains(done, p) ||
+ set_contains(failed, p))
+ continue;
+
+ q = find_nodes(bus, service, p, paths, many);
+ if (q < 0) {
+ if (r >= 0)
+ r = q;
+
+ q = set_put(failed, p);
+ } else
+ q = set_put(done, p);
+
+ if (q < 0)
+ return log_oom();
+
+ assert(q != 0);
+ p = NULL;
+ }
+
+ pager_open_if_enabled();
+
+ l = set_get_strv(done);
+ if (!l)
+ return log_oom();
+
+ strv_sort(l);
+ print_tree(prefix, l);
+
+ fflush(stdout);
+
+ return r;
+}
+
+static int tree(sd_bus *bus, char **argv) {
+ char **i;
+ int r = 0;
+
+ if (!arg_unique && !arg_acquired)
+ arg_acquired = true;
+
+ if (strv_length(argv) <= 1) {
+ _cleanup_strv_free_ char **names = NULL;
+ bool not_first = false;
+
+ r = sd_bus_list_names(bus, &names, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get name list: %m");
+
+ pager_open_if_enabled();
+
+ STRV_FOREACH(i, names) {
+ int q;
+
+ if (!arg_unique && (*i)[0] == ':')
+ continue;
+
+ if (!arg_acquired && (*i)[0] == ':')
+ continue;
+
+ if (not_first)
+ printf("\n");
+
+ printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
+
+ q = tree_one(bus, *i, NULL, true);
+ if (q < 0 && r >= 0)
+ r = q;
+
+ not_first = true;
+ }
+ } else {
+ STRV_FOREACH(i, argv+1) {
+ int q;
+
+ if (i > argv+1)
+ printf("\n");
+
+ if (argv[2]) {
+ pager_open_if_enabled();
+ printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
+ }
+
+ q = tree_one(bus, *i, NULL, !!argv[2]);
+ if (q < 0 && r >= 0)
+ r = q;
+ }
+ }
+
+ return r;
+}
+
+static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
+ int r;
+
+ for (;;) {
+ const char *contents = NULL;
+ char type;
+ union {
+ uint8_t u8;
+ uint16_t u16;
+ int16_t s16;
+ uint32_t u32;
+ int32_t s32;
+ uint64_t u64;
+ int64_t s64;
+ double d64;
+ const char *string;
+ int i;
+ } basic;
+
+ r = sd_bus_message_peek_type(m, &type, &contents);
+ if (r <= 0)
+ return r;
+
+ if (bus_type_is_container(type) > 0) {
+
+ r = sd_bus_message_enter_container(m, type, contents);
+ if (r < 0)
+ return r;
+
+ if (type == SD_BUS_TYPE_ARRAY) {
+ unsigned n = 0;
+
+ /* count array entries */
+ for (;;) {
+
+ r = sd_bus_message_skip(m, contents);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ n++;
+ }
+
+ r = sd_bus_message_rewind(m, false);
+ if (r < 0)
+ return r;
+
+ if (needs_space)
+ fputc(' ', f);
+
+ fprintf(f, "%u", n);
+ } else if (type == SD_BUS_TYPE_VARIANT) {
+
+ if (needs_space)
+ fputc(' ', f);
+
+ fprintf(f, "%s", contents);
+ }
+
+ r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+
+ continue;
+ }
+
+ r = sd_bus_message_read_basic(m, type, &basic);
+ if (r < 0)
+ return r;
+
+ if (needs_space)
+ fputc(' ', f);
+
+ switch (type) {
+ case SD_BUS_TYPE_BYTE:
+ fprintf(f, "%u", basic.u8);
+ break;
+
+ case SD_BUS_TYPE_BOOLEAN:
+ fputs(true_false(basic.i), f);
+ break;
+
+ case SD_BUS_TYPE_INT16:
+ fprintf(f, "%i", basic.s16);
+ break;
+
+ case SD_BUS_TYPE_UINT16:
+ fprintf(f, "%u", basic.u16);
+ break;
+
+ case SD_BUS_TYPE_INT32:
+ fprintf(f, "%i", basic.s32);
+ break;
+
+ case SD_BUS_TYPE_UINT32:
+ fprintf(f, "%u", basic.u32);
+ break;
+
+ case SD_BUS_TYPE_INT64:
+ fprintf(f, "%" PRIi64, basic.s64);
+ break;
+
+ case SD_BUS_TYPE_UINT64:
+ fprintf(f, "%" PRIu64, basic.u64);
+ break;
+
+ case SD_BUS_TYPE_DOUBLE:
+ fprintf(f, "%g", basic.d64);
+ break;
+
+ case SD_BUS_TYPE_STRING:
+ case SD_BUS_TYPE_OBJECT_PATH:
+ case SD_BUS_TYPE_SIGNATURE: {
+ _cleanup_free_ char *b = NULL;
+
+ b = cescape(basic.string);
+ if (!b)
+ return -ENOMEM;
+
+ fprintf(f, "\"%s\"", b);
+ break;
+ }
+
+ case SD_BUS_TYPE_UNIX_FD:
+ fprintf(f, "%i", basic.i);
+ break;
+
+ default:
+ assert_not_reached("Unknown basic type.");
+ }
+
+ needs_space = true;
+ }
+}
+
+typedef struct Member {
+ const char *type;
+ char *interface;
+ char *name;
+ char *signature;
+ char *result;
+ char *value;
+ bool writable;
+ uint64_t flags;
+} Member;
+
+static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
+ const Member *m = p;
+ unsigned long ul;
+
+ assert(m);
+ assert(m->type);
+
+ ul = string_hash_func(m->type, hash_key);
+
+ if (m->name)
+ ul ^= string_hash_func(m->name, hash_key);
+
+ if (m->interface)
+ ul ^= string_hash_func(m->interface, hash_key);
+
+ return ul;
+}
+
+static int member_compare_func(const void *a, const void *b) {
+ const Member *x = a, *y = b;
+ int d;
+
+ assert(x);
+ assert(y);
+ assert(x->type);
+ assert(y->type);
+
+ if (!x->interface && y->interface)
+ return -1;
+ if (x->interface && !y->interface)
+ return 1;
+ if (x->interface && y->interface) {
+ d = strcmp(x->interface, y->interface);
+ if (d != 0)
+ return d;
+ }
+
+ d = strcmp(x->type, y->type);
+ if (d != 0)
+ return d;
+
+ if (!x->name && y->name)
+ return -1;
+ if (x->name && !y->name)
+ return 1;
+ if (x->name && y->name)
+ return strcmp(x->name, y->name);
+
+ return 0;
+}
+
+static int member_compare_funcp(const void *a, const void *b) {
+ const Member *const * x = (const Member *const *) a, * const *y = (const Member *const *) b;
+
+ return member_compare_func(*x, *y);
+}
+
+static void member_free(Member *m) {
+ if (!m)
+ return;
+
+ free(m->interface);
+ free(m->name);
+ free(m->signature);
+ free(m->result);
+ free(m->value);
+ free(m);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free);
+
+static void member_set_free(Set *s) {
+ Member *m;
+
+ while ((m = set_steal_first(s)))
+ member_free(m);
+
+ set_free(s);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free);
+
+static int on_interface(const char *interface, uint64_t flags, void *userdata) {
+ _cleanup_(member_freep) Member *m;
+ Set *members = userdata;
+ int r;
+
+ assert(interface);
+ assert(members);
+
+ m = new0(Member, 1);
+ if (!m)
+ return log_oom();
+
+ m->type = "interface";
+ m->flags = flags;
+
+ r = free_and_strdup(&m->interface, interface);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(members, m);
+ if (r <= 0) {
+ log_error("Duplicate interface");
+ return -EINVAL;
+ }
+
+ m = NULL;
+ return 0;
+}
+
+static int on_method(const char *interface, const char *name, const char *signature, const char *result, uint64_t flags, void *userdata) {
+ _cleanup_(member_freep) Member *m;
+ Set *members = userdata;
+ int r;
+
+ assert(interface);
+ assert(name);
+
+ m = new0(Member, 1);
+ if (!m)
+ return log_oom();
+
+ m->type = "method";
+ m->flags = flags;
+
+ r = free_and_strdup(&m->interface, interface);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->name, name);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->signature, signature);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->result, result);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(members, m);
+ if (r <= 0) {
+ log_error("Duplicate method");
+ return -EINVAL;
+ }
+
+ m = NULL;
+ return 0;
+}
+
+static int on_signal(const char *interface, const char *name, const char *signature, uint64_t flags, void *userdata) {
+ _cleanup_(member_freep) Member *m;
+ Set *members = userdata;
+ int r;
+
+ assert(interface);
+ assert(name);
+
+ m = new0(Member, 1);
+ if (!m)
+ return log_oom();
+
+ m->type = "signal";
+ m->flags = flags;
+
+ r = free_and_strdup(&m->interface, interface);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->name, name);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->signature, signature);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(members, m);
+ if (r <= 0) {
+ log_error("Duplicate signal");
+ return -EINVAL;
+ }
+
+ m = NULL;
+ return 0;
+}
+
+static int on_property(const char *interface, const char *name, const char *signature, bool writable, uint64_t flags, void *userdata) {
+ _cleanup_(member_freep) Member *m;
+ Set *members = userdata;
+ int r;
+
+ assert(interface);
+ assert(name);
+
+ m = new0(Member, 1);
+ if (!m)
+ return log_oom();
+
+ m->type = "property";
+ m->flags = flags;
+ m->writable = writable;
+
+ r = free_and_strdup(&m->interface, interface);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->name, name);
+ if (r < 0)
+ return log_oom();
+
+ r = free_and_strdup(&m->signature, signature);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(members, m);
+ if (r <= 0) {
+ log_error("Duplicate property");
+ return -EINVAL;
+ }
+
+ m = NULL;
+ return 0;
+}
+
+static const char *strdash(const char *x) {
+ return isempty(x) ? "-" : x;
+}
+
+static int introspect(sd_bus *bus, char **argv) {
+ static const struct hash_ops member_hash_ops = {
+ .hash = member_hash_func,
+ .compare = member_compare_func,
+ };
+
+ static const XMLIntrospectOps ops = {
+ .on_interface = on_interface,
+ .on_method = on_method,
+ .on_signal = on_signal,
+ .on_property = on_property,
+ };
+
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(member_set_freep) Set *members = NULL;
+ Iterator i;
+ Member *m;
+ const char *xml;
+ int r;
+ unsigned name_width, type_width, signature_width, result_width;
+ Member **sorted = NULL;
+ unsigned k = 0, j;
+
+ if (strv_length(argv) != 3) {
+ log_error("Requires service and object path argument.");
+ return -EINVAL;
+ }
+
+ members = set_new(&member_hash_ops);
+ if (!members)
+ return log_oom();
+
+ r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, "");
+ if (r < 0) {
+ log_error("Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_read(reply, "s", &xml);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ /* First, get list of all properties */
+ r = parse_xml_introspect(argv[2], xml, &ops, members);
+ if (r < 0)
+ return r;
+
+ /* Second, find the current values for them */
+ SET_FOREACH(m, members, i) {
+
+ if (!streq(m->type, "property"))
+ continue;
+
+ if (m->value)
+ continue;
+
+ r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_enter_container(reply, 'a', "{sv}");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ for (;;) {
+ Member *z;
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *mf = NULL;
+ size_t sz = 0;
+ const char *name;
+
+ r = sd_bus_message_enter_container(reply, 'e', "sv");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_read(reply, "s", &name);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_enter_container(reply, 'v', NULL);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ mf = open_memstream(&buf, &sz);
+ if (!mf)
+ return log_oom();
+
+ r = format_cmdline(reply, mf, false);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ fclose(mf);
+ mf = NULL;
+
+ z = set_get(members, &((Member) {
+ .type = "property",
+ .interface = m->interface,
+ .name = (char*) name }));
+ if (z) {
+ free(z->value);
+ z->value = buf;
+ buf = NULL;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
+ pager_open_if_enabled();
+
+ name_width = strlen("NAME");
+ type_width = strlen("TYPE");
+ signature_width = strlen("SIGNATURE");
+ result_width = strlen("RESULT/VALUE");
+
+ sorted = newa(Member*, set_size(members));
+
+ SET_FOREACH(m, members, i) {
+ if (m->interface)
+ name_width = MAX(name_width, strlen(m->interface));
+ if (m->name)
+ name_width = MAX(name_width, strlen(m->name) + 1);
+ if (m->type)
+ type_width = MAX(type_width, strlen(m->type));
+ if (m->signature)
+ signature_width = MAX(signature_width, strlen(m->signature));
+ if (m->result)
+ result_width = MAX(result_width, strlen(m->result));
+ if (m->value)
+ result_width = MAX(result_width, strlen(m->value));
+
+ sorted[k++] = m;
+ }
+
+ if (result_width > 40)
+ result_width = 40;
+
+ assert(k == set_size(members));
+ qsort(sorted, k, sizeof(Member*), member_compare_funcp);
+
+ if (arg_legend) {
+ printf("%-*s %-*s %-*s %-*s %s\n",
+ (int) name_width, "NAME",
+ (int) type_width, "TYPE",
+ (int) signature_width, "SIGNATURE",
+ (int) result_width, "RESULT/VALUE",
+ "FLAGS");
+ }
+
+ for (j = 0; j < k; j++) {
+ _cleanup_free_ char *ellipsized = NULL;
+ const char *rv;
+ bool is_interface;
+
+ m = sorted[j];
+
+ is_interface = streq(m->type, "interface");
+
+ if (m->value) {
+ ellipsized = ellipsize(m->value, result_width, 100);
+ if (!ellipsized)
+ return log_oom();
+
+ rv = ellipsized;
+ } else
+ rv = strdash(m->result);
+
+ printf("%s%s%-*s%s %-*s %-*s %-*s%s%s%s%s%s%s\n",
+ is_interface ? ansi_highlight() : "",
+ is_interface ? "" : ".",
+ - !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
+ is_interface ? ansi_highlight_off() : "",
+ (int) type_width, strdash(m->type),
+ (int) signature_width, strdash(m->signature),
+ (int) result_width, rv,
+ (m->flags & SD_BUS_VTABLE_DEPRECATED) ? " deprecated" : (m->flags || m->writable ? "" : " -"),
+ (m->flags & SD_BUS_VTABLE_METHOD_NO_REPLY) ? " no-reply" : "",
+ (m->flags & SD_BUS_VTABLE_PROPERTY_CONST) ? " const" : "",
+ (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE) ? " emits-change" : "",
+ (m->flags & SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION) ? " emits-invalidation" : "",
+ m->writable ? " writable" : "");
+ }
+
+ return 0;
+}
+
+static int message_dump(sd_bus_message *m, FILE *f) {
+ return bus_message_dump(m, f, BUS_MESSAGE_DUMP_WITH_HEADER);
+}
+
+static int message_pcap(sd_bus_message *m, FILE *f) {
+ return bus_message_pcap_frame(m, arg_snaplen, f);
+}
+
+static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
bool added_something = false;
char **i;
int r;
@@ -241,43 +1088,35 @@ static int monitor(sd_bus *bus, char *argv[]) {
return log_oom();
r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
added_something = true;
}
STRV_FOREACH(i, arg_matches) {
r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
added_something = true;
}
if (!added_something) {
r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
}
for (;;) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
r = sd_bus_process(bus, &m);
- if (r < 0) {
- log_error("Failed to process bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to process bus: %m");
if (m) {
- bus_message_dump(m, stdout, true);
+ dump(m, stdout);
continue;
}
@@ -285,13 +1124,33 @@ static int monitor(sd_bus *bus, char *argv[]) {
continue;
r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0) {
- log_error("Failed to wait for bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to wait for bus: %m");
}
}
+static int capture(sd_bus *bus, char *argv[]) {
+ int r;
+
+ if (isatty(fileno(stdout)) > 0) {
+ log_error("Refusing to write message data to console, please redirect output to a file.");
+ return -EINVAL;
+ }
+
+ bus_pcap_header(arg_snaplen, stdout);
+
+ r = monitor(bus, argv, message_pcap);
+ if (r < 0)
+ return r;
+
+ if (ferror(stdout)) {
+ log_error("Couldn't write capture file.");
+ return -EIO;
+ }
+
+ return r;
+}
+
static int status(sd_bus *bus, char *argv[]) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
pid_t pid;
@@ -299,23 +1158,498 @@ static int status(sd_bus *bus, char *argv[]) {
assert(bus);
- if (strv_length(argv) != 2) {
- log_error("Expects one argument.");
+ if (strv_length(argv) > 2) {
+ log_error("Expects no or one argument.");
+ return -EINVAL;
+ }
+
+ if (argv[1]) {
+ r = parse_pid(argv[1], &pid);
+ if (r < 0)
+ r = sd_bus_get_name_creds(
+ bus,
+ argv[1],
+ (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
+ &creds);
+ else
+ r = sd_bus_creds_new_from_pid(
+ &creds,
+ pid,
+ _SD_BUS_CREDS_ALL);
+ } else {
+ const char *scope, *address;
+ sd_id128_t bus_id;
+
+ r = sd_bus_get_address(bus, &address);
+ if (r >= 0)
+ printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
+
+ r = sd_bus_get_scope(bus, &scope);
+ if (r >= 0)
+ printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
+
+ r = sd_bus_get_bus_id(bus, &bus_id);
+ if (r >= 0)
+ printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
+
+ r = sd_bus_get_owner_creds(
+ bus,
+ (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL,
+ &creds);
+ }
+
+ if (r < 0)
+ return log_error_errno(r, "Failed to get credentials: %m");
+
+ bus_creds_dump(creds, NULL, false);
+ return 0;
+}
+
+static int message_append_cmdline(sd_bus_message *m, const char *signature, char ***x) {
+ char **p;
+ int r;
+
+ assert(m);
+ assert(signature);
+ assert(x);
+
+ p = *x;
+
+ for (;;) {
+ const char *v;
+ char t;
+
+ t = *signature;
+ v = *p;
+
+ if (t == 0)
+ break;
+ if (!v) {
+ log_error("Too few parameters for signature.");
+ return -EINVAL;
+ }
+
+ signature++;
+ p++;
+
+ switch (t) {
+
+ case SD_BUS_TYPE_BOOLEAN:
+
+ r = parse_boolean(v);
+ if (r < 0) {
+ log_error("Failed to parse as boolean: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &r);
+ break;
+
+ case SD_BUS_TYPE_BYTE: {
+ uint8_t z;
+
+ r = safe_atou8(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as byte (unsigned 8bit integer): %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_INT16: {
+ int16_t z;
+
+ r = safe_atoi16(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as signed 16bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_UINT16: {
+ uint16_t z;
+
+ r = safe_atou16(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as unsigned 16bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_INT32: {
+ int32_t z;
+
+ r = safe_atoi32(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as signed 32bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_UINT32: {
+ uint32_t z;
+
+ r = safe_atou32(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as unsigned 32bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_INT64: {
+ int64_t z;
+
+ r = safe_atoi64(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as signed 64bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_UINT64: {
+ uint64_t z;
+
+ r = safe_atou64(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as unsigned 64bit integer: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+
+ case SD_BUS_TYPE_DOUBLE: {
+ double z;
+
+ r = safe_atod(v, &z);
+ if (r < 0) {
+ log_error("Failed to parse as double precision floating point: %s", v);
+ return r;
+ }
+
+ r = sd_bus_message_append_basic(m, t, &z);
+ break;
+ }
+
+ case SD_BUS_TYPE_STRING:
+ case SD_BUS_TYPE_OBJECT_PATH:
+ case SD_BUS_TYPE_SIGNATURE:
+
+ r = sd_bus_message_append_basic(m, t, v);
+ break;
+
+ case SD_BUS_TYPE_ARRAY: {
+ uint32_t n;
+ size_t k;
+
+ r = safe_atou32(v, &n);
+ if (r < 0) {
+ log_error("Failed to parse number of array entries: %s", v);
+ return r;
+ }
+
+ r = signature_element_length(signature, &k);
+ if (r < 0) {
+ log_error("Invalid array signature.");
+ return r;
+ }
+
+ {
+ unsigned i;
+ char s[k + 1];
+ memcpy(s, signature, k);
+ s[k] = 0;
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ for (i = 0; i < n; i++) {
+ r = message_append_cmdline(m, s, &p);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ signature += k;
+
+ r = sd_bus_message_close_container(m);
+ break;
+ }
+
+ case SD_BUS_TYPE_VARIANT:
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, v);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = message_append_cmdline(m, v, &p);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ break;
+
+ case SD_BUS_TYPE_STRUCT_BEGIN:
+ case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
+ size_t k;
+
+ signature--;
+ p--;
+
+ r = signature_element_length(signature, &k);
+ if (r < 0) {
+ log_error("Invalid struct/dict entry signature.");
+ return r;
+ }
+
+ {
+ char s[k-1];
+ memcpy(s, signature + 1, k - 2);
+ s[k - 2] = 0;
+
+ r = sd_bus_message_open_container(m, t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = message_append_cmdline(m, s, &p);
+ if (r < 0)
+ return r;
+ }
+
+ signature += k;
+
+ r = sd_bus_message_close_container(m);
+ break;
+ }
+
+ case SD_BUS_TYPE_UNIX_FD:
+ log_error("UNIX file descriptor not supported as type.");
+ return -EINVAL;
+
+ default:
+ log_error("Unknown signature type %c.", t);
+ return -EINVAL;
+ }
+
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ *x = p;
+ return 0;
+}
+
+static int call(sd_bus *bus, char *argv[]) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
+ int r;
+
+ assert(bus);
+
+ if (strv_length(argv) < 5) {
+ log_error("Expects at least four arguments.");
return -EINVAL;
}
- r = parse_pid(argv[1], &pid);
+ r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
if (r < 0)
- r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
- else
- r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_expect_reply(m, arg_expect_reply);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_auto_start(m, arg_auto_start);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (!isempty(argv[5])) {
+ char **p;
+
+ p = argv+6;
+
+ r = message_append_cmdline(m, argv[5], &p);
+ if (r < 0)
+ return r;
+
+ if (*p) {
+ log_error("Too many parameters for signature.");
+ return -EINVAL;
+ }
+ }
+ if (!arg_expect_reply) {
+ r = sd_bus_send(bus, m, NULL);
+ if (r < 0) {
+ log_error("Failed to send message.");
+ return r;
+ }
+
+ return 0;
+ }
+
+ r = sd_bus_call(bus, m, arg_timeout, &error, &reply);
if (r < 0) {
- log_error("Failed to get credentials: %s", strerror(-r));
+ log_error("%s", bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_is_empty(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (r == 0 && !arg_quiet) {
+
+ if (arg_verbose) {
+ pager_open_if_enabled();
+
+ r = bus_message_dump(reply, stdout, 0);
+ if (r < 0)
+ return r;
+ } else {
+
+ fputs(sd_bus_message_get_signature(reply, true), stdout);
+ fputc(' ', stdout);
+
+ r = format_cmdline(reply, stdout, false);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ fputc('\n', stdout);
+ }
+ }
+
+ return 0;
+}
+
+static int get_property(sd_bus *bus, char *argv[]) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ unsigned n;
+ char **i;
+ int r;
+
+ assert(bus);
+
+ n = strv_length(argv);
+ if (n < 5) {
+ log_error("Expects at least four arguments.");
+ return -EINVAL;
+ }
+
+ STRV_FOREACH(i, argv + 4) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ const char *contents = NULL;
+ char type;
+
+ r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Get", &error, &reply, "ss", argv[3], *i);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
+ return r;
+ }
+
+ r = sd_bus_message_peek_type(reply, &type, &contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_enter_container(reply, 'v', contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (arg_verbose) {
+ pager_open_if_enabled();
+
+ r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
+ if (r < 0)
+ return r;
+ } else {
+ fputs(contents, stdout);
+ fputc(' ', stdout);
+
+ r = format_cmdline(reply, stdout, false);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ fputc('\n', stdout);
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
+ return 0;
+}
+
+static int set_property(sd_bus *bus, char *argv[]) {
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ unsigned n;
+ char **p;
+ int r;
+
+ assert(bus);
+
+ n = strv_length(argv);
+ if (n < 6) {
+ log_error("Expects at least five arguments.");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ss", argv[3], argv[4]);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', argv[5]);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = argv+6;
+ r = message_append_cmdline(m, argv[5], &p);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ if (*p) {
+ log_error("Too many parameters for signature.");
+ return -EINVAL;
+ }
+
+ r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
return r;
}
- bus_creds_dump(creds, NULL);
return 0;
}
@@ -335,11 +1669,29 @@ static int help(void) {
" --unique Only show unique names\n"
" --acquired Only show acquired names\n"
" --activatable Only show activatable names\n"
- " --match=MATCH Only show matching messages\n\n"
+ " --match=MATCH Only show matching messages\n"
+ " --list Don't show tree, but simple object path list\n"
+ " --quiet Don't show method call reply\n"
+ " --verbose Show result values in long format\n"
+ " --expect-reply=BOOL Expect a method call reply\n"
+ " --auto-start=BOOL Auto-start destination service\n"
+ " --allow-interactive-authorization=BOOL\n"
+ " Allow interactive authorization for operation\n"
+ " --timeout=SECS Maximum time to wait for method call completion\n"
+ " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n"
"Commands:\n"
" list List bus names\n"
+ " status [SERVICE] Show bus service, process or bus owner credentials\n"
" monitor [SERVICE...] Show bus traffic\n"
- " status NAME Show name status\n"
+ " capture [SERVICE...] Capture bus traffic as pcap\n"
+ " tree [SERVICE...] Show object tree of service\n"
+ " introspect SERVICE OBJECT\n"
+ " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
+ " Call a method\n"
+ " get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
+ " Get property value\n"
+ " set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
+ " Set property value\n"
" help Show this help\n"
, program_invocation_short_name);
@@ -359,7 +1711,15 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SHOW_MACHINE,
ARG_UNIQUE,
ARG_ACQUIRED,
- ARG_ACTIVATABLE
+ ARG_ACTIVATABLE,
+ ARG_SIZE,
+ ARG_LIST,
+ ARG_VERBOSE,
+ ARG_EXPECT_REPLY,
+ ARG_AUTO_START,
+ ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
+ ARG_TIMEOUT,
+ ARG_AUGMENT_CREDS,
};
static const struct option options[] = {
@@ -377,15 +1737,24 @@ static int parse_argv(int argc, char *argv[]) {
{ "match", required_argument, NULL, ARG_MATCH },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
+ { "size", required_argument, NULL, ARG_SIZE },
+ { "list", no_argument, NULL, ARG_LIST },
+ { "quiet", no_argument, NULL, 'q' },
+ { "verbose", no_argument, NULL, ARG_VERBOSE },
+ { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
+ { "auto-start", required_argument, NULL, ARG_AUTO_START },
+ { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
+ { "timeout", required_argument, NULL, ARG_TIMEOUT },
+ { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS},
{},
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hH:M:q", options, NULL)) >= 0)
switch (c) {
@@ -438,6 +1807,28 @@ static int parse_argv(int argc, char *argv[]) {
return log_oom();
break;
+ case ARG_SIZE: {
+ off_t o;
+
+ r = parse_size(optarg, 0, &o);
+ if (r < 0) {
+ log_error("Failed to parse size: %s", optarg);
+ return r;
+ }
+
+ if ((off_t) (size_t) o != o) {
+ log_error("Size out of range.");
+ return -E2BIG;
+ }
+
+ arg_snaplen = (size_t) o;
+ break;
+ }
+
+ case ARG_LIST:
+ arg_list = true;
+ break;
+
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
@@ -448,6 +1839,65 @@ static int parse_argv(int argc, char *argv[]) {
arg_host = optarg;
break;
+ case 'q':
+ arg_quiet = true;
+ break;
+
+ case ARG_VERBOSE:
+ arg_verbose = true;
+ break;
+
+ case ARG_EXPECT_REPLY:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --expect-reply= parameter.");
+ return r;
+ }
+
+ arg_expect_reply = !!r;
+ break;
+
+
+ case ARG_AUTO_START:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --auto-start= parameter.");
+ return r;
+ }
+
+ arg_auto_start = !!r;
+ break;
+
+
+ case ARG_ALLOW_INTERACTIVE_AUTHORIZATION:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --allow-interactive-authorization= parameter.");
+ return r;
+ }
+
+ arg_allow_interactive_authorization = !!r;
+ break;
+
+ case ARG_TIMEOUT:
+ r = parse_sec(optarg, &arg_timeout);
+ if (r < 0) {
+ log_error("Failed to parse --timeout= parameter.");
+ return r;
+ }
+
+ break;
+
+ case ARG_AUGMENT_CREDS:
+ r = parse_boolean(optarg);
+ if (r < 0) {
+ log_error("Failed to parse --augment-creds= parameter.");
+ return r;
+ }
+
+ arg_augment_creds = !!r;
+ break;
+
case '?':
return -EINVAL;
@@ -455,9 +1905,6 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (!arg_unique && !arg_acquired && !arg_activatable)
- arg_unique = arg_acquired = arg_activatable = true;
-
return 1;
}
@@ -469,11 +1916,29 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
return list_bus_names(bus, argv + optind);
if (streq(argv[optind], "monitor"))
- return monitor(bus, argv + optind);
+ return monitor(bus, argv + optind, message_dump);
+
+ if (streq(argv[optind], "capture"))
+ return capture(bus, argv + optind);
if (streq(argv[optind], "status"))
return status(bus, argv + optind);
+ if (streq(argv[optind], "tree"))
+ return tree(bus, argv + optind);
+
+ if (streq(argv[optind], "introspect"))
+ return introspect(bus, argv + optind);
+
+ if (streq(argv[optind], "call"))
+ return call(bus, argv + optind);
+
+ if (streq(argv[optind], "get-property"))
+ return get_property(bus, argv + optind);
+
+ if (streq(argv[optind], "set-property"))
+ return set_property(bus, argv + optind);
+
if (streq(argv[optind], "help"))
return help();
@@ -494,33 +1959,34 @@ int main(int argc, char *argv[]) {
r = sd_bus_new(&bus);
if (r < 0) {
- log_error("Failed to allocate bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate bus: %m");
goto finish;
}
- if (streq_ptr(argv[optind], "monitor")) {
+ if (streq_ptr(argv[optind], "monitor") ||
+ streq_ptr(argv[optind], "capture")) {
r = sd_bus_set_monitor(bus, true);
if (r < 0) {
- log_error("Failed to set monitor mode: %s", strerror(-r));
+ log_error_errno(r, "Failed to set monitor mode: %m");
goto finish;
}
- r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
+ r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
if (r < 0) {
- log_error("Failed to enable credentials: %s", strerror(-r));
+ log_error_errno(r, "Failed to enable credentials: %m");
goto finish;
}
r = sd_bus_negotiate_timestamp(bus, true);
if (r < 0) {
- log_error("Failed to enable timestamps: %s", strerror(-r));
+ log_error_errno(r, "Failed to enable timestamps: %m");
goto finish;
}
r = sd_bus_negotiate_fds(bus, true);
if (r < 0) {
- log_error("Failed to enable fds: %s", strerror(-r));
+ log_error_errno(r, "Failed to enable fds: %m");
goto finish;
}
}
@@ -528,13 +1994,22 @@ int main(int argc, char *argv[]) {
if (arg_address)
r = sd_bus_set_address(bus, arg_address);
else {
+ r = sd_bus_set_bus_client(bus, true);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set bus client: %m");
+ goto finish;
+ }
+
switch (arg_transport) {
case BUS_TRANSPORT_LOCAL:
- if (arg_user)
+ if (arg_user) {
+ bus->is_user = true;
r = bus_set_address_user(bus);
- else
+ } else {
+ bus->is_system = true;
r = bus_set_address_system(bus);
+ }
break;
case BUS_TRANSPORT_REMOTE:
@@ -550,19 +2025,13 @@ int main(int argc, char *argv[]) {
}
}
if (r < 0) {
- log_error("Failed to set address: %s", strerror(-r));
- goto finish;
- }
-
- r = sd_bus_set_bus_client(bus, true);
- if (r < 0) {
- log_error("Failed to set bus client: %s", strerror(-r));
+ log_error_errno(r, "Failed to set address: %m");
goto finish;
}
r = sd_bus_start(bus);
if (r < 0) {
- log_error("Failed to connect to bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to connect to bus: %m");
goto finish;
}
diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h
index 2ebf405d7d..e2262de6ba 100644
--- a/src/libsystemd/sd-bus/kdbus.h
+++ b/src/libsystemd/sd-bus/kdbus.h
@@ -58,25 +58,41 @@ struct kdbus_notify_name_change {
/**
* struct kdbus_creds - process credentials
* @uid: User ID
+ * @euid: Effective UID
+ * @suid: Saved UID
+ * @fsuid: Filesystem UID
* @gid: Group ID
+ * @egid: Effective GID
+ * @sgid: Saved GID
+ * @fsgid: Filesystem GID
+ *
+ * Attached to:
+ * KDBUS_ITEM_CREDS
+ */
+struct kdbus_creds {
+ __u32 uid;
+ __u32 euid;
+ __u32 suid;
+ __u32 fsuid;
+ __u32 gid;
+ __u32 egid;
+ __u32 sgid;
+ __u32 fsgid;
+};
+
+/**
+ * struct kdbus_pids - process identifiers
* @pid: Process ID
* @tid: Thread ID
- * @starttime: Starttime of the process
*
- * The starttime of the process PID. This is useful to detect PID overruns
- * from the client side. i.e. if you use the PID to look something up in
- * /proc/$PID/ you can afterwards check the starttime field of it, to ensure
- * you didn't run into a PID overrun.
+ * The PID and TID of a process.
*
* Attached to:
- * KDBUS_ITEM_CREDS
+ * KDBUS_ITEM_PIDS
*/
-struct kdbus_creds {
- __u64 uid;
- __u64 gid;
+struct kdbus_pids {
__u64 pid;
__u64 tid;
- __u64 starttime;
};
/**
@@ -103,8 +119,8 @@ struct kdbus_caps {
* KDBUS_ITEM_AUDIT
*/
struct kdbus_audit {
- __u64 sessionid;
- __u64 loginuid;
+ __u32 sessionid;
+ __u32 loginuid;
};
/**
@@ -162,7 +178,8 @@ struct kdbus_bloom_filter {
/**
* struct kdbus_memfd - a kdbus memfd
- * @size: The memfd's size
+ * @start: The offset into the memfd where the segment starts
+ * @size: The size of the memfd segment
* @fd: The file descriptor number
* @__pad: Padding to ensure proper alignment and size
*
@@ -170,6 +187,7 @@ struct kdbus_bloom_filter {
* KDBUS_ITEM_PAYLOAD_MEMFD
*/
struct kdbus_memfd {
+ __u64 start;
__u64 size;
int fd;
__u32 __pad;
@@ -181,7 +199,7 @@ struct kdbus_memfd {
* @name: Well-known name
*
* Attached to:
- * KDBUS_ITEM_NAME
+ * KDBUS_ITEM_OWNED_NAME
*/
struct kdbus_name {
__u64 flags;
@@ -203,49 +221,67 @@ struct kdbus_policy_access {
/**
* enum kdbus_item_type - item types to chain data in a list
- * @_KDBUS_ITEM_NULL: Uninitialized/invalid
- * @_KDBUS_ITEM_USER_BASE: Start of user items
- * @KDBUS_ITEM_PAYLOAD_VEC: Vector to data
- * @KDBUS_ITEM_PAYLOAD_OFF: Data at returned offset to message head
- * @KDBUS_ITEM_PAYLOAD_MEMFD: Data as sealed memfd
- * @KDBUS_ITEM_FDS: Attached file descriptors
- * @KDBUS_ITEM_BLOOM_PARAMETER: Bus-wide bloom parameters, used with
- * KDBUS_CMD_BUS_MAKE, carries a
- * struct kdbus_bloom_parameter
- * @KDBUS_ITEM_BLOOM_FILTER: Bloom filter carried with a message, used to
- * match against a bloom mask of a connection,
- * carries a struct kdbus_bloom_filter
- * @KDBUS_ITEM_BLOOM_MASK: Bloom mask used to match against a message's
- * bloom filter
- * @KDBUS_ITEM_DST_NAME: Destination's well-known name
- * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint
- * @KDBUS_ITEM_ATTACH_FLAGS: Attach-flags, used for updating which metadata
- * a connection subscribes to
- * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items
- * @KDBUS_ITEM_NAME: Well-know name with flags
- * @KDBUS_ITEM_ID: Connection ID
- * @KDBUS_ITEM_TIMESTAMP: Timestamp
- * @KDBUS_ITEM_CREDS: Process credential
- * @KDBUS_ITEM_AUXGROUPS: Auxiliary process groups
- * @KDBUS_ITEM_PID_COMM: Process ID "comm" identifier
- * @KDBUS_ITEM_TID_COMM: Thread ID "comm" identifier
- * @KDBUS_ITEM_EXE: The path of the executable
- * @KDBUS_ITEM_CMDLINE: The process command line
- * @KDBUS_ITEM_CGROUP: The croup membership
- * @KDBUS_ITEM_CAPS: The process capabilities
- * @KDBUS_ITEM_SECLABEL: The security label
- * @KDBUS_ITEM_AUDIT: The audit IDs
- * @KDBUS_ITEM_CONN_NAME: The connection's human-readable name (debugging)
- * @_KDBUS_ITEM_POLICY_BASE: Start of policy items
- * @KDBUS_ITEM_POLICY_ACCESS: Policy access block
- * @_KDBUS_ITEM_KERNEL_BASE: Start of kernel-generated message items
- * @KDBUS_ITEM_NAME_ADD: Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_REMOVE: Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_NAME_CHANGE: Notify in struct kdbus_notify_name_change
- * @KDBUS_ITEM_ID_ADD: Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_ID_REMOVE: Notify in struct kdbus_notify_id_change
- * @KDBUS_ITEM_REPLY_TIMEOUT: Timeout has been reached
- * @KDBUS_ITEM_REPLY_DEAD: Destination died
+ * @_KDBUS_ITEM_NULL: Uninitialized/invalid
+ * @_KDBUS_ITEM_USER_BASE: Start of user items
+ * @KDBUS_ITEM_PAYLOAD_VEC: Vector to data
+ * @KDBUS_ITEM_PAYLOAD_OFF: Data at returned offset to message head
+ * @KDBUS_ITEM_PAYLOAD_MEMFD: Data as sealed memfd
+ * @KDBUS_ITEM_FDS: Attached file descriptors
+ * @KDBUS_ITEM_BLOOM_PARAMETER: Bus-wide bloom parameters, used with
+ * KDBUS_CMD_BUS_MAKE, carries a
+ * struct kdbus_bloom_parameter
+ * @KDBUS_ITEM_BLOOM_FILTER: Bloom filter carried with a message,
+ * used to match against a bloom mask of a
+ * connection, carries a struct
+ * kdbus_bloom_filter
+ * @KDBUS_ITEM_BLOOM_MASK: Bloom mask used to match against a
+ * message'sbloom filter
+ * @KDBUS_ITEM_DST_NAME: Destination's well-known name
+ * @KDBUS_ITEM_MAKE_NAME: Name of domain, bus, endpoint
+ * @KDBUS_ITEM_ATTACH_FLAGS_SEND: Attach-flags, used for updating which
+ * metadata a connection opts in to send
+ * @KDBUS_ITEM_ATTACH_FLAGS_RECV: Attach-flags, used for updating which
+ * metadata a connection requests to
+ * receive for each reeceived message
+ * @KDBUS_ITEM_ID: Connection ID
+ * @KDBUS_ITEM_NAME: Well-know name with flags
+ * @_KDBUS_ITEM_ATTACH_BASE: Start of metadata attach items
+ * @KDBUS_ITEM_TIMESTAMP: Timestamp
+ * @KDBUS_ITEM_CREDS: Process credentials
+ * @KDBUS_ITEM_PIDS: Process identifiers
+ * @KDBUS_ITEM_AUXGROUPS: Auxiliary process groups
+ * @KDBUS_ITEM_OWNED_NAME: A name owned by the associated
+ * connection
+ * @KDBUS_ITEM_TID_COMM: Thread ID "comm" identifier
+ * (Don't trust this, see below.)
+ * @KDBUS_ITEM_PID_COMM: Process ID "comm" identifier
+ * (Don't trust this, see below.)
+ * @KDBUS_ITEM_EXE: The path of the executable
+ * (Don't trust this, see below.)
+ * @KDBUS_ITEM_CMDLINE: The process command line
+ * (Don't trust this, see below.)
+ * @KDBUS_ITEM_CGROUP: The croup membership
+ * @KDBUS_ITEM_CAPS: The process capabilities
+ * @KDBUS_ITEM_SECLABEL: The security label
+ * @KDBUS_ITEM_AUDIT: The audit IDs
+ * @KDBUS_ITEM_CONN_DESCRIPTION: The connection's human-readable name
+ * (debugging)
+ * @_KDBUS_ITEM_POLICY_BASE: Start of policy items
+ * @KDBUS_ITEM_POLICY_ACCESS: Policy access block
+ * @_KDBUS_ITEM_KERNEL_BASE: Start of kernel-generated message items
+ * @KDBUS_ITEM_NAME_ADD: Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_REMOVE: Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_NAME_CHANGE: Notification in kdbus_notify_name_change
+ * @KDBUS_ITEM_ID_ADD: Notification in kdbus_notify_id_change
+ * @KDBUS_ITEM_ID_REMOVE: Notification in kdbus_notify_id_change
+ * @KDBUS_ITEM_REPLY_TIMEOUT: Timeout has been reached
+ * @KDBUS_ITEM_REPLY_DEAD: Destination died
+ *
+ * N.B: The process and thread COMM fields, as well as the CMDLINE and
+ * EXE fields may be altered by unprivileged processes und should
+ * hence *not* used for security decisions. Peers should make use of
+ * these items only for informational purposes, such as generating log
+ * records.
*/
enum kdbus_item_type {
_KDBUS_ITEM_NULL,
@@ -259,23 +295,27 @@ enum kdbus_item_type {
KDBUS_ITEM_BLOOM_MASK,
KDBUS_ITEM_DST_NAME,
KDBUS_ITEM_MAKE_NAME,
- KDBUS_ITEM_ATTACH_FLAGS,
+ KDBUS_ITEM_ATTACH_FLAGS_SEND,
+ KDBUS_ITEM_ATTACH_FLAGS_RECV,
+ KDBUS_ITEM_ID,
+ KDBUS_ITEM_NAME,
+ /* keep these item types in sync with KDBUS_ATTACH_* flags */
_KDBUS_ITEM_ATTACH_BASE = 0x1000,
- KDBUS_ITEM_NAME = _KDBUS_ITEM_ATTACH_BASE,
- KDBUS_ITEM_ID,
- KDBUS_ITEM_TIMESTAMP,
+ KDBUS_ITEM_TIMESTAMP = _KDBUS_ITEM_ATTACH_BASE,
KDBUS_ITEM_CREDS,
+ KDBUS_ITEM_PIDS,
KDBUS_ITEM_AUXGROUPS,
- KDBUS_ITEM_PID_COMM,
+ KDBUS_ITEM_OWNED_NAME,
KDBUS_ITEM_TID_COMM,
+ KDBUS_ITEM_PID_COMM,
KDBUS_ITEM_EXE,
KDBUS_ITEM_CMDLINE,
KDBUS_ITEM_CGROUP,
KDBUS_ITEM_CAPS,
KDBUS_ITEM_SECLABEL,
KDBUS_ITEM_AUDIT,
- KDBUS_ITEM_CONN_NAME,
+ KDBUS_ITEM_CONN_DESCRIPTION,
_KDBUS_ITEM_POLICY_BASE = 0x2000,
KDBUS_ITEM_POLICY_ACCESS = _KDBUS_ITEM_POLICY_BASE,
@@ -326,6 +366,7 @@ struct kdbus_item {
__u64 id;
struct kdbus_vec vec;
struct kdbus_creds creds;
+ struct kdbus_pids pids;
struct kdbus_audit audit;
struct kdbus_caps caps;
struct kdbus_timestamp timestamp;
@@ -445,6 +486,16 @@ enum kdbus_recv_flags {
* @offset: Returned offset in the pool where the message is
* stored. The user must use KDBUS_CMD_FREE to free
* the allocated memory.
+ * @dropped_msgs: In case the KDBUS_CMD_MSG_RECV ioctl returns
+ * -EOVERFLOW, this field will contain the number of
+ * broadcast messages that have been lost since the
+ * last call.
+ * @msg_size: Filled by the kernel with the actual message size. This
+ * is the full size of the slice placed at @offset. It
+ * includes the memory used for the kdbus_msg object, but
+ * also for all appended VECs. By using @msg_size and
+ * @offset, you can map a single message, instead of
+ * mapping the whole pool.
*
* This struct is used with the KDBUS_CMD_MSG_RECV ioctl.
*/
@@ -452,13 +503,17 @@ struct kdbus_cmd_recv {
__u64 flags;
__u64 kernel_flags;
__s64 priority;
- __u64 offset;
+ union {
+ __u64 offset;
+ __u64 dropped_msgs;
+ };
+ __u64 msg_size;
} __attribute__((aligned(8)));
/**
* struct kdbus_cmd_cancel - struct to cancel a synchronously pending message
- * @cookie The cookie of the pending message
- * @flags Flags for the free command. Currently unused.
+ * @cookie: The cookie of the pending message
+ * @flags: Flags for the free command. Currently unused.
*
* This struct is used with the KDBUS_CMD_CANCEL ioctl.
*/
@@ -525,46 +580,54 @@ enum kdbus_policy_type {
* a service
* @KDBUS_HELLO_MONITOR: Special-purpose connection to monitor
* bus traffic
+ * @KDBUS_HELLO_UNPRIVILEGED: Don't treat this connection as privileged once
+ * the bus connection was established.
*/
enum kdbus_hello_flags {
KDBUS_HELLO_ACCEPT_FD = 1ULL << 0,
KDBUS_HELLO_ACTIVATOR = 1ULL << 1,
KDBUS_HELLO_POLICY_HOLDER = 1ULL << 2,
KDBUS_HELLO_MONITOR = 1ULL << 3,
+ KDBUS_HELLO_UNPRIVILEGED = 1ULL << 4,
};
/**
* enum kdbus_attach_flags - flags for metadata attachments
- * @KDBUS_ATTACH_TIMESTAMP: Timestamp
- * @KDBUS_ATTACH_CREDS: Credentials
- * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups
- * @KDBUS_ATTACH_NAMES: Well-known names
- * @KDBUS_ATTACH_COMM_TID: The "comm" process identifier of the TID
- * @KDBUS_ATTACH_COMM_PID: The "comm" process identifier of the PID
- * @KDBUS_ATTACH_EXE: The path of the executable
- * @KDBUS_ATTACH_CMDLINE: The process command line
- * @KDBUS_ATTACH_CGROUP: The croup membership
- * @KDBUS_ATTACH_CAPS: The process capabilities
- * @KDBUS_ATTACH_SECLABEL: The security label
- * @KDBUS_ATTACH_AUDIT: The audit IDs
- * @KDBUS_ATTACH_CONN_NAME: The human-readable connection name
- * @_KDBUS_ATTACH_ALL: All of the above
+ * @KDBUS_ATTACH_TIMESTAMP: Timestamp
+ * @KDBUS_ATTACH_CREDS: Credentials
+ * @KDBUS_ATTACH_PIDS: PIDs
+ * @KDBUS_ATTACH_AUXGROUPS: Auxiliary groups
+ * @KDBUS_ATTACH_NAMES: Well-known names
+ * @KDBUS_ATTACH_TID_COMM: The "comm" process identifier of the TID
+ * @KDBUS_ATTACH_PID_COMM: The "comm" process identifier of the PID
+ * @KDBUS_ATTACH_EXE: The path of the executable
+ * @KDBUS_ATTACH_CMDLINE: The process command line
+ * @KDBUS_ATTACH_CGROUP: The croup membership
+ * @KDBUS_ATTACH_CAPS: The process capabilities
+ * @KDBUS_ATTACH_SECLABEL: The security label
+ * @KDBUS_ATTACH_AUDIT: The audit IDs
+ * @KDBUS_ATTACH_CONN_DESCRIPTION: The human-readable connection name
+ * @_KDBUS_ATTACH_ALL: All of the above
+ * @_KDBUS_ATTACH_ANY: Wildcard match to enable any kind of
+ * metatdata.
*/
enum kdbus_attach_flags {
KDBUS_ATTACH_TIMESTAMP = 1ULL << 0,
KDBUS_ATTACH_CREDS = 1ULL << 1,
- KDBUS_ATTACH_AUXGROUPS = 1ULL << 2,
- KDBUS_ATTACH_NAMES = 1ULL << 3,
- KDBUS_ATTACH_TID_COMM = 1ULL << 4,
- KDBUS_ATTACH_PID_COMM = 1ULL << 5,
- KDBUS_ATTACH_EXE = 1ULL << 6,
- KDBUS_ATTACH_CMDLINE = 1ULL << 7,
- KDBUS_ATTACH_CGROUP = 1ULL << 8,
- KDBUS_ATTACH_CAPS = 1ULL << 9,
- KDBUS_ATTACH_SECLABEL = 1ULL << 10,
- KDBUS_ATTACH_AUDIT = 1ULL << 11,
- KDBUS_ATTACH_CONN_NAME = 1ULL << 12,
- _KDBUS_ATTACH_ALL = (1ULL << 13) - 1,
+ KDBUS_ATTACH_PIDS = 1ULL << 2,
+ KDBUS_ATTACH_AUXGROUPS = 1ULL << 3,
+ KDBUS_ATTACH_NAMES = 1ULL << 4,
+ KDBUS_ATTACH_TID_COMM = 1ULL << 5,
+ KDBUS_ATTACH_PID_COMM = 1ULL << 6,
+ KDBUS_ATTACH_EXE = 1ULL << 7,
+ KDBUS_ATTACH_CMDLINE = 1ULL << 8,
+ KDBUS_ATTACH_CGROUP = 1ULL << 9,
+ KDBUS_ATTACH_CAPS = 1ULL << 10,
+ KDBUS_ATTACH_SECLABEL = 1ULL << 11,
+ KDBUS_ATTACH_AUDIT = 1ULL << 12,
+ KDBUS_ATTACH_CONN_DESCRIPTION = 1ULL << 13,
+ _KDBUS_ATTACH_ALL = (1ULL << 14) - 1,
+ _KDBUS_ATTACH_ANY = ~0ULL
};
/**
@@ -572,8 +635,10 @@ enum kdbus_attach_flags {
* @size: The total size of the structure
* @flags: Connection flags (KDBUS_HELLO_*), userspace → kernel
* @kernel_flags: Supported connection flags, kernel → userspace
- * @attach_flags: Mask of metadata to attach to each message sent
- * (KDBUS_ATTACH_*)
+ * @attach_flags_send: Mask of metadata to attach to each message sent
+ * off by this connection (KDBUS_ATTACH_*)
+ * @attach_flags_recv: Mask of metadata to attach to each message receieved
+ * by the new connection (KDBUS_ATTACH_*)
* @bus_flags: The flags field copied verbatim from the original
* KDBUS_CMD_BUS_MAKE ioctl. It's intended to be useful
* to do negotiation of features of the payload that is
@@ -592,7 +657,8 @@ struct kdbus_cmd_hello {
__u64 size;
__u64 flags;
__u64 kernel_flags;
- __u64 attach_flags;
+ __u64 attach_flags_send;
+ __u64 attach_flags_recv;
__u64 bus_flags;
__u64 id;
__u64 pool_size;
@@ -603,8 +669,8 @@ struct kdbus_cmd_hello {
/**
* enum kdbus_make_flags - Flags for KDBUS_CMD_{BUS,EP,NS}_MAKE
- * @KDBUS_MAKE_ACCESS_GROUP: Make the device node group-accessible
- * @KDBUS_MAKE_ACCESS_WORLD: Make the device node world-accessible
+ * @KDBUS_MAKE_ACCESS_GROUP: Make the bus or endpoint node group-accessible
+ * @KDBUS_MAKE_ACCESS_WORLD: Make the bus or endpoint node world-accessible
*/
enum kdbus_make_flags {
KDBUS_MAKE_ACCESS_GROUP = 1ULL << 0,
@@ -619,8 +685,8 @@ enum kdbus_make_flags {
* @kernel_flags: Supported flags for the used command, kernel → userspace
* @items: Items describing details
*
- * This structure is used with the KDBUS_CMD_BUS_MAKE, KDBUS_CMD_ENDPOINT_MAKE
- * and KDBUS_CMD_DOMAIN_MAKE ioctls.
+ * This structure is used with the KDBUS_CMD_BUS_MAKE and
+ * KDBUS_CMD_ENDPOINT_MAKE ioctls.
*/
struct kdbus_cmd_make {
__u64 size;
@@ -666,17 +732,15 @@ struct kdbus_cmd_name {
/**
* struct kdbus_name_info - struct to describe a well-known name
* @size: The total size of the struct
- * @flags: Flags for a name entry (KDBUS_NAME_*),
* @conn_flags: The flags of the owning connection (KDBUS_HELLO_*)
* @owner_id: The current owner of the name
* @items: Item list, containing the well-known name as
- * KDBUS_ITEM_NAME
+ * KDBUS_ITEM_OWNED_NAME
*
* This structure is used as return struct for the KDBUS_CMD_NAME_LIST ioctl.
*/
struct kdbus_name_info {
__u64 size;
- __u64 flags;
__u64 conn_flags;
__u64 owner_id;
struct kdbus_item items[0];
@@ -699,11 +763,12 @@ enum kdbus_name_list_flags {
/**
* struct kdbus_cmd_name_list - request a list of name entries
* @flags: Flags for the query (KDBUS_NAME_LIST_*),
- * userspace → kernel
+ * userspace → kernel
* @kernel_flags: Supported flags for queries, kernel → userspace
* @offset: The returned offset in the caller's pool buffer.
* The user must use KDBUS_CMD_FREE to free the
* allocated memory.
+ * @size: Output buffer to report size of data at @offset.
*
* This structure is used with the KDBUS_CMD_NAME_LIST ioctl.
*/
@@ -711,6 +776,7 @@ struct kdbus_cmd_name_list {
__u64 flags;
__u64 kernel_flags;
__u64 offset;
+ __u64 size;
} __attribute__((aligned(8)));
/**
@@ -737,6 +803,7 @@ struct kdbus_name_list {
* @offset: Returned offset in the caller's pool buffer where the
* kdbus_info struct result is stored. The user must
* use KDBUS_CMD_FREE to free the allocated memory.
+ * @info_size: Output buffer to report size of data at @offset.
* @items: The optional item list, containing the
* well-known name to look up as a KDBUS_ITEM_NAME.
* Only needed in case @id is zero.
@@ -751,6 +818,7 @@ struct kdbus_cmd_info {
__u64 kernel_flags;
__u64 id;
__u64 offset;
+ __u64 info_size;
struct kdbus_item items[0];
} __attribute__((aligned(8)));
@@ -819,100 +887,94 @@ struct kdbus_cmd_match {
} __attribute__((aligned(8)));
/**
- * enum kdbus_ioctl_type - Ioctl API
- * @KDBUS_CMD_BUS_MAKE: After opening the "control" device node, this
- * command creates a new bus with the specified
+ * Ioctl API
+ * KDBUS_CMD_BUS_MAKE: After opening the "control" node, this command
+ * creates a new bus with the specified
* name. The bus is immediately shut down and
- * cleaned up when the opened "control" device node
- * is closed.
- * @KDBUS_CMD_DOMAIN_MAKE: Similar to KDBUS_CMD_BUS_MAKE, but it creates a
- * new kdbus domain.
- * @KDBUS_CMD_ENDPOINT_MAKE: Creates a new named special endpoint to talk to
+ * cleaned up when the opened file descriptor is
+ * closed.
+ * KDBUS_CMD_ENDPOINT_MAKE: Creates a new named special endpoint to talk to
* the bus. Such endpoints usually carry a more
* restrictive policy and grant restricted access
* to specific applications.
- * @KDBUS_CMD_HELLO: By opening the bus device node a connection is
+ * KDBUS_CMD_HELLO: By opening the bus node, a connection is
* created. After a HELLO the opened connection
* becomes an active peer on the bus.
- * @KDBUS_CMD_BYEBYE: Disconnect a connection. If there are no
+ * KDBUS_CMD_BYEBYE: Disconnect a connection. If there are no
* messages queued up in the connection's pool,
* the call succeeds, and the handle is rendered
* unusable. Otherwise, -EBUSY is returned without
* any further side-effects.
- * @KDBUS_CMD_MSG_SEND: Send a message and pass data from userspace to
+ * KDBUS_CMD_MSG_SEND: Send a message and pass data from userspace to
* the kernel.
- * @KDBUS_CMD_MSG_RECV: Receive a message from the kernel which is
+ * KDBUS_CMD_MSG_RECV: Receive a message from the kernel which is
* placed in the receiver's pool.
- * @KDBUS_CMD_MSG_CANCEL: Cancel a pending request of a message that
+ * KDBUS_CMD_MSG_CANCEL: Cancel a pending request of a message that
* blocks while waiting for a reply. The parameter
* denotes the cookie of the message in flight.
- * @KDBUS_CMD_FREE: Release the allocated memory in the receiver's
+ * KDBUS_CMD_FREE: Release the allocated memory in the receiver's
* pool.
- * @KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with
+ * KDBUS_CMD_NAME_ACQUIRE: Request a well-known bus name to associate with
* the connection. Well-known names are used to
* address a peer on the bus.
- * @KDBUS_CMD_NAME_RELEASE: Release a well-known name the connection
+ * KDBUS_CMD_NAME_RELEASE: Release a well-known name the connection
* currently owns.
- * @KDBUS_CMD_NAME_LIST: Retrieve the list of all currently registered
+ * KDBUS_CMD_NAME_LIST: Retrieve the list of all currently registered
* well-known and unique names.
- * @KDBUS_CMD_CONN_INFO: Retrieve credentials and properties of the
+ * KDBUS_CMD_CONN_INFO: Retrieve credentials and properties of the
* initial creator of the connection. The data was
* stored at registration time and does not
* necessarily represent the connected process or
* the actual state of the process.
- * @KDBUS_CMD_CONN_UPDATE: Update the properties of a connection. Used to
+ * KDBUS_CMD_CONN_UPDATE: Update the properties of a connection. Used to
* update the metadata subscription mask and
* policy.
- * @KDBUS_CMD_BUS_CREATOR_INFO: Retrieve information of the creator of the bus
+ * KDBUS_CMD_BUS_CREATOR_INFO: Retrieve information of the creator of the bus
* a connection is attached to.
- * @KDBUS_CMD_ENDPOINT_UPDATE: Update the properties of a custom enpoint. Used
+ * KDBUS_CMD_ENDPOINT_UPDATE: Update the properties of a custom enpoint. Used
* to update the policy.
- * @KDBUS_CMD_MATCH_ADD: Install a match which broadcast messages should
+ * KDBUS_CMD_MATCH_ADD: Install a match which broadcast messages should
* be delivered to the connection.
- * @KDBUS_CMD_MATCH_REMOVE: Remove a current match for broadcast messages.
- */
-enum kdbus_ioctl_type {
- KDBUS_CMD_BUS_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x00,
- struct kdbus_cmd_make),
- KDBUS_CMD_DOMAIN_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x10,
- struct kdbus_cmd_make),
- KDBUS_CMD_ENDPOINT_MAKE = _IOW(KDBUS_IOCTL_MAGIC, 0x20,
- struct kdbus_cmd_make),
-
- KDBUS_CMD_HELLO = _IOWR(KDBUS_IOCTL_MAGIC, 0x30,
- struct kdbus_cmd_hello),
- KDBUS_CMD_BYEBYE = _IO(KDBUS_IOCTL_MAGIC, 0x31),
-
- KDBUS_CMD_MSG_SEND = _IOWR(KDBUS_IOCTL_MAGIC, 0x40,
- struct kdbus_msg),
- KDBUS_CMD_MSG_RECV = _IOWR(KDBUS_IOCTL_MAGIC, 0x41,
- struct kdbus_cmd_recv),
- KDBUS_CMD_MSG_CANCEL = _IOW(KDBUS_IOCTL_MAGIC, 0x42,
- struct kdbus_cmd_cancel),
- KDBUS_CMD_FREE = _IOW(KDBUS_IOCTL_MAGIC, 0x43,
- struct kdbus_cmd_free),
-
- KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOCTL_MAGIC, 0x50,
- struct kdbus_cmd_name),
- KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOCTL_MAGIC, 0x51,
- struct kdbus_cmd_name),
- KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOCTL_MAGIC, 0x52,
- struct kdbus_cmd_name_list),
-
- KDBUS_CMD_CONN_INFO = _IOWR(KDBUS_IOCTL_MAGIC, 0x60,
- struct kdbus_cmd_info),
- KDBUS_CMD_CONN_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x61,
- struct kdbus_cmd_update),
- KDBUS_CMD_BUS_CREATOR_INFO = _IOWR(KDBUS_IOCTL_MAGIC, 0x62,
- struct kdbus_cmd_info),
-
- KDBUS_CMD_ENDPOINT_UPDATE = _IOW(KDBUS_IOCTL_MAGIC, 0x71,
- struct kdbus_cmd_update),
-
- KDBUS_CMD_MATCH_ADD = _IOW(KDBUS_IOCTL_MAGIC, 0x80,
- struct kdbus_cmd_match),
- KDBUS_CMD_MATCH_REMOVE = _IOW(KDBUS_IOCTL_MAGIC, 0x81,
- struct kdbus_cmd_match),
-};
+ * KDBUS_CMD_MATCH_REMOVE: Remove a current match for broadcast messages.
+ */
+#define KDBUS_CMD_BUS_MAKE _IOW(KDBUS_IOCTL_MAGIC, 0x00, \
+ struct kdbus_cmd_make)
+#define KDBUS_CMD_ENDPOINT_MAKE _IOW(KDBUS_IOCTL_MAGIC, 0x10, \
+ struct kdbus_cmd_make)
+
+#define KDBUS_CMD_HELLO _IOWR(KDBUS_IOCTL_MAGIC, 0x20, \
+ struct kdbus_cmd_hello)
+#define KDBUS_CMD_BYEBYE _IO(KDBUS_IOCTL_MAGIC, 0x21) \
+
+#define KDBUS_CMD_MSG_SEND _IOWR(KDBUS_IOCTL_MAGIC, 0x30, \
+ struct kdbus_msg)
+#define KDBUS_CMD_MSG_RECV _IOWR(KDBUS_IOCTL_MAGIC, 0x31, \
+ struct kdbus_cmd_recv)
+#define KDBUS_CMD_MSG_CANCEL _IOW(KDBUS_IOCTL_MAGIC, 0x32, \
+ struct kdbus_cmd_cancel)
+#define KDBUS_CMD_FREE _IOW(KDBUS_IOCTL_MAGIC, 0x33, \
+ struct kdbus_cmd_free)
+
+#define KDBUS_CMD_NAME_ACQUIRE _IOWR(KDBUS_IOCTL_MAGIC, 0x40, \
+ struct kdbus_cmd_name)
+#define KDBUS_CMD_NAME_RELEASE _IOW(KDBUS_IOCTL_MAGIC, 0x41, \
+ struct kdbus_cmd_name)
+#define KDBUS_CMD_NAME_LIST _IOWR(KDBUS_IOCTL_MAGIC, 0x42, \
+ struct kdbus_cmd_name_list)
+
+#define KDBUS_CMD_CONN_INFO _IOWR(KDBUS_IOCTL_MAGIC, 0x50, \
+ struct kdbus_cmd_info)
+#define KDBUS_CMD_CONN_UPDATE _IOW(KDBUS_IOCTL_MAGIC, 0x51, \
+ struct kdbus_cmd_update)
+#define KDBUS_CMD_BUS_CREATOR_INFO _IOWR(KDBUS_IOCTL_MAGIC, 0x52, \
+ struct kdbus_cmd_info)
+
+#define KDBUS_CMD_ENDPOINT_UPDATE _IOW(KDBUS_IOCTL_MAGIC, 0x61, \
+ struct kdbus_cmd_update)
+
+#define KDBUS_CMD_MATCH_ADD _IOW(KDBUS_IOCTL_MAGIC, 0x70, \
+ struct kdbus_cmd_match)
+#define KDBUS_CMD_MATCH_REMOVE _IOW(KDBUS_IOCTL_MAGIC, 0x71, \
+ struct kdbus_cmd_match)
#endif /* _KDBUS_UAPI_H_ */
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 03ec6036fa..ef0b15185f 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -129,7 +129,7 @@ static void bus_free(sd_bus *b) {
free(b->machine);
free(b->fake_label);
free(b->cgroup_root);
- free(b->connection_name);
+ free(b->description);
free(b->exec_path);
strv_free(b->exec_argv);
@@ -274,24 +274,50 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
}
_public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
+ uint64_t new_flags;
assert_return(bus, -EINVAL);
- assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- SET_FLAG(bus->attach_flags, KDBUS_ATTACH_TIMESTAMP, b);
+ new_flags = bus->attach_flags;
+ SET_FLAG(new_flags, KDBUS_ATTACH_TIMESTAMP, b);
+
+ if (bus->attach_flags == new_flags)
+ return 0;
+
+ bus->attach_flags = new_flags;
+ if (bus->state != BUS_UNSET && bus->is_kernel)
+ bus_kernel_realize_attach_flags(bus);
+
return 0;
}
-_public_ int sd_bus_negotiate_creds(sd_bus *bus, uint64_t mask) {
+_public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
+ uint64_t new_flags;
+
assert_return(bus, -EINVAL);
assert_return(mask <= _SD_BUS_CREDS_ALL, -EINVAL);
- assert_return(bus->state == BUS_UNSET, -EPERM);
+ assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
+ if (b)
+ bus->creds_mask |= mask;
+ else
+ bus->creds_mask &= ~mask;
+
/* The well knowns we need unconditionally, so that matches can work */
- bus->creds_mask = mask | SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
+
+ /* Make sure we don't lose the timestamp flag */
+ new_flags = (bus->attach_flags & KDBUS_ATTACH_TIMESTAMP) | attach_flags_to_kdbus(bus->creds_mask);
+ if (bus->attach_flags == new_flags)
+ return 0;
- return kdbus_translate_attach_flags(bus->creds_mask, &bus->attach_flags);
+ bus->attach_flags = new_flags;
+ if (bus->state != BUS_UNSET && bus->is_kernel)
+ bus_kernel_realize_attach_flags(bus);
+
+ return 0;
}
_public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
@@ -323,22 +349,12 @@ _public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
return 0;
}
-_public_ int sd_bus_set_name(sd_bus *bus, const char *name) {
- char *n;
-
+_public_ int sd_bus_set_description(sd_bus *bus, const char *description) {
assert_return(bus, -EINVAL);
- assert_return(name, -EINVAL);
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- n = strdup(name);
- if (!n)
- return -ENOMEM;
-
- free(bus->connection_name);
- bus->connection_name = n;
-
- return 0;
+ return free_and_strdup(&bus->description, description);
}
static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
@@ -817,7 +833,7 @@ static int parse_container_kernel_address(sd_bus *b, const char **p, char **guid
machine = NULL;
free(b->kernel);
- b->kernel = strdup("/dev/kdbus/0-system/bus");
+ b->kernel = strdup("/sys/fs/kdbus/0-system/bus");
if (!b->kernel)
return -ENOMEM;
@@ -1081,6 +1097,7 @@ _public_ int sd_bus_open(sd_bus **ret) {
* be safe, and authenticate everything */
b->trusted = false;
b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
+ b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
r = sd_bus_start(b);
if (r < 0)
@@ -1102,7 +1119,7 @@ int bus_set_address_system(sd_bus *b) {
if (e)
return sd_bus_set_address(b, e);
- return sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_PATH);
+ return sd_bus_set_address(b, DEFAULT_SYSTEM_BUS_ADDRESS);
}
_public_ int sd_bus_open_system(sd_bus **ret) {
@@ -1126,6 +1143,7 @@ _public_ int sd_bus_open_system(sd_bus **ret) {
* need the caller's UID and capability set for that. */
b->trusted = false;
b->attach_flags |= KDBUS_ATTACH_CAPS | KDBUS_ATTACH_CREDS;
+ b->creds_mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS;
r = sd_bus_start(b);
if (r < 0)
@@ -1157,13 +1175,13 @@ int bus_set_address_user(sd_bus *b) {
return -ENOMEM;
#ifdef ENABLE_KDBUS
- (void) asprintf(&b->address, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT, getuid(), ee);
+ (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, getuid(), ee);
#else
- (void) asprintf(&b->address, UNIX_USER_BUS_FMT, ee);
+ (void) asprintf(&b->address, UNIX_USER_BUS_ADDRESS_FMT, ee);
#endif
} else {
#ifdef ENABLE_KDBUS
- (void) asprintf(&b->address, KERNEL_USER_BUS_FMT, getuid());
+ (void) asprintf(&b->address, KERNEL_USER_BUS_ADDRESS_FMT, getuid());
#else
return -ECONNREFUSED;
#endif
@@ -1265,6 +1283,7 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) {
bus->bus_client = true;
bus->trusted = false;
+ bus->is_system = true;
r = sd_bus_start(bus);
if (r < 0)
@@ -1317,6 +1336,7 @@ _public_ int sd_bus_open_system_container(sd_bus **ret, const char *machine) {
bus->bus_client = true;
bus->trusted = false;
+ bus->is_system = true;
r = sd_bus_start(bus);
if (r < 0)
@@ -1422,18 +1442,18 @@ _public_ int sd_bus_can_send(sd_bus *bus, char type) {
return bus_type_is_valid(type);
}
-_public_ int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *server_id) {
+_public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
int r;
assert_return(bus, -EINVAL);
- assert_return(server_id, -EINVAL);
+ assert_return(id, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
r = bus_ensure_running(bus);
if (r < 0)
return r;
- *server_id = bus->server_id;
+ *id = bus->server_id;
return 0;
}
@@ -2487,6 +2507,15 @@ null_message:
return r;
}
+static void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
+ assert(bus);
+ assert(m);
+
+ m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
+ m->creds.well_known_names_local = true;
+ m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+}
+
static int process_closing(sd_bus *bus, sd_bus_message **ret) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
struct reply_callback *c;
@@ -2555,7 +2584,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) {
if (r < 0)
return r;
- m->sender = "org.freedesktop.DBus.Local";
+ bus_message_set_sender_local(bus, m);
r = bus_seal_synthetic_message(bus, m);
if (r < 0)
@@ -3015,7 +3044,7 @@ static int attach_io_events(sd_bus *bus) {
if (r < 0)
return r;
- r = sd_event_source_set_name(bus->input_io_event_source, "bus-input");
+ r = sd_event_source_set_description(bus->input_io_event_source, "bus-input");
} else
r = sd_event_source_set_io_fd(bus->input_io_event_source, bus->input_fd);
@@ -3034,7 +3063,7 @@ static int attach_io_events(sd_bus *bus) {
if (r < 0)
return r;
- r = sd_event_source_set_name(bus->input_io_event_source, "bus-output");
+ r = sd_event_source_set_description(bus->input_io_event_source, "bus-output");
} else
r = sd_event_source_set_io_fd(bus->output_io_event_source, bus->output_fd);
@@ -3087,7 +3116,7 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = sd_event_source_set_name(bus->time_event_source, "bus-time");
+ r = sd_event_source_set_description(bus->time_event_source, "bus-time");
if (r < 0)
goto fail;
@@ -3095,7 +3124,7 @@ _public_ int sd_bus_attach_event(sd_bus *bus, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = sd_event_source_set_name(bus->quit_event_source, "bus-exit");
+ r = sd_event_source_set_description(bus->quit_event_source, "bus-exit");
if (r < 0)
goto fail;
@@ -3322,12 +3351,13 @@ _public_ int sd_bus_try_close(sd_bus *bus) {
return 0;
}
-_public_ int sd_bus_get_name(sd_bus *bus, const char **name) {
+_public_ int sd_bus_get_description(sd_bus *bus, const char **description) {
assert_return(bus, -EINVAL);
- assert_return(name, -EINVAL);
+ assert_return(description, -EINVAL);
+ assert_return(bus->description, -ENXIO);
assert_return(!bus_pid_changed(bus), -ECHILD);
- *name = bus->connection_name;
+ *description = bus->description;
return 0;
}
@@ -3348,3 +3378,101 @@ int bus_get_root_path(sd_bus *bus) {
return r;
}
+
+_public_ int sd_bus_get_scope(sd_bus *bus, const char **scope) {
+ int r;
+
+ assert_return(bus, -EINVAL);
+ assert_return(scope, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (bus->is_kernel) {
+ _cleanup_free_ char *n = NULL;
+ const char *dash;
+
+ r = bus_kernel_get_bus_name(bus, &n);
+ if (r < 0)
+ return r;
+
+ if (streq(n, "0-system")) {
+ *scope = "system";
+ return 0;
+ }
+
+ dash = strchr(n, '-');
+ if (streq_ptr(dash, "-user")) {
+ *scope = "user";
+ return 0;
+ }
+ }
+
+ if (bus->is_user) {
+ *scope = "user";
+ return 0;
+ }
+
+ if (bus->is_system) {
+ *scope = "system";
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+_public_ int sd_bus_get_address(sd_bus *bus, const char **address) {
+
+ assert_return(bus, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ if (bus->address) {
+ *address = bus->address;
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *mask) {
+ assert_return(bus, -EINVAL);
+ assert_return(mask, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ *mask = bus->creds_mask;
+ return 0;
+}
+
+int sd_bus_is_bus_client(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->bus_client;
+}
+
+int sd_bus_is_server(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->is_server;
+}
+
+int sd_bus_is_anonymous(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->anonymous_auth;
+}
+
+int sd_bus_is_trusted(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return bus->trusted;
+}
+
+int sd_bus_is_monitor(sd_bus *bus) {
+ assert_return(bus, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ return !!(bus->hello_flags & KDBUS_HELLO_MONITOR);
+}
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index d5903f41d5..06edd621e4 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -53,10 +53,8 @@ static int object_callback(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
log_info("Invoked Foobar() on %s", sd_bus_message_get_path(m));
r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
return 1;
}
@@ -74,19 +72,19 @@ static int server_init(sd_bus **_bus) {
r = sd_bus_open_user(&bus);
if (r < 0) {
- log_error("Failed to connect to user bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to connect to user bus: %m");
goto fail;
}
- r = sd_bus_get_server_id(bus, &id);
+ r = sd_bus_get_bus_id(bus, &id);
if (r < 0) {
- log_error("Failed to get server ID: %s", strerror(-r));
+ log_error_errno(r, "Failed to get server ID: %m");
goto fail;
}
r = sd_bus_get_unique_name(bus, &unique);
if (r < 0) {
- log_error("Failed to get unique name: %s", strerror(-r));
+ log_error_errno(r, "Failed to get unique name: %m");
goto fail;
}
@@ -96,25 +94,25 @@ static int server_init(sd_bus **_bus) {
r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
if (r < 0) {
- log_error("Failed to acquire name: %s", strerror(-r));
+ log_error_errno(r, "Failed to acquire name: %m");
goto fail;
}
r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
if (r < 0) {
- log_error("Failed to add object: %s", strerror(-r));
+ log_error_errno(r, "Failed to add object: %m");
goto fail;
}
r = sd_bus_add_match(bus, NULL, "type='signal',interface='foo.bar',member='Notify'", match_callback, NULL);
if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
+ log_error_errno(r, "Failed to add match: %m");
goto fail;
}
r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
+ log_error_errno(r, "Failed to add match: %m");
goto fail;
}
@@ -141,14 +139,14 @@ static int server(sd_bus *bus) {
r = sd_bus_process(bus, &m);
if (r < 0) {
- log_error("Failed to process requests: %s", strerror(-r));
+ log_error_errno(r, "Failed to process requests: %m");
goto fail;
}
if (r == 0) {
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0) {
- log_error("Failed to wait: %s", strerror(-r));
+ log_error_errno(r, "Failed to wait: %m");
goto fail;
}
@@ -173,7 +171,7 @@ static int server(sd_bus *bus) {
r = sd_bus_message_read(m, "s", &hello);
if (r < 0) {
- log_error("Failed to get parameter: %s", strerror(-r));
+ log_error_errno(r, "Failed to get parameter: %m");
goto fail;
}
@@ -187,14 +185,14 @@ static int server(sd_bus *bus) {
r = sd_bus_reply_method_return(m, "s", lowercase);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
r = sd_bus_reply_method_return(m, NULL);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
@@ -203,7 +201,7 @@ static int server(sd_bus *bus) {
r = sd_bus_reply_method_return(m, NULL);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
@@ -214,7 +212,7 @@ static int server(sd_bus *bus) {
r = sd_bus_reply_method_return(m, NULL);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
@@ -224,21 +222,21 @@ static int server(sd_bus *bus) {
r = sd_bus_message_read(m, "h", &fd);
if (r < 0) {
- log_error("Failed to get parameter: %s", strerror(-r));
+ log_error_errno(r, "Failed to get parameter: %m");
goto fail;
}
log_info("Received fd=%d", fd);
if (write(fd, &x, 1) < 0) {
- log_error("Failed to write to fd: %m");
+ log_error_errno(errno, "Failed to write to fd: %m");
safe_close(fd);
goto fail;
}
r = sd_bus_reply_method_return(m, NULL);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
@@ -248,7 +246,7 @@ static int server(sd_bus *bus) {
m,
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
}
@@ -276,7 +274,7 @@ static void* client1(void*p) {
r = sd_bus_open_user(&bus);
if (r < 0) {
- log_error("Failed to connect to user bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to connect to user bus: %m");
goto finish;
}
@@ -291,20 +289,20 @@ static void* client1(void*p) {
"s",
"HELLO");
if (r < 0) {
- log_error("Failed to issue method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to issue method call: %m");
goto finish;
}
r = sd_bus_message_read(reply, "s", &hello);
if (r < 0) {
- log_error("Failed to get string: %s", strerror(-r));
+ log_error_errno(r, "Failed to get string: %m");
goto finish;
}
assert(streq(hello, "hello"));
if (pipe2(pp, O_CLOEXEC|O_NONBLOCK) < 0) {
- log_error("Failed to allocate pipe: %m");
+ log_error_errno(errno, "Failed to allocate pipe: %m");
r = -errno;
goto finish;
}
@@ -322,7 +320,7 @@ static void* client1(void*p) {
"h",
pp[1]);
if (r < 0) {
- log_error("Failed to issue method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to issue method call: %m");
goto finish;
}
@@ -346,7 +344,7 @@ finish:
"org.freedesktop.systemd.test",
"ExitClient1");
if (r < 0)
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
else
sd_bus_send(bus, q, NULL);
@@ -380,7 +378,7 @@ static void* client2(void*p) {
r = sd_bus_open_user(&bus);
if (r < 0) {
- log_error("Failed to connect to user bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to connect to user bus: %m");
goto finish;
}
@@ -392,7 +390,7 @@ static void* client2(void*p) {
"org.object.test",
"Foobar");
if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
goto finish;
}
@@ -412,7 +410,7 @@ static void* client2(void*p) {
"foo.bar",
"Notify");
if (r < 0) {
- log_error("Failed to allocate signal: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate signal: %m");
goto finish;
}
@@ -433,7 +431,7 @@ static void* client2(void*p) {
"org.freedesktop.DBus.Peer",
"GetMachineId");
if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
goto finish;
}
@@ -445,7 +443,7 @@ static void* client2(void*p) {
r = sd_bus_message_read(reply, "s", &mid);
if (r < 0) {
- log_error("Failed to parse machine ID: %s", strerror(-r));
+ log_error_errno(r, "Failed to parse machine ID: %m");
goto finish;
}
@@ -462,7 +460,7 @@ static void* client2(void*p) {
"org.freedesktop.systemd.test",
"Slow");
if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
goto finish;
}
@@ -486,7 +484,7 @@ static void* client2(void*p) {
"org.freedesktop.systemd.test",
"Slow");
if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
goto finish;
}
@@ -499,13 +497,13 @@ static void* client2(void*p) {
while (!quit) {
r = sd_bus_process(bus, NULL);
if (r < 0) {
- log_error("Failed to process requests: %s", strerror(-r));
+ log_error_errno(r, "Failed to process requests: %m");
goto finish;
}
if (r == 0) {
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0) {
- log_error("Failed to wait: %s", strerror(-r));
+ log_error_errno(r, "Failed to wait: %m");
goto finish;
}
}
@@ -525,7 +523,7 @@ finish:
"org.freedesktop.systemd.test",
"ExitClient2");
if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate method call: %m");
goto finish;
}
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index c4894e8696..ff2602ba34 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -31,7 +31,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
assert_se(r >= 0);
- bus_creds_dump(creds, NULL);
+ bus_creds_dump(creds, NULL, true);
creds = sd_bus_creds_unref(creds);
@@ -39,7 +39,7 @@ int main(int argc, char *argv[]) {
if (r != -EACCES) {
assert_se(r >= 0);
putchar('\n');
- bus_creds_dump(creds, NULL);
+ bus_creds_dump(creds, NULL, true);
}
return 0;
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index b78be5499c..463fc81c75 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -22,9 +22,10 @@
#include "sd-bus.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "errno-list.h"
+#include "bus-common-errors.h"
-int main(int argc, char *argv[]) {
-
+static void test_error(void) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL;
const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error");
const sd_bus_error temporarily_const_error = {
@@ -110,6 +111,92 @@ int main(int argc, char *argv[]) {
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR));
assert_se(sd_bus_error_get_errno(&error) == EIO);
assert_se(sd_bus_error_is_set(&error));
+}
+
+extern const sd_bus_error_map __start_BUS_ERROR_MAP[];
+extern const sd_bus_error_map __stop_BUS_ERROR_MAP[];
+
+static void dump_mapping_table(void) {
+ const sd_bus_error_map *m;
+
+ printf("----- errno mappings ------\n");
+ m = __start_BUS_ERROR_MAP;
+ while (m < __stop_BUS_ERROR_MAP) {
+
+ if (m->code == BUS_ERROR_MAP_END_MARKER) {
+ m = ALIGN8_PTR(m+1);
+ continue;
+ }
+
+ printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code)));
+ m ++;
+ }
+ printf("---------------------------\n");
+}
+
+static void test_errno_mapping_standard(void) {
+ assert_se(sd_bus_error_set(NULL, "System.Error.EUCLEAN", NULL) == -EUCLEAN);
+ assert_se(sd_bus_error_set(NULL, "System.Error.EBUSY", NULL) == -EBUSY);
+ assert_se(sd_bus_error_set(NULL, "System.Error.EINVAL", NULL) == -EINVAL);
+ assert_se(sd_bus_error_set(NULL, "System.Error.WHATSIT", NULL) == -EIO);
+}
+
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map test_errors[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error", 5),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-2", 52),
+ SD_BUS_ERROR_MAP_END
+};
+
+BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map test_errors2[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-3", 33),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-4", 44),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-33", 333),
+ SD_BUS_ERROR_MAP_END
+};
+
+static const sd_bus_error_map test_errors3[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-88", 888),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-99", 999),
+ SD_BUS_ERROR_MAP_END
+};
+
+static const sd_bus_error_map test_errors4[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-77", 777),
+ SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-78", 778),
+ SD_BUS_ERROR_MAP_END
+};
+
+static void test_errno_mapping_custom(void) {
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-x", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-33", NULL) == -333);
+
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-88", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-99", NULL) == -EIO);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-77", NULL) == -EIO);
+
+ assert_se(sd_bus_error_add_map(test_errors3) > 0);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-88", NULL) == -888);
+ assert_se(sd_bus_error_add_map(test_errors4) > 0);
+ assert_se(sd_bus_error_add_map(test_errors4) == 0);
+ assert_se(sd_bus_error_add_map(test_errors3) == 0);
+
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-99", NULL) == -999);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-77", NULL) == -777);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-78", NULL) == -778);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52);
+ assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-y", NULL) == -EIO);
+
+ assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT);
+}
+
+int main(int argc, char *argv[]) {
+ dump_mapping_table();
+
+ test_error();
+ test_errno_mapping_standard();
+ test_errno_mapping_custom();
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c
index 9226858825..56df5d0b48 100644
--- a/src/libsystemd/sd-bus/test-bus-gvariant.c
+++ b/src/libsystemd/sd-bus/test-bus-gvariant.c
@@ -175,14 +175,14 @@ static void test_marshal(void) {
}
#endif
- assert_se(bus_message_dump(m, NULL, true) >= 0);
+ assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
assert_se(bus_message_get_blob(m, &blob, &sz) >= 0);
assert_se(bus_message_from_malloc(bus, blob, sz, NULL, 0, NULL, NULL, &n) >= 0);
blob = NULL;
- assert_se(bus_message_dump(n, NULL, true) >= 0);
+ assert_se(bus_message_dump(n, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
m = sd_bus_message_unref(m);
@@ -191,7 +191,7 @@ static void test_marshal(void) {
assert_se(sd_bus_message_append(m, "as", 0) >= 0);
assert_se(bus_message_seal(m, 4712, 0) >= 0);
- assert_se(bus_message_dump(m, NULL, true) >= 0);
+ assert_se(bus_message_dump(m, NULL, BUS_MESSAGE_DUMP_WITH_HEADER) >= 0);
}
int main(int argc, char *argv[]) {
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
index 5ee6eea0e8..071b7e0cf9 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
@@ -32,6 +32,7 @@ static void test_one(
const char *path,
const char *interface,
const char *member,
+ bool as_list,
const char *arg0,
const char *match,
bool good) {
@@ -76,7 +77,11 @@ static void test_one(
assert_se(r >= 0);
log_debug("signal");
- r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
+
+ if (as_list)
+ r = sd_bus_emit_signal(a, path, interface, member, "as", 1, arg0);
+ else
+ r = sd_bus_emit_signal(a, path, interface, member, "s", arg0);
assert_se(r >= 0);
r = sd_bus_process(b, &m);
@@ -89,27 +94,29 @@ static void test_one(
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/tuut'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "interface='waldo.com'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Piep'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "member='Pi_ep'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foobar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "arg0='foo_bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
-
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path='/foo/bar/waldo/quux'", false);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar/waldo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo/bar'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/foo'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/'", true);
- test_one("/foo/bar/waldo", "waldo.com", "Piep", "foobar", "path_namespace='/quux'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/tuut'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "interface='waldo.com'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Piep'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "member='Pi_ep'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "arg0='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", true, "foobar", "arg0='foo_bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo',interface='waldo.com',member='Piep',arg0='foobar2'", false);
+
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path='/foo/bar/waldo/quux'", false);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar/waldo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo/bar'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/foo'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/'", true);
+ test_one("/foo/bar/waldo", "waldo.com", "Piep", false, "foobar", "path_namespace='/quux'", false);
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
index 7bb8b0a540..3aec568229 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel.c
@@ -33,7 +33,7 @@
int main(int argc, char *argv[]) {
_cleanup_close_ int bus_ref = -1;
- _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL;
+ _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *bname = NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *ua = NULL, *ub = NULL, *the_string = NULL;
@@ -45,6 +45,8 @@ int main(int argc, char *argv[]) {
assert_se(asprintf(&name, "deine-mutter-%u", (unsigned) getpid()) >= 0);
+ bus_kernel_fix_attach_mask();
+
bus_ref = bus_kernel_create_bus(name, false, &bus_name);
if (bus_ref == -ENOENT)
return EXIT_TEST_SKIP;
@@ -60,7 +62,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_new(&b);
assert_se(r >= 0);
- r = sd_bus_set_name(a, "a");
+ r = sd_bus_set_description(a, "a");
assert_se(r >= 0);
r = sd_bus_set_address(a, address);
@@ -70,10 +72,10 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
assert_se(sd_bus_negotiate_timestamp(a, 1) >= 0);
- assert_se(sd_bus_negotiate_creds(a, _SD_BUS_CREDS_ALL) >= 0);
+ assert_se(sd_bus_negotiate_creds(a, true, _SD_BUS_CREDS_ALL) >= 0);
- assert_se(sd_bus_negotiate_timestamp(b, 1) >= 0);
- assert_se(sd_bus_negotiate_creds(b, _SD_BUS_CREDS_ALL) >= 0);
+ assert_se(sd_bus_negotiate_timestamp(b, 0) >= 0);
+ assert_se(sd_bus_negotiate_creds(b, true, 0) >= 0);
r = sd_bus_start(a);
assert_se(r >= 0);
@@ -81,11 +83,14 @@ int main(int argc, char *argv[]) {
r = sd_bus_start(b);
assert_se(r >= 0);
+ assert_se(sd_bus_negotiate_timestamp(b, 1) >= 0);
+ assert_se(sd_bus_negotiate_creds(b, true, _SD_BUS_CREDS_ALL) >= 0);
+
r = sd_bus_get_unique_name(a, &ua);
assert_se(r >= 0);
printf("unique a: %s\n", ua);
- r = sd_bus_get_name(a, &nn);
+ r = sd_bus_get_description(a, &nn);
assert_se(r >= 0);
printf("name of a: %s\n", nn);
@@ -93,10 +98,13 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
printf("unique b: %s\n", ub);
- r = sd_bus_get_name(b, &nn);
+ r = sd_bus_get_description(b, &nn);
assert_se(r >= 0);
printf("name of b: %s\n", nn);
+ assert_se(bus_kernel_get_bus_name(b, &bname) >= 0);
+ assert_se(endswith(bname, name));
+
r = sd_bus_call_method(a, "this.doesnt.exist", "/foo", "meh.mah", "muh", &error, NULL, "s", "yayayay");
assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_SERVICE_UNKNOWN));
assert_se(r == -EHOSTUNREACH);
@@ -117,7 +125,7 @@ int main(int argc, char *argv[]) {
assert_se(r > 0);
assert_se(m);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
assert_se(sd_bus_message_rewind(m, true) >= 0);
r = sd_bus_message_read(m, "s", &the_string);
@@ -154,7 +162,7 @@ int main(int argc, char *argv[]) {
assert_se(r > 0);
assert_se(m);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
assert_se(sd_bus_message_rewind(m, true) >= 0);
if (sd_bus_message_is_method_call(m, "an.inter.face", "AMethod")) {
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index 9532112524..8cefc7a154 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -148,10 +148,10 @@ int main(int argc, char *argv[]) {
r = bus_message_seal(m, 4711, 0);
assert_se(r >= 0);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
ms = open_memstream(&first, &first_size);
- bus_message_dump(m, ms, false);
+ bus_message_dump(m, ms, 0);
fflush(ms);
assert_se(!ferror(ms));
@@ -201,11 +201,11 @@ int main(int argc, char *argv[]) {
r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, NULL, NULL, &m);
assert_se(r >= 0);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
fclose(ms);
ms = open_memstream(&second, &second_size);
- bus_message_dump(m, ms, false);
+ bus_message_dump(m, ms, 0);
fflush(ms);
assert_se(!ferror(ms));
assert_se(first_size == second_size);
@@ -285,7 +285,7 @@ int main(int argc, char *argv[]) {
fclose(ms);
ms = open_memstream(&third, &third_size);
- bus_message_dump(copy, ms, false);
+ bus_message_dump(copy, ms, 0);
fflush(ms);
assert_se(!ferror(ms));
diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c
index 6c5d35b3d3..7133117038 100644
--- a/src/libsystemd/sd-bus/test-bus-match.c
+++ b/src/libsystemd/sd-bus/test-bus-match.c
@@ -33,8 +33,9 @@
static bool mask[32];
static int filter(sd_bus *b, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
- log_info("Ran %i", PTR_TO_INT(userdata));
- mask[PTR_TO_INT(userdata)] = true;
+ log_info("Ran %u", PTR_TO_UINT(userdata));
+ assert(PTR_TO_UINT(userdata) < ELEMENTSOF(mask));
+ mask[PTR_TO_UINT(userdata)] = true;
return 0;
}
@@ -85,9 +86,9 @@ int main(int argc, char *argv[]) {
};
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_bus_unref_ sd_bus *bus = NULL;
+ _cleanup_bus_close_unref_ sd_bus *bus = NULL;
enum bus_match_node_type i;
- sd_bus_slot slots[15];
+ sd_bus_slot slots[19];
int r;
r = sd_bus_open_system(&bus);
@@ -108,16 +109,20 @@ int main(int argc, char *argv[]) {
assert_se(match_add(slots, &root, "arg1='two'", 12) >= 0);
assert_se(match_add(slots, &root, "member='waldo',arg2path='/prefix/'", 13) >= 0);
assert_se(match_add(slots, &root, "member=waldo,path='/foo/bar',arg3namespace='prefix'", 14) >= 0);
+ assert_se(match_add(slots, &root, "arg4='pi'", 15) >= 0);
+ assert_se(match_add(slots, &root, "arg4='pa'", 16) >= 0);
+ assert_se(match_add(slots, &root, "arg4='po'", 17) >= 0);
+ assert_se(match_add(slots, &root, "arg4='pu'", 18) >= 0);
bus_match_dump(&root, 0);
assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0);
- assert_se(sd_bus_message_append(m, "ssss", "one", "two", "/prefix/three", "prefix.four") >= 0);
+ assert_se(sd_bus_message_append(m, "ssssas", "one", "two", "/prefix/three", "prefix.four", 3, "pi", "pa", "po") >= 0);
assert_se(bus_message_seal(m, 1, 0) >= 0);
zero(mask);
assert_se(bus_match_run(NULL, &root, m) == 0);
- assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14 }, 8));
+ assert_se(mask_contains((unsigned[]) { 9, 8, 7, 5, 10, 12, 13, 14, 15, 16, 17 }, 11));
assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0);
assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0);
@@ -126,7 +131,7 @@ int main(int argc, char *argv[]) {
zero(mask);
assert_se(bus_match_run(NULL, &root, m) == 0);
- assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7 }, 6));
+ assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7, 15, 16, 17 }, 9));
for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) {
char buf[32];
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index e7a445f3cb..06b8904f13 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -237,14 +237,14 @@ static void *server(void *p) {
r = sd_bus_process(bus, NULL);
if (r < 0) {
- log_error("Failed to process requests: %s", strerror(-r));
+ log_error_errno(r, "Failed to process requests: %m");
goto fail;
}
if (r == 0) {
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0) {
- log_error("Failed to wait: %s", strerror(-r));
+ log_error_errno(r, "Failed to wait: %m");
goto fail;
}
@@ -385,7 +385,7 @@ static int client(struct context *c) {
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "");
assert_se(r >= 0);
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
@@ -403,7 +403,7 @@ static int client(struct context *c) {
r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, "");
assert_se(r >= 0);
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
@@ -415,7 +415,7 @@ static int client(struct context *c) {
assert_se(r > 0);
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
@@ -427,7 +427,7 @@ static int client(struct context *c) {
assert_se(r > 0);
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged"));
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
@@ -439,7 +439,7 @@ static int client(struct context *c) {
assert_se(r > 0);
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded"));
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
@@ -451,7 +451,7 @@ static int client(struct context *c) {
assert_se(r > 0);
assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved"));
- bus_message_dump(reply, stdout, true);
+ bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_unref(reply);
reply = NULL;
diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c
index 96d6298336..5f807c3b1e 100644
--- a/src/libsystemd/sd-bus/test-bus-server.c
+++ b/src/libsystemd/sd-bus/test-bus-server.c
@@ -65,14 +65,14 @@ static void *server(void *p) {
r = sd_bus_process(bus, &m);
if (r < 0) {
- log_error("Failed to process requests: %s", strerror(-r));
+ log_error_errno(r, "Failed to process requests: %m");
goto fail;
}
if (r == 0) {
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0) {
- log_error("Failed to wait: %s", strerror(-r));
+ log_error_errno(r, "Failed to wait: %m");
goto fail;
}
@@ -90,7 +90,7 @@ static void *server(void *p) {
r = sd_bus_message_new_method_return(m, &reply);
if (r < 0) {
- log_error("Failed to allocate return: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate return: %m");
goto fail;
}
@@ -102,7 +102,7 @@ static void *server(void *p) {
&reply,
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
if (r < 0) {
- log_error("Failed to allocate return: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate return: %m");
goto fail;
}
}
@@ -110,7 +110,7 @@ static void *server(void *p) {
if (reply) {
r = sd_bus_send(bus, reply, NULL);
if (r < 0) {
- log_error("Failed to send reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send reply: %m");
goto fail;
}
}
@@ -146,10 +146,8 @@ static int client(struct context *c) {
"/",
"org.freedesktop.systemd.test",
"Exit");
- if (r < 0) {
- log_error("Failed to allocate method call: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate method call: %m");
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
index e3010fbf7e..a054f74bf3 100644
--- a/src/libsystemd/sd-bus/test-bus-zero-copy.c
+++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c
@@ -24,7 +24,7 @@
#include "util.h"
#include "log.h"
-#include "memfd.h"
+#include "memfd-util.h"
#include "sd-bus.h"
#include "bus-message.h"
@@ -48,6 +48,7 @@ int main(int argc, char *argv[]) {
uint32_t u32;
size_t i, l;
char *s;
+ _cleanup_close_ int sfd = -1;
log_set_max_level(LOG_DEBUG);
@@ -107,7 +108,7 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
assert_se(sz == STRING_SIZE);
- r = sd_bus_message_append_string_memfd(m, f);
+ r = sd_bus_message_append_string_memfd(m, f, 0, (uint64_t) -1);
assert_se(r >= 0);
close(f);
@@ -124,7 +125,7 @@ int main(int argc, char *argv[]) {
assert_se(r >= 0);
assert_se(sz == SECOND_ARRAY);
- r = sd_bus_message_append_array_memfd(m, 'y', f);
+ r = sd_bus_message_append_array_memfd(m, 'y', f, 0, (uint64_t) -1);
assert_se(r >= 0);
close(f);
@@ -135,10 +136,15 @@ int main(int argc, char *argv[]) {
r = sd_bus_message_append(m, "u", 4711);
assert_se(r >= 0);
+ assert_se((sfd = memfd_new_and_map(NULL, 6, (void**) &p)) >= 0);
+ memcpy(p, "abcd\0", 6);
+ munmap(p, 6);
+ assert_se(sd_bus_message_append_string_memfd(m, sfd, 1, 4) >= 0);
+
r = bus_message_seal(m, 55, 99*USEC_PER_SEC);
assert_se(r >= 0);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
r = sd_bus_send(b, m, NULL);
assert_se(r >= 0);
@@ -148,7 +154,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_process(a, &m);
assert_se(r > 0);
- bus_message_dump(m, stdout, true);
+ bus_message_dump(m, stdout, BUS_MESSAGE_DUMP_WITH_HEADER);
sd_bus_message_rewind(m, true);
r = sd_bus_message_enter_container(m, 'r', "aysay");
@@ -188,6 +194,10 @@ int main(int argc, char *argv[]) {
assert_se(r > 0);
assert_se(u32 == 4711);
+ r = sd_bus_message_read(m, "s", &s);
+ assert_se(r > 0);
+ assert_se(streq_ptr(s, "bcd"));
+
sd_bus_message_unref(m);
sd_bus_unref(a);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 80a2ae97e8..f9fa54d2e8 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -66,7 +66,7 @@ struct sd_event_source {
void *userdata;
sd_event_handler_t prepare;
- char *name;
+ char *description;
EventSourceType type:5;
int enabled:3;
@@ -737,7 +737,7 @@ static void source_free(sd_event_source *s) {
assert(s);
source_disconnect(s);
- free(s->name);
+ free(s->description);
free(s);
}
@@ -1031,6 +1031,9 @@ _public_ int sd_event_add_signal(
}
}
+ /* Use the signal name as description for the event source by default */
+ (void) sd_event_source_set_description(s, signal_to_string(sig));
+
if (ret)
*ret = s;
@@ -1253,18 +1256,20 @@ _public_ sd_event_source* sd_event_source_unref(sd_event_source *s) {
return NULL;
}
-_public_ int sd_event_source_set_name(sd_event_source *s, const char *name) {
+_public_ int sd_event_source_set_description(sd_event_source *s, const char *description) {
assert_return(s, -EINVAL);
+ assert_return(!event_pid_changed(s->event), -ECHILD);
- return free_and_strdup(&s->name, name);
+ return free_and_strdup(&s->description, description);
}
-_public_ int sd_event_source_get_name(sd_event_source *s, const char **name) {
+_public_ int sd_event_source_get_description(sd_event_source *s, const char **description) {
assert_return(s, -EINVAL);
- assert_return(name, -EINVAL);
-
- *name = s->name;
+ assert_return(description, -EINVAL);
+ assert_return(s->description, -ENXIO);
+ assert_return(!event_pid_changed(s->event), -ECHILD);
+ *description = s->description;
return 0;
}
@@ -2152,10 +2157,10 @@ static int source_dispatch(sd_event_source *s) {
s->dispatching = false;
if (r < 0) {
- if (s->name)
- log_debug("Event source '%s' returned error, disabling: %s", s->name, strerror(-r));
+ if (s->description)
+ log_debug_errno(r, "Event source '%s' returned error, disabling: %m", s->description);
else
- log_debug("Event source %p returned error, disabling: %s", s, strerror(-r));
+ log_debug_errno(r, "Event source %p returned error, disabling: %m", s);
}
if (s->n_ref == 0)
@@ -2190,10 +2195,10 @@ static int event_prepare(sd_event *e) {
s->dispatching = false;
if (r < 0) {
- if (s->name)
- log_debug("Prepare callback of event source '%s' returned error, disabling: %s", s->name, strerror(-r));
+ if (s->description)
+ log_debug_errno(r, "Prepare callback of event source '%s' returned error, disabling: %m", s->description);
else
- log_debug("Prepare callback of event source %p returned error, disabling: %s", s, strerror(-r));
+ log_debug_errno(r, "Prepare callback of event source %p returned error, disabling: %m", s);
}
if (s->n_ref == 0)
diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c
index c6c3bfb0ea..a9dc9313a6 100644
--- a/src/libsystemd/sd-resolve/test-resolve.c
+++ b/src/libsystemd/sd-resolve/test-resolve.c
@@ -43,7 +43,7 @@ static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrin
assert(q);
if (ret != 0) {
- log_error("getaddrinfo error: %s %i\n", gai_strerror(ret), ret);
+ log_error("getaddrinfo error: %s %i", gai_strerror(ret), ret);
return 0;
}
@@ -63,7 +63,7 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c
assert(q);
if (ret != 0) {
- log_error("getnameinfo error: %s %i\n", gai_strerror(ret), ret);
+ log_error("getnameinfo error: %s %i", gai_strerror(ret), ret);
return 0;
}
@@ -80,12 +80,12 @@ static int res_handler(sd_resolve_query *q, int ret, unsigned char *answer, void
assert(q);
if (ret < 0) {
- log_error("res_query() error: %s %i\n", strerror(errno), errno);
+ log_error("res_query() error: %s %i", strerror(errno), errno);
return 0;
}
if (ret == 0) {
- log_error("No reply for SRV lookup\n");
+ log_error("No reply for SRV lookup");
return 0;
}
@@ -146,18 +146,18 @@ int main(int argc, char *argv[]) {
/* Make a name -> address query */
r = sd_resolve_getaddrinfo(resolve, &q1, argc >= 2 ? argv[1] : "www.heise.de", NULL, &hints, getaddrinfo_handler, NULL);
if (r < 0)
- log_error("sd_resolve_getaddrinfo(): %s\n", strerror(-r));
+ log_error_errno(r, "sd_resolve_getaddrinfo(): %m");
/* Make an address -> name query */
sa.sin_addr.s_addr = inet_addr(argc >= 3 ? argv[2] : "193.99.144.71");
r = sd_resolve_getnameinfo(resolve, &q2, (struct sockaddr*) &sa, sizeof(sa), 0, SD_RESOLVE_GET_BOTH, getnameinfo_handler, NULL);
if (r < 0)
- log_error("sd_resolve_getnameinfo(): %s\n", strerror(-r));
+ log_error_errno(r, "sd_resolve_getnameinfo(): %m");
/* Make a res_query() call */
r = sd_resolve_res_query(resolve, &q3, "_xmpp-client._tcp.gmail.com", C_IN, T_SRV, res_handler, NULL);
if (r < 0)
- log_error("sd_resolve_res_query(): %s\n", strerror(-r));
+ log_error_errno(r, "sd_resolve_res_query(): %m");
/* Wait until the three queries are completed */
while (sd_resolve_query_is_done(q1) == 0 ||
@@ -166,7 +166,7 @@ int main(int argc, char *argv[]) {
r = sd_resolve_wait(resolve, (uint64_t) -1);
if (r < 0) {
- log_error("sd_resolve_wait(): %s\n", strerror(-r));
+ log_error_errno(r, "sd_resolve_wait(): %m");
assert_not_reached("sd_resolve_wait() failed");
}
}
diff --git a/src/libsystemd/sd-rtnl/local-addresses.c b/src/libsystemd/sd-rtnl/local-addresses.c
index c5508856c8..31bfa06066 100644
--- a/src/libsystemd/sd-rtnl/local-addresses.c
+++ b/src/libsystemd/sd-rtnl/local-addresses.c
@@ -30,14 +30,19 @@ static int address_compare(const void *_a, const void *_b) {
/* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
+ if (a->family == AF_INET && b->family == AF_INET6)
+ return -1;
+ if (a->family == AF_INET6 && b->family == AF_INET)
+ return 1;
+
if (a->scope < b->scope)
return -1;
if (a->scope > b->scope)
return 1;
- if (a->family == AF_INET && b->family == AF_INET6)
+ if (a->metric < b->metric)
return -1;
- if (a->family == AF_INET6 && b->family == AF_INET)
+ if (a->metric > b->metric)
return 1;
if (a->ifindex < b->ifindex)
@@ -45,10 +50,10 @@ static int address_compare(const void *_a, const void *_b) {
if (a->ifindex > b->ifindex)
return 1;
- return 0;
+ return memcmp(&a->address, &b->address, FAMILY_ADDRESS_SIZE(a->family));
}
-int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
+int local_addresses(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_free_ struct local_address *list = NULL;
@@ -66,7 +71,7 @@ int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
return r;
}
- r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
+ r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, af);
if (r < 0)
return r;
@@ -78,7 +83,7 @@ int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
struct local_address *a;
unsigned char flags;
uint16_t type;
- int ifi;
+ int ifi, family;
r = sd_rtnl_message_get_errno(m);
if (r < 0)
@@ -87,25 +92,28 @@ int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
r = sd_rtnl_message_get_type(m, &type);
if (r < 0)
return r;
-
if (type != RTM_NEWADDR)
continue;
r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
if (r < 0)
return r;
+ if (ifindex > 0 && ifi != ifindex)
+ continue;
- if (ifindex != 0 && ifi != ifindex)
+ r = sd_rtnl_message_addr_get_family(m, &family);
+ if (r < 0)
+ return r;
+ if (af != AF_UNSPEC && af != family)
continue;
r = sd_rtnl_message_addr_get_flags(m, &flags);
if (r < 0)
return r;
-
if (flags & IFA_F_DEPRECATED)
continue;
- if (!GREEDY_REALLOC(list, n_allocated, n_list+1))
+ if (!GREEDY_REALLOC0(list, n_allocated, n_list+1))
return -ENOMEM;
a = list + n_list;
@@ -117,11 +125,7 @@ int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
continue;
- r = sd_rtnl_message_addr_get_family(m, &a->family);
- if (r < 0)
- return r;
-
- switch (a->family) {
+ switch (family) {
case AF_INET:
r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
@@ -146,11 +150,123 @@ int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
}
a->ifindex = ifi;
+ a->family = family;
n_list++;
};
- if (n_list)
+ if (n_list > 0)
+ qsort(list, n_list, sizeof(struct local_address), address_compare);
+
+ *ret = list;
+ list = NULL;
+
+ return (int) n_list;
+}
+
+int local_gateways(sd_rtnl *context, int ifindex, int af, struct local_address **ret) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+ _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+ _cleanup_free_ struct local_address *list = NULL;
+ sd_rtnl_message *m = NULL;
+ size_t n_list = 0, n_allocated = 0;
+ int r;
+
+ assert(ret);
+
+ if (context)
+ rtnl = sd_rtnl_ref(context);
+ else {
+ r = sd_rtnl_open(&rtnl, 0);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, af, RTPROT_UNSPEC);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_call(rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (m = reply; m; m = sd_rtnl_message_next(m)) {
+ struct local_address *a;
+ uint16_t type;
+ unsigned char dst_len, src_len;
+ uint32_t ifi;
+ int family;
+
+ r = sd_rtnl_message_get_errno(m);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_get_type(m, &type);
+ if (r < 0)
+ return r;
+ if (type != RTM_NEWROUTE)
+ continue;
+
+ /* We only care for default routes */
+ r = sd_rtnl_message_route_get_dst_prefixlen(m, &dst_len);
+ if (r < 0)
+ return r;
+ if (dst_len != 0)
+ continue;
+
+ r = sd_rtnl_message_route_get_src_prefixlen(m, &src_len);
+ if (r < 0)
+ return r;
+ if (src_len != 0)
+ continue;
+
+ r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
+ if (r < 0)
+ return r;
+ if (ifindex > 0 && (int) ifi != ifindex)
+ continue;
+
+ r = sd_rtnl_message_route_get_family(m, &family);
+ if (r < 0)
+ return r;
+ if (af != AF_UNSPEC && af != family)
+ continue;
+
+ if (!GREEDY_REALLOC0(list, n_allocated, n_list + 1))
+ return -ENOMEM;
+
+ a = list + n_list;
+
+ switch (family) {
+ case AF_INET:
+ r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &a->address.in);
+ if (r < 0)
+ continue;
+
+ break;
+ case AF_INET6:
+ r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &a->address.in6);
+ if (r < 0)
+ continue;
+
+ break;
+ default:
+ continue;
+ }
+
+ sd_rtnl_message_read_u32(m, RTA_PRIORITY, &a->metric);
+
+ a->ifindex = ifi;
+ a->family = family;
+
+ n_list++;
+ }
+
+ if (n_list > 0)
qsort(list, n_list, sizeof(struct local_address), address_compare);
*ret = list;
diff --git a/src/libsystemd/sd-rtnl/local-addresses.h b/src/libsystemd/sd-rtnl/local-addresses.h
index b1ed6341f6..ef7def530d 100644
--- a/src/libsystemd/sd-rtnl/local-addresses.h
+++ b/src/libsystemd/sd-rtnl/local-addresses.h
@@ -32,7 +32,10 @@
struct local_address {
int family, ifindex;
unsigned char scope;
+ uint32_t metric;
union in_addr_union address;
};
-int local_addresses(sd_rtnl *rtnl, int ifindex, struct local_address **ret);
+int local_addresses(sd_rtnl *rtnl, int ifindex, int af, struct local_address **ret);
+
+int local_gateways(sd_rtnl *rtnl, int ifindex, int af, struct local_address **ret);
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index b501a52cf1..165e84d7a0 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -36,6 +36,8 @@
#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
+#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
+
static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
sd_rtnl_message *m;
@@ -112,6 +114,24 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char pr
return 0;
}
+int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
+ 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);
+
+ if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
+ (rtm->rtm_family == AF_INET6 && prefixlen > 128))
+ return -ERANGE;
+
+ rtm->rtm_src_len = prefixlen;
+
+ return 0;
+}
+
int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
struct rtmsg *rtm;
@@ -126,6 +146,51 @@ int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
return 0;
}
+int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) {
+ 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(family, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *family = rtm->rtm_family;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) {
+ 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(dst_len, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *dst_len = rtm->rtm_dst_len;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) {
+ 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(src_len, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *src_len = rtm->rtm_src_len;
+
+ return 0;
+}
+
int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
uint16_t nlmsg_type, int rtm_family,
unsigned char rtm_protocol) {
@@ -133,7 +198,8 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
int r;
assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
- assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
+ assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
+ rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -154,6 +220,59 @@ int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
return 0;
}
+int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) {
+ struct ndmsg *ndm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(family, -EINVAL);
+
+ ndm = NLMSG_DATA(m->hdr);
+
+ *family = ndm->ndm_family;
+
+ return 0;
+}
+
+int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) {
+ struct ndmsg *ndm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(index, -EINVAL);
+
+ ndm = NLMSG_DATA(m->hdr);
+
+ *index = ndm->ndm_ifindex;
+
+ return 0;
+}
+
+int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
+ struct ndmsg *ndm;
+ int r;
+
+ assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
+ assert_return(ndm_family == AF_INET || ndm_family == AF_INET6, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = message_new(rtnl, ret, nlmsg_type);
+ if (r < 0)
+ return r;
+
+ if (nlmsg_type == RTM_NEWNEIGH)
+ (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+
+ ndm = NLMSG_DATA((*ret)->hdr);
+
+ ndm->ndm_family = ndm_family;
+ ndm->ndm_ifindex = index;
+
+ return 0;
+}
+
int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
struct ifinfomsg *ifi;
@@ -184,6 +303,20 @@ int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
return 0;
}
+int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) {
+ struct ifinfomsg *ifi;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+
+ ifi = NLMSG_DATA(m->hdr);
+
+ ifi->ifi_family = family;
+
+ return 0;
+}
+
int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
uint16_t nlmsg_type, int index) {
struct ifinfomsg *ifi;
@@ -211,9 +344,10 @@ int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL);
- assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
- m->hdr->nlmsg_type == RTM_GETADDR ||
- m->hdr->nlmsg_type == RTM_GETROUTE,
+ assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
+ m->hdr->nlmsg_type == RTM_GETADDR ||
+ m->hdr->nlmsg_type == RTM_GETROUTE ||
+ m->hdr->nlmsg_type == RTM_GETNEIGH,
-EINVAL);
if (dump)
@@ -566,8 +700,8 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const
size = (size_t)r;
if (size) {
- length = strnlen(data, size);
- if (length >= size)
+ length = strnlen(data, size+1);
+ if (length > size)
return -EINVAL;
} else
length = strlen(data);
@@ -723,7 +857,7 @@ int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
if (r < 0)
return r;
- r = add_rtattr(m, type, NULL, size);
+ r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
if (r < 0)
return r;
@@ -799,6 +933,8 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const c
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_STRING);
if (r < 0)
return r;
@@ -809,7 +945,8 @@ int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const c
else if (strnlen(attr_data, r) >= (size_t) r)
return -EIO;
- *data = (const char *) attr_data;
+ if (data)
+ *data = (const char *) attr_data;
return 0;
}
@@ -818,6 +955,8 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_U8);
if (r < 0)
return r;
@@ -828,7 +967,8 @@ int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *da
else if ((size_t) r < sizeof(uint8_t))
return -EIO;
- *data = *(uint8_t *) attr_data;
+ if (data)
+ *data = *(uint8_t *) attr_data;
return 0;
}
@@ -837,6 +977,8 @@ int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_U16);
if (r < 0)
return r;
@@ -847,7 +989,8 @@ int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *
else if ((size_t) r < sizeof(uint16_t))
return -EIO;
- *data = *(uint16_t *) attr_data;
+ if (data)
+ *data = *(uint16_t *) attr_data;
return 0;
}
@@ -856,6 +999,8 @@ int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_U32);
if (r < 0)
return r;
@@ -866,7 +1011,8 @@ int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *
else if ((size_t)r < sizeof(uint32_t))
return -EIO;
- *data = *(uint32_t *) attr_data;
+ if (data)
+ *data = *(uint32_t *) attr_data;
return 0;
}
@@ -875,6 +1021,8 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
if (r < 0)
return r;
@@ -885,7 +1033,8 @@ int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, str
else if ((size_t)r < sizeof(struct ether_addr))
return -EIO;
- memcpy(data, attr_data, sizeof(struct ether_addr));
+ if (data)
+ memcpy(data, attr_data, sizeof(struct ether_addr));
return 0;
}
@@ -894,6 +1043,8 @@ int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, str
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
if (r < 0)
return r;
@@ -904,7 +1055,8 @@ int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, str
else if ((size_t)r < sizeof(struct ifa_cacheinfo))
return -EIO;
- memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
+ if (info)
+ memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
return 0;
}
@@ -913,6 +1065,8 @@ int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_IN_ADDR);
if (r < 0)
return r;
@@ -923,7 +1077,8 @@ int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct
else if ((size_t)r < sizeof(struct in_addr))
return -EIO;
- memcpy(data, attr_data, sizeof(struct in_addr));
+ if (data)
+ memcpy(data, attr_data, sizeof(struct in_addr));
return 0;
}
@@ -932,6 +1087,8 @@ int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struc
int r;
void *attr_data;
+ assert_return(m, -EINVAL);
+
r = message_attribute_has_type(m, type, NLA_IN_ADDR);
if (r < 0)
return r;
@@ -942,7 +1099,8 @@ int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struc
else if ((size_t)r < sizeof(struct in6_addr))
return -EIO;
- memcpy(data, attr_data, sizeof(struct in6_addr));
+ if (data)
+ memcpy(data, attr_data, sizeof(struct in6_addr));
return 0;
}
@@ -1036,13 +1194,20 @@ uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
return m->hdr->nlmsg_seq;
}
+int sd_rtnl_message_is_error(sd_rtnl_message *m) {
+ assert_return(m, 0);
+ assert_return(m->hdr, 0);
+
+ return m->hdr->nlmsg_type == NLMSG_ERROR;
+}
+
int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
struct nlmsgerr *err;
assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL);
- if (m->hdr->nlmsg_type != NLMSG_ERROR)
+ if (!sd_rtnl_message_is_error(m))
return 0;
err = NLMSG_DATA(m->hdr);
@@ -1066,7 +1231,7 @@ int rtnl_message_parse(sd_rtnl_message *m,
*rta_tb_size = max + 1;
for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
- type = rta->rta_type;
+ type = RTA_TYPE(rta);
/* if the kernel is newer than the headers we used
when building, we ignore out-of-range attributes
@@ -1222,7 +1387,7 @@ int socket_read_message(sd_rtnl *rtnl) {
}
}
- for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
+ for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
const NLType *nl_type;
@@ -1237,7 +1402,8 @@ int socket_read_message(sd_rtnl *rtnl) {
if (new_msg->nlmsg_type == NLMSG_DONE) {
/* finished reading multi-part message */
done = true;
- break;
+
+ continue;
}
/* check that we support this message type */
@@ -1251,8 +1417,10 @@ int socket_read_message(sd_rtnl *rtnl) {
}
/* check that the size matches the message type */
- if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
+ if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
+ log_debug("sd-rtnl: message larger than expected, dropping");
continue;
+ }
r = message_new_empty(rtnl, &m);
if (r < 0)
diff --git a/src/libsystemd/sd-rtnl/rtnl-types.c b/src/libsystemd/sd-rtnl/rtnl-types.c
index df9a45dab1..a1db2ab76c 100644
--- a/src/libsystemd/sd-rtnl/rtnl-types.c
+++ b/src/libsystemd/sd-rtnl/rtnl-types.c
@@ -211,7 +211,23 @@ static const NLTypeSystem rtnl_link_info_type_system = {
.types = rtnl_link_info_types,
};
-static const NLType rtnl_link_types[IFLA_MAX + 1] = {
+static const struct NLType rtnl_bridge_port_types[IFLA_BRPORT_MAX + 1] = {
+ [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
+ [IFLA_BRPORT_COST] = { .type = NLA_U32 },
+ [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
+ [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
+ [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
+ [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
+ [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
+ [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
+};
+
+static const NLTypeSystem rtnl_bridge_port_type_system = {
+ .max = ELEMENTSOF(rtnl_bridge_port_types) - 1,
+ .types = rtnl_bridge_port_types,
+};
+
+static const NLType rtnl_link_types[IFLA_MAX + 1 ] = {
[IFLA_ADDRESS] = { .type = NLA_ETHER_ADDR, },
[IFLA_BROADCAST] = { .type = NLA_ETHER_ADDR, },
[IFLA_IFNAME] = { .type = NLA_STRING, .size = IFNAMSIZ - 1, },
@@ -228,6 +244,7 @@ static const NLType rtnl_link_types[IFLA_MAX + 1] = {
[IFLA_WIRELESS],
[IFLA_PROTINFO],
*/
+ [IFLA_PROTINFO] = { .type = NLA_NESTED, .type_system = &rtnl_bridge_port_type_system },
[IFLA_TXQLEN] = { .type = NLA_U32 },
/*
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
@@ -312,6 +329,25 @@ static const NLTypeSystem rtnl_route_type_system = {
.types = rtnl_route_types,
};
+static const NLType rtnl_neigh_types[NDA_MAX + 1] = {
+ [NDA_DST] = { .type = NLA_IN_ADDR },
+ [NDA_LLADDR] = { .type = NLA_ETHER_ADDR },
+/*
+ NDA_CACHEINFO,
+ NDA_PROBES,
+ NDA_VLAN,
+ NDA_PORT
+ NDA_VNI
+ NDA_IFINDEX
+ NDA_MASTER
+*/
+};
+
+static const NLTypeSystem rtnl_neigh_type_system = {
+ .max = ELEMENTSOF(rtnl_neigh_types) - 1,
+ .types = rtnl_neigh_types,
+};
+
static const NLType rtnl_types[RTM_MAX + 1] = {
[NLMSG_ERROR] = { .type = NLA_META, .size = sizeof(struct nlmsgerr) },
[RTM_NEWLINK] = { .type = NLA_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) },
@@ -324,6 +360,9 @@ static const NLType rtnl_types[RTM_MAX + 1] = {
[RTM_NEWROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_DELROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
[RTM_GETROUTE] = { .type = NLA_NESTED, .type_system = &rtnl_route_type_system, .size = sizeof(struct rtmsg) },
+ [RTM_NEWNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
+ [RTM_DELNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
+ [RTM_GETNEIGH] = { .type = NLA_NESTED, .type_system = &rtnl_neigh_type_system, .size = sizeof(struct ndmsg) },
};
const NLTypeSystem rtnl_type_system = {
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c
index 1ec1fa8d27..194a267b04 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.c
+++ b/src/libsystemd/sd-rtnl/rtnl-util.c
@@ -122,6 +122,17 @@ int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message
return 0;
}
+bool rtnl_message_type_is_neigh(uint16_t type) {
+ switch (type) {
+ case RTM_NEWNEIGH:
+ case RTM_GETNEIGH:
+ case RTM_DELNEIGH:
+ return true;
+ default:
+ return false;
+ }
+}
+
bool rtnl_message_type_is_route(uint16_t type) {
switch (type) {
case RTM_NEWROUTE:
@@ -157,11 +168,9 @@ bool rtnl_message_type_is_addr(uint16_t type) {
}
int rtnl_log_parse_error(int r) {
- log_error("Failed to parse netlink message: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to parse netlink message: %m");
}
int rtnl_log_create_error(int r) {
- log_error("Failed to create netlink message: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to create netlink message: %m");
}
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h
index fa3592df9d..ca9fbd4f41 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.h
+++ b/src/libsystemd/sd-rtnl/rtnl-util.h
@@ -33,6 +33,7 @@ void rtnl_message_seal(sd_rtnl_message *m);
bool rtnl_message_type_is_link(uint16_t type);
bool rtnl_message_type_is_addr(uint16_t type);
bool rtnl_message_type_is_route(uint16_t type);
+bool rtnl_message_type_is_neigh(uint16_t type);
int rtnl_set_link_name(sd_rtnl **rtnl, int ifindex, const char *name);
int rtnl_set_link_properties(sd_rtnl **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
diff --git a/src/libsystemd/sd-rtnl/sd-rtnl.c b/src/libsystemd/sd-rtnl/sd-rtnl.c
index b7f1afe905..abb011ea24 100644
--- a/src/libsystemd/sd-rtnl/sd-rtnl.c
+++ b/src/libsystemd/sd-rtnl/sd-rtnl.c
@@ -140,6 +140,10 @@ int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
return 0;
}
+int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
+ return fd_inc_rcvbuf(rtnl->fd, size);
+}
+
sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
assert_return(rtnl, NULL);
assert_return(!rtnl_pid_changed(rtnl), NULL);
@@ -859,7 +863,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = sd_event_source_set_name(rtnl->io_event_source, "rtnl-receive-message");
+ r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
if (r < 0)
goto fail;
@@ -875,7 +879,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = sd_event_source_set_name(rtnl->time_event_source, "rtnl-timer");
+ r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
if (r < 0)
goto fail;
@@ -883,7 +887,7 @@ int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
if (r < 0)
goto fail;
- r = sd_event_source_set_name(rtnl->exit_event_source, "rtnl-exit");
+ r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
if (r < 0)
goto fail;
diff --git a/src/libsystemd/sd-rtnl/test-local-addresses.c b/src/libsystemd/sd-rtnl/test-local-addresses.c
new file mode 100644
index 0000000000..38cbcfbccb
--- /dev/null
+++ b/src/libsystemd/sd-rtnl/test-local-addresses.c
@@ -0,0 +1,58 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "in-addr-util.h"
+#include "local-addresses.h"
+#include "af-list.h"
+
+static void print_local_addresses(struct local_address *a, unsigned n) {
+ unsigned i;
+
+ for (i = 0; i < n; i++) {
+ _cleanup_free_ char *b = NULL;
+
+ assert_se(in_addr_to_string(a[i].family, &a[i].address, &b) >= 0);
+ printf("%s if%i scope=%i metric=%u address=%s\n", af_to_name(a[i].family), a[i].ifindex, a[i].scope, a[i].metric, b);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ struct local_address *a;
+ int n;
+
+ a = NULL;
+ n = local_addresses(NULL, 0, AF_UNSPEC, &a);
+ assert_se(n >= 0);
+
+ printf("Local Addresses:\n");
+ print_local_addresses(a, (unsigned) n);
+ free(a);
+
+ a = NULL;
+ n = local_gateways(NULL, 0, AF_UNSPEC, &a);
+ assert_se(n >= 0);
+
+ printf("Local Gateways:\n");
+ print_local_addresses(a, (unsigned) n);
+ free(a);
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-rtnl/test-rtnl.c b/src/libsystemd/sd-rtnl/test-rtnl.c
index 46b5bb20c3..72d8fe2273 100644
--- a/src/libsystemd/sd-rtnl/test-rtnl.c
+++ b/src/libsystemd/sd-rtnl/test-rtnl.c
@@ -135,7 +135,7 @@ static void test_route(void) {
r = sd_rtnl_message_new_route(NULL, &req, RTM_NEWROUTE, AF_INET, RTPROT_STATIC);
if (r < 0) {
- log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
+ log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
return;
}
@@ -143,13 +143,13 @@ static void test_route(void) {
r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &addr);
if (r < 0) {
- log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
+ log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
return;
}
r = sd_rtnl_message_append_u32(req, RTA_OIF, index);
if (r < 0) {
- log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
+ log_error_errno(r, "Could not append RTA_OIF attribute: %m");
return;
}
@@ -223,7 +223,7 @@ static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
- log_info("%d left in pipe. got reply: %s", *counter, strerror(-r));
+ log_info_errno(r, "%d left in pipe. got reply: %m", *counter);
assert_se(r >= 0);
diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c
index 637d064819..fb4c6e2940 100644
--- a/src/libudev/libudev-device-private.c
+++ b/src/libudev/libudev-device-private.c
@@ -102,7 +102,6 @@ static bool device_has_info(struct udev_device *udev_device)
int udev_device_update_db(struct udev_device *udev_device)
{
- struct udev *udev = udev_device_get_udev(udev_device);
bool has_info;
const char *id;
char filename[UTIL_PATH_SIZE];
@@ -129,10 +128,8 @@ int udev_device_update_db(struct udev_device *udev_device)
strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
mkdir_parents(filename_tmp, 0755);
f = fopen(filename_tmp, "we");
- if (f == NULL) {
- udev_err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp);
- return -1;
- }
+ if (f == NULL)
+ return log_debug_errno(errno, "unable to create temporary db file '%s': %m", filename_tmp);
/*
* set 'sticky' bit to indicate that we should not clean the
@@ -172,7 +169,7 @@ int udev_device_update_db(struct udev_device *udev_device)
r = rename(filename_tmp, filename);
if (r < 0)
return -1;
- udev_dbg(udev, "created %s file '%s' for '%s'\n", has_info ? "db" : "empty",
+ log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
filename, udev_device_get_devpath(udev_device));
return 0;
}
diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
index 2699374072..16ee1f4be3 100644
--- a/src/libudev/libudev-device.c
+++ b/src/libudev/libudev-device.c
@@ -534,10 +534,8 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile)
}
f = fopen(dbfile, "re");
- if (f == NULL) {
- udev_dbg(udev_device->udev, "no db file to read %s: %m\n", dbfile);
- return -errno;
- }
+ if (f == NULL)
+ return log_debug_errno(errno, "no db file to read %s: %m", dbfile);
/* devices with a database entry are initialized */
udev_device->is_initialized = true;
@@ -577,7 +575,7 @@ int udev_device_read_db(struct udev_device *udev_device, const char *dbfile)
}
fclose(f);
- udev_dbg(udev_device->udev, "device %p filled with db file data\n", udev_device);
+ log_debug("device %p filled with db file data", udev_device);
return 0;
}
@@ -642,7 +640,6 @@ void udev_device_set_info_loaded(struct udev_device *device)
struct udev_device *udev_device_new(struct udev *udev)
{
struct udev_device *udev_device;
- struct udev_list_entry *list_entry;
if (udev == NULL) {
errno = EINVAL;
@@ -662,11 +659,7 @@ struct udev_device *udev_device_new(struct udev *udev)
udev_list_init(udev, &udev_device->sysattr_list, false);
udev_list_init(udev, &udev_device->tags_list, true);
udev_device->watch_handle = -1;
- /* copy global properties */
- udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev))
- udev_device_add_property(udev_device,
- udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry));
+
return udev_device;
}
@@ -704,7 +697,7 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
/* path starts in sys */
if (!startswith(syspath, "/sys")) {
- udev_dbg(udev, "not in sys :%s\n", syspath);
+ log_debug("not in sys :%s", syspath);
errno = EINVAL;
return NULL;
}
@@ -730,8 +723,13 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
return NULL;
} else {
/* everything else just needs to be a directory */
- if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
+ if (stat(path, &statbuf) != 0)
+ return NULL;
+
+ if (!S_ISDIR(statbuf.st_mode)) {
+ errno = EISDIR;
return NULL;
+ }
}
udev_device = udev_device_new(udev);
@@ -739,7 +737,7 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con
return NULL;
udev_device_set_syspath(udev_device, path);
- udev_dbg(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
+ log_debug("device %p has devpath '%s'", udev_device, udev_device_get_devpath(udev_device));
return udev_device;
}
@@ -971,7 +969,7 @@ _public_ struct udev_device *udev_device_new_from_environment(struct udev *udev)
udev_device_add_property_from_string_parse(udev_device, environ[i]);
if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
- udev_dbg(udev, "missing values, invalid device\n");
+ log_debug("missing values, invalid device");
udev_device_unref(udev_device);
udev_device = NULL;
}
diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c
index a1cfc0bd5a..05a685868f 100644
--- a/src/libudev/libudev-hwdb.c
+++ b/src/libudev/libudev-hwdb.c
@@ -289,45 +289,45 @@ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) {
else if (errno == ENOENT)
continue;
else {
- udev_dbg(udev, "error reading %s: %m", hwdb_bin_path);
+ log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
}
if (!hwdb->f) {
- udev_err(udev, "hwdb.bin does not exist, please run udevadm hwdb --update");
+ log_debug("hwdb.bin does not exist, please run udevadm hwdb --update");
udev_hwdb_unref(hwdb);
return NULL;
}
if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
(size_t)hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8) {
- udev_dbg(udev, "error reading %s: %m", hwdb_bin_path);
+ log_debug_errno(errno, "error reading %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
if (hwdb->map == MAP_FAILED) {
- udev_dbg(udev, "error mapping %s: %m", hwdb_bin_path);
+ log_debug_errno(errno, "error mapping %s: %m", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
(size_t)hwdb->st.st_size != le64toh(hwdb->head->file_size)) {
- udev_dbg(udev, "error recognizing the format of %s", hwdb_bin_path);
+ log_debug("error recognizing the format of %s", hwdb_bin_path);
udev_hwdb_unref(hwdb);
return NULL;
}
- udev_dbg(udev, "=== trie on-disk ===\n");
- udev_dbg(udev, "tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
- udev_dbg(udev, "file size: %8"PRIu64" bytes\n", hwdb->st.st_size);
- udev_dbg(udev, "header size %8"PRIu64" bytes\n", le64toh(hwdb->head->header_size));
- udev_dbg(udev, "strings %8"PRIu64" bytes\n", le64toh(hwdb->head->strings_len));
- udev_dbg(udev, "nodes %8"PRIu64" bytes\n", le64toh(hwdb->head->nodes_len));
+ log_debug("=== trie on-disk ===");
+ log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
+ log_debug("file size: %8"PRIu64" bytes", hwdb->st.st_size);
+ log_debug("header size %8"PRIu64" bytes", le64toh(hwdb->head->header_size));
+ log_debug("strings %8"PRIu64" bytes", le64toh(hwdb->head->strings_len));
+ log_debug("nodes %8"PRIu64" bytes", le64toh(hwdb->head->nodes_len));
return hwdb;
}
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 59698b85b7..e8d6b4a61b 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -121,7 +121,7 @@ static bool udev_has_devtmpfs(struct udev *udev) {
r = name_to_handle_at(AT_FDCWD, "/dev", &h.handle, &mount_id, 0);
if (r < 0) {
if (errno != EOPNOTSUPP)
- udev_err(udev, "name_to_handle_at on /dev: %m\n");
+ log_debug_errno(errno, "name_to_handle_at on /dev: %m");
return false;
}
@@ -174,7 +174,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
* will not receive any messages.
*/
if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
- udev_dbg(udev, "the udev service seems not to be active, disable the monitor\n");
+ log_debug("the udev service seems not to be active, disable the monitor");
group = UDEV_MONITOR_NONE;
} else
group = UDEV_MONITOR_UDEV;
@@ -190,7 +190,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
if (fd < 0) {
udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
if (udev_monitor->sock == -1) {
- udev_err(udev, "error getting socket: %m\n");
+ log_debug_errno(errno, "error getting socket: %m");
free(udev_monitor);
return NULL;
}
@@ -407,14 +407,14 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
if (err == 0)
udev_monitor->snl.nl.nl_pid = snl.nl.nl_pid;
} else {
- udev_err(udev_monitor->udev, "bind failed: %m\n");
+ log_debug_errno(errno, "bind failed: %m");
return -errno;
}
/* enable receiving of sender credentials */
err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (err < 0)
- udev_err(udev_monitor->udev, "setting SO_PASSCRED failed: %m\n");
+ log_debug_errno(errno, "setting SO_PASSCRED failed: %m");
return 0;
}
@@ -602,12 +602,12 @@ retry:
buflen = recvmsg(udev_monitor->sock, &smsg, 0);
if (buflen < 0) {
if (errno != EINTR)
- udev_dbg(udev_monitor->udev, "unable to receive message\n");
+ log_debug("unable to receive message");
return NULL;
}
if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
- udev_dbg(udev_monitor->udev, "invalid message length\n");
+ log_debug("invalid message length");
return NULL;
}
@@ -615,12 +615,12 @@ retry:
/* unicast message, check if we trust the sender */
if (udev_monitor->snl_trusted_sender.nl.nl_pid == 0 ||
snl.nl.nl_pid != udev_monitor->snl_trusted_sender.nl.nl_pid) {
- udev_dbg(udev_monitor->udev, "unicast netlink message ignored\n");
+ log_debug("unicast netlink message ignored");
return NULL;
}
} else if (snl.nl.nl_groups == UDEV_MONITOR_KERNEL) {
if (snl.nl.nl_pid > 0) {
- udev_dbg(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
+ log_debug("multicast kernel netlink message from pid %d ignored",
snl.nl.nl_pid);
return NULL;
}
@@ -628,13 +628,13 @@ retry:
cmsg = CMSG_FIRSTHDR(&smsg);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
- udev_dbg(udev_monitor->udev, "no sender credentials received, message ignored\n");
+ log_debug("no sender credentials received, message ignored");
return NULL;
}
cred = (struct ucred *)CMSG_DATA(cmsg);
if (cred->uid != 0) {
- udev_dbg(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
+ log_debug("sender uid=%d, message ignored", cred->uid);
return NULL;
}
@@ -648,7 +648,7 @@ retry:
/* udev message needs proper version magic */
nlh = (struct udev_monitor_netlink_header *) buf;
if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) {
- udev_err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n",
+ log_debug("unrecognized message signature (%x != %x)",
nlh->magic, htonl(UDEV_MONITOR_MAGIC));
udev_device_unref(udev_device);
return NULL;
@@ -666,14 +666,14 @@ retry:
/* kernel message with header */
bufpos = strlen(buf) + 1;
if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
- udev_dbg(udev_monitor->udev, "invalid message length\n");
+ log_debug("invalid message length");
udev_device_unref(udev_device);
return NULL;
}
/* check message header */
if (strstr(buf, "@/") == NULL) {
- udev_dbg(udev_monitor->udev, "unrecognized message header\n");
+ log_debug("unrecognized message header");
udev_device_unref(udev_device);
return NULL;
}
@@ -694,7 +694,7 @@ retry:
}
if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
- udev_dbg(udev_monitor->udev, "missing values, invalid device\n");
+ log_debug("missing values, invalid device");
udev_device_unref(udev_device);
return NULL;
}
@@ -778,7 +778,7 @@ int udev_monitor_send_device(struct udev_monitor *udev_monitor,
smsg.msg_name = &udev_monitor->snl_destination;
smsg.msg_namelen = sizeof(struct sockaddr_nl);
count = sendmsg(udev_monitor->sock, &smsg, 0);
- udev_dbg(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
+ log_debug("passed %zi bytes to netlink monitor %p", count, udev_monitor);
return count;
}
diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
index 7e11f7326d..64f132f91d 100644
--- a/src/libudev/libudev-private.h
+++ b/src/libudev/libudev-private.h
@@ -33,24 +33,8 @@
#define READ_END 0
#define WRITE_END 1
-/* avoid (sometimes expensive) calculations of parameters for debug output */
-#define udev_log_cond(udev, prio, arg...) \
- do { \
- if (udev_get_log_priority(udev) >= prio) \
- udev_log(udev, prio, __FILE__, __LINE__, __FUNCTION__, ## arg); \
- } while (0)
-
-#define udev_dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg)
-#define udev_info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg)
-#define udev_err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg)
-
/* libudev.c */
-void udev_log(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, ...) _printf_(6, 7);
int udev_get_rules_path(struct udev *udev, char **path[], usec_t *ts_usec[]);
-struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
-struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
/* libudev-device.c */
struct udev_device *udev_device_new(struct udev *udev);
diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c
index f3fdf3b5aa..291829e6d8 100644
--- a/src/libudev/libudev-util.c
+++ b/src/libudev/libudev-util.c
@@ -93,7 +93,7 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
strscpy(result, maxsize, val);
else
result[0] = '\0';
- udev_dbg(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
+ log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result);
} else {
size_t l;
char *s;
@@ -102,7 +102,7 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
l = strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
if (attr != NULL)
strpcpyl(&s, l, "/", attr, NULL);
- udev_dbg(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
+ log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, attr, result);
}
udev_device_unref(dev);
return 0;
@@ -159,9 +159,13 @@ int util_log_priority(const char *priority)
char *endptr;
int prio;
- prio = strtol(priority, &endptr, 10);
- if (endptr[0] == '\0' || isspace(endptr[0]))
- return prio;
+ prio = strtoul(priority, &endptr, 10);
+ if (endptr[0] == '\0' || isspace(endptr[0])) {
+ if (prio >= 0 && prio <= 7)
+ return prio;
+ else
+ return -ERANGE;
+ }
return log_level_from_string(priority);
}
diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c
index e2ab960d55..8785f22071 100644
--- a/src/libudev/libudev.c
+++ b/src/libudev/libudev.c
@@ -1,7 +1,7 @@
/***
This file is part of systemd.
- Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+ Copyright 2008-2014 Kay Sievers <kay@vrfy.org>
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
@@ -50,41 +50,18 @@ struct udev {
int priority, const char *file, int line, const char *fn,
const char *format, va_list args);
void *userdata;
- struct udev_list properties_list;
- int log_priority;
};
-void udev_log(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- udev->log_fn(udev, priority, file, line, fn, format, args);
- va_end(args);
-}
-
-_printf_(6,0)
-static void log_stderr(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, va_list args)
-{
- fprintf(stderr, "libudev: %s: ", fn);
- vfprintf(stderr, format, args);
-}
-
/**
* udev_get_userdata:
* @udev: udev library context
*
* Retrieve stored data pointer from library context. This might be useful
- * to access from callbacks like a custom logging function.
+ * to access from callbacks.
*
* Returns: stored userdata
**/
-_public_ void *udev_get_userdata(struct udev *udev)
-{
+_public_ void *udev_get_userdata(struct udev *udev) {
if (udev == NULL)
return NULL;
return udev->userdata;
@@ -97,8 +74,7 @@ _public_ void *udev_get_userdata(struct udev *udev)
*
* Store custom @userdata in the library context.
**/
-_public_ void udev_set_userdata(struct udev *udev, void *userdata)
-{
+_public_ void udev_set_userdata(struct udev *udev, void *userdata) {
if (udev == NULL)
return;
udev->userdata = userdata;
@@ -115,24 +91,19 @@ _public_ void udev_set_userdata(struct udev *udev, void *userdata)
*
* Returns: a new udev library context
**/
-_public_ struct udev *udev_new(void)
-{
+_public_ struct udev *udev_new(void) {
struct udev *udev;
- const char *env;
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
udev = new0(struct udev, 1);
if (udev == NULL)
return NULL;
udev->refcount = 1;
- udev->log_fn = log_stderr;
- udev->log_priority = LOG_INFO;
- udev_list_init(udev, &udev->properties_list, true);
f = fopen("/etc/udev/udev.conf", "re");
if (f != NULL) {
char line[UTIL_LINE_SIZE];
- int line_nr = 0;
+ unsigned line_nr = 0;
while (fgets(line, sizeof(line), f)) {
size_t len;
@@ -153,7 +124,7 @@ _public_ struct udev *udev_new(void)
/* split key/value */
val = strchr(key, '=');
if (val == NULL) {
- udev_err(udev, "missing <key>=<value> in /etc/udev/udev.conf[%i]; skip line\n", line_nr);
+ log_debug("/etc/udev/udev.conf:%u: missing assignment, skipping line.", line_nr);
continue;
}
val[0] = '\0';
@@ -185,7 +156,7 @@ _public_ struct udev *udev_new(void)
/* unquote */
if (val[0] == '"' || val[0] == '\'') {
if (val[len-1] != val[0]) {
- udev_err(udev, "inconsistent quoting in /etc/udev/udev.conf[%i]; skip line\n", line_nr);
+ log_debug("/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.", line_nr);
continue;
}
val[len-1] = '\0';
@@ -193,18 +164,18 @@ _public_ struct udev *udev_new(void)
}
if (streq(key, "udev_log")) {
- udev_set_log_priority(udev, util_log_priority(val));
+ int prio;
+
+ prio = util_log_priority(val);
+ if (prio < 0)
+ log_debug("/etc/udev/udev.conf:%u: invalid log level '%s', ignoring.", line_nr, val);
+ else
+ log_set_max_level(prio);
continue;
}
}
- fclose(f);
}
- /* environment overrides config */
- env = secure_getenv("UDEV_LOG");
- if (env != NULL)
- udev_set_log_priority(udev, util_log_priority(env));
-
return udev;
}
@@ -216,8 +187,7 @@ _public_ struct udev *udev_new(void)
*
* Returns: the passed udev library context
**/
-_public_ struct udev *udev_ref(struct udev *udev)
-{
+_public_ struct udev *udev_ref(struct udev *udev) {
if (udev == NULL)
return NULL;
udev->refcount++;
@@ -233,14 +203,12 @@ _public_ struct udev *udev_ref(struct udev *udev)
*
* Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
**/
-_public_ struct udev *udev_unref(struct udev *udev)
-{
+_public_ struct udev *udev_unref(struct udev *udev) {
if (udev == NULL)
return NULL;
udev->refcount--;
if (udev->refcount > 0)
return udev;
- udev_list_cleanup(&udev->properties_list);
free(udev);
return NULL;
}
@@ -248,68 +216,37 @@ _public_ struct udev *udev_unref(struct udev *udev)
/**
* udev_set_log_fn:
* @udev: udev library context
- * @log_fn: function to be called for logging messages
+ * @log_fn: function to be called for log messages
*
- * The built-in logging writes to stderr. It can be
- * overridden by a custom function, to plug log messages
- * into the users' logging functionality.
+ * This function is deprecated.
*
**/
_public_ void udev_set_log_fn(struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
- const char *format, va_list args))
-{
- udev->log_fn = log_fn;
- udev_dbg(udev, "custom logging function %p registered\n", log_fn);
+ const char *format, va_list args)) {
+ return;
}
/**
* udev_get_log_priority:
* @udev: udev library context
*
- * The initial logging priority is read from the udev config file
- * at startup.
+ * This function is deprecated.
*
- * Returns: the current logging priority
**/
-_public_ int udev_get_log_priority(struct udev *udev)
-{
- return udev->log_priority;
+_public_ int udev_get_log_priority(struct udev *udev) {
+ return log_get_max_level();
}
/**
* udev_set_log_priority:
* @udev: udev library context
- * @priority: the new logging priority
+ * @priority: the new log priority
+ *
+ * This function is deprecated.
*
- * Set the current logging priority. The value controls which messages
- * are logged.
**/
-_public_ void udev_set_log_priority(struct udev *udev, int priority)
-{
- char num[32];
-
- udev->log_priority = priority;
- snprintf(num, sizeof(num), "%u", udev->log_priority);
- udev_add_property(udev, "UDEV_LOG", num);
-}
-
-struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
-{
- if (value == NULL) {
- struct udev_list_entry *list_entry;
-
- list_entry = udev_get_properties_list_entry(udev);
- list_entry = udev_list_entry_get_by_name(list_entry, key);
- if (list_entry != NULL)
- udev_list_entry_delete(list_entry);
- return NULL;
- }
- return udev_list_entry_add(&udev->properties_list, key, value);
-}
-
-struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
-{
- return udev_list_get_entry(&udev->properties_list);
+_public_ void udev_set_log_priority(struct udev *udev, int priority) {
+ log_set_max_level(priority);
}
diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h
index 4f2f11502c..a94505c09e 100644
--- a/src/libudev/libudev.h
+++ b/src/libudev/libudev.h
@@ -41,9 +41,9 @@ struct udev *udev_new(void);
void udev_set_log_fn(struct udev *udev,
void (*log_fn)(struct udev *udev,
int priority, const char *file, int line, const char *fn,
- const char *format, va_list args));
-int udev_get_log_priority(struct udev *udev);
-void udev_set_log_priority(struct udev *udev, int priority);
+ const char *format, va_list args)) __attribute__ ((deprecated));
+int udev_get_log_priority(struct udev *udev) __attribute__ ((deprecated));
+void udev_set_log_priority(struct udev *udev, int priority) __attribute__ ((deprecated));
void *udev_get_userdata(struct udev *udev);
void udev_set_userdata(struct udev *udev, void *userdata);
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 3690f9fc89..58b8984bc8 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -110,7 +110,7 @@ static void print_overriden_variables(void) {
NULL);
if (r < 0 && r != -ENOENT) {
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read /proc/cmdline: %m");
goto finish;
}
@@ -118,11 +118,11 @@ static void print_overriden_variables(void) {
if (variables[j]) {
if (print_warning) {
log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n"
- " Command Line: %s=%s\n", locale_variable_to_string(j), variables[j]);
+ " Command Line: %s=%s", locale_variable_to_string(j), variables[j]);
print_warning = false;
} else
- log_warning(" %s=%s\n", locale_variable_to_string(j), variables[j]);
+ log_warning(" %s=%s", locale_variable_to_string(j), variables[j]);
}
finish:
for (j = 0; j < _VARIABLE_LC_MAX; j++)
@@ -178,7 +178,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
map,
&info);
if (r < 0) {
- log_error("Could not get properties: %s", strerror(-r));
+ log_error_errno(r, "Could not get properties: %m");
goto fail;
}
@@ -234,10 +234,8 @@ static int list_locales(sd_bus *bus, char **args, unsigned n) {
assert(args);
r = get_locales(&l);
- if (r < 0) {
- log_error("Failed to read list of locales: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read list of locales: %m");
pager_open_if_enabled();
strv_print(l);
@@ -309,10 +307,8 @@ static int nftw_cb(
*e = 0;
r = set_consume(keymaps, p);
- if (r < 0 && r != -EEXIST) {
- log_error("Can't add keymap: %s", strerror(-r));
- return r;
- }
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Can't add keymap: %m");
return 0;
}
@@ -405,10 +401,8 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
}
f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
- if (!f) {
- log_error("Failed to open keyboard mapping list. %m");
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to open keyboard mapping list. %m");
if (streq(args[0], "list-x11-keymap-models"))
look_for = MODELS;
@@ -505,7 +499,7 @@ static void help(void) {
" list-locales Show known locales\n"
" set-keymap MAP [MAP] Set virtual console keyboard mapping\n"
" list-keymaps Show known virtual console keyboard mappings\n"
- " set-x11-keymap LAYOUT [MODEL] [VARIANT] [OPTIONS]\n"
+ " set-x11-keymap LAYOUT [MODEL [VARIANT [OPTIONS]]]\n"
" Set X11 keyboard mapping\n"
" list-x11-keymap-models Show known X11 keyboard mapping models\n"
" list-x11-keymap-layouts Show known X11 keyboard mapping layouts\n"
@@ -683,7 +677,7 @@ int main(int argc, char*argv[]) {
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
diff --git a/src/locale/localed.c b/src/locale/localed.c
index 552ffdf87a..8d60d0ff13 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -41,6 +41,10 @@
#include "event-util.h"
#include "locale-util.h"
+#ifdef HAVE_XKBCOMMON
+#include <xkbcommon/xkbcommon.h>
+#endif
+
enum {
/* We don't list LC_ALL here on purpose. People should be
* using LANG instead. */
@@ -224,7 +228,7 @@ static int x11_read_data(Context *c) {
if (in_section && first_word(l, "Option")) {
_cleanup_strv_free_ char **a = NULL;
- r = strv_split_quoted(&a, l);
+ r = strv_split_quoted(&a, l, false);
if (r < 0)
return r;
@@ -247,7 +251,7 @@ static int x11_read_data(Context *c) {
} else if (!in_section && first_word(l, "Section")) {
_cleanup_strv_free_ char **a = NULL;
- r = strv_split_quoted(&a, l);
+ r = strv_split_quoted(&a, l, false);
if (r < 0)
return -ENOMEM;
@@ -371,7 +375,7 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) {
r = sd_bus_call(bus, m, 0, &error, NULL);
if (r < 0)
- log_error("Failed to update the manager environment: %s", strerror(-r));
+ log_error_errno(r, "Failed to update the manager environment: %m");
return 0;
}
@@ -533,7 +537,7 @@ static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
if (l[0] == 0 || l[0] == '#')
continue;
- r = strv_split_quoted(&b, l);
+ r = strv_split_quoted(&b, l, false);
if (r < 0)
return r;
@@ -606,10 +610,8 @@ static int vconsole_convert_to_x11(Context *c, sd_bus *bus) {
int r;
r = x11_write_data(c);
- if (r < 0) {
- log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set X11 keyboard layout: %m");
log_info("Changed X11 keyboard layout to '%s' model '%s' variant '%s' options '%s'",
strempty(c->x11_layout),
@@ -786,7 +788,7 @@ static int x11_convert_to_vconsole(Context *c, sd_bus *bus) {
if (modified) {
r = vconsole_write_data(c);
if (r < 0)
- log_error("Failed to set virtual console keymap: %s", strerror(-r));
+ log_error_errno(r, "Failed to set virtual console keymap: %m");
log_info("Changed virtual console keymap to '%s' toggle '%s'",
strempty(c->vc_keymap), strempty(c->vc_keymap_toggle));
@@ -919,7 +921,7 @@ static int method_set_locale(sd_bus *bus, sd_bus_message *m, void *userdata, sd_
r = locale_write_data(c, &settings);
if (r < 0) {
- log_error("Failed to set locale: %s", strerror(-r));
+ log_error_errno(r, "Failed to set locale: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set locale: %s", strerror(-r));
}
@@ -979,7 +981,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
r = vconsole_write_data(c);
if (r < 0) {
- log_error("Failed to set virtual console keymap: %s", strerror(-r));
+ log_error_errno(r, "Failed to set virtual console keymap: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set virtual console keymap: %s", strerror(-r));
}
@@ -988,7 +990,7 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
r = vconsole_reload(bus);
if (r < 0)
- log_error("Failed to request keymap reload: %s", strerror(-r));
+ log_error_errno(r, "Failed to request keymap reload: %m");
sd_bus_emit_properties_changed(bus,
"/org/freedesktop/locale1",
@@ -998,13 +1000,61 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata
if (convert) {
r = vconsole_convert_to_x11(c, bus);
if (r < 0)
- log_error("Failed to convert keymap data: %s", strerror(-r));
+ log_error_errno(r, "Failed to convert keymap data: %m");
}
}
return sd_bus_reply_method_return(m, NULL);
}
+#ifdef HAVE_XKBCOMMON
+static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
+ const char *fmt;
+
+ fmt = strappenda("libxkbcommon: ", format);
+ log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
+}
+
+static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+ const struct xkb_rule_names rmlvo = {
+ .model = model,
+ .layout = layout,
+ .variant = variant,
+ .options = options,
+ };
+ struct xkb_context *ctx = NULL;
+ struct xkb_keymap *km = NULL;
+ int r;
+
+ /* compile keymap from RMLVO information to check out its validity */
+
+ ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+ if (!ctx) {
+ r = -ENOMEM;
+ goto exit;
+ }
+
+ xkb_context_set_log_fn(ctx, log_xkb);
+
+ km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ if (!km) {
+ r = -EINVAL;
+ goto exit;
+ }
+
+ r = 0;
+
+exit:
+ xkb_keymap_unref(km);
+ xkb_context_unref(ctx);
+ return r;
+}
+#else
+static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+ return 0;
+}
+#endif
+
static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = userdata;
const char *layout, *model, *variant, *options;
@@ -1044,6 +1094,13 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+ r = verify_xkb_rmlvo(model, layout, variant, options);
+ if (r < 0) {
+ log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
+ strempty(model), strempty(layout), strempty(variant), strempty(options));
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
+ }
+
if (free_and_strdup(&c->x11_layout, layout) < 0 ||
free_and_strdup(&c->x11_model, model) < 0 ||
free_and_strdup(&c->x11_variant, variant) < 0 ||
@@ -1052,7 +1109,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
r = x11_write_data(c);
if (r < 0) {
- log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
+ log_error_errno(r, "Failed to set X11 keyboard layout: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set X11 keyboard layout: %s", strerror(-r));
}
@@ -1070,7 +1127,7 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
if (convert) {
r = x11_convert_to_vconsole(c, bus);
if (r < 0)
- log_error("Failed to convert keymap data: %s", strerror(-r));
+ log_error_errno(r, "Failed to convert keymap data: %m");
}
}
@@ -1101,28 +1158,20 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
assert(_bus);
r = sd_bus_default_system(&bus);
- if (r < 0) {
- log_error("Failed to get system bus connection: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get system bus connection: %m");
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/locale1", "org.freedesktop.locale1", locale_vtable, c);
- if (r < 0) {
- log_error("Failed to register object: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register object: %m");
r = sd_bus_request_name(bus, "org.freedesktop.locale1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(bus, event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
*_bus = bus;
bus = NULL;
@@ -1151,7 +1200,7 @@ int main(int argc, char *argv[]) {
r = sd_event_default(&event);
if (r < 0) {
- log_error("Failed to allocate event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate event loop: %m");
goto finish;
}
@@ -1163,13 +1212,13 @@ int main(int argc, char *argv[]) {
r = context_read_data(&context);
if (r < 0) {
- log_error("Failed to read locale data: %s", strerror(-r));
+ log_error_errno(r, "Failed to read locale data: %m");
goto finish;
}
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.locale1", DEFAULT_EXIT_USEC, NULL, NULL);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index d5ea1d913c..44bda34aff 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -36,7 +36,7 @@
static const char* arg_what = "idle:sleep:shutdown";
static const char* arg_who = NULL;
static const char* arg_why = "Unknown reason";
-static const char* arg_mode = "block";
+static const char* arg_mode = NULL;
static enum {
ACTION_INHIBIT,
@@ -97,6 +97,9 @@ static int print_inhibitors(sd_bus *bus, sd_bus_error *error) {
while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
_cleanup_free_ char *comm = NULL, *u = NULL;
+ if (arg_mode && !streq(mode, arg_mode))
+ continue;
+
get_process_comm(pid, &comm);
u = uid_to_name(uid);
@@ -205,7 +208,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (arg_action == ACTION_INHIBIT && argc == 1)
+ if (arg_action == ACTION_INHIBIT && optind == argc)
arg_action = ACTION_LIST;
else if (arg_action == ACTION_INHIBIT && optind >= argc) {
@@ -232,7 +235,7 @@ int main(int argc, char *argv[]) {
r = sd_bus_default_system(&bus);
if (r < 0) {
- log_error("Failed to connect to bus: %s", strerror(-r));
+ log_error_errno(r, "Failed to connect to bus: %m");
return EXIT_FAILURE;
}
@@ -252,6 +255,9 @@ int main(int argc, char *argv[]) {
if (!arg_who)
arg_who = w = strv_join(argv + optind, " ");
+ if (!arg_mode)
+ arg_mode = "block";
+
fd = inhibit(bus, &error);
if (fd < 0) {
log_error("Failed to inhibit: %s", bus_error_message(&error, -r));
@@ -260,7 +266,7 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
return EXIT_FAILURE;
}
@@ -270,11 +276,11 @@ int main(int argc, char *argv[]) {
close_all_fds(NULL, 0);
execvp(argv[optind], argv + optind);
- log_error("Failed to execute %s: %m", argv[optind]);
+ log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
_exit(EXIT_FAILURE);
}
- r = wait_for_terminate_and_warn(argv[optind], pid);
+ r = wait_for_terminate_and_warn(argv[optind], pid, true);
return r < 0 ? EXIT_FAILURE : r;
}
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index fcdf6275e9..6505eb89c1 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -384,10 +384,8 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
int r;
r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
- if (r < 0) {
- log_error("Could not get properties: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not get properties: %m");
if (*new_line)
printf("\n");
@@ -498,7 +496,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
if (r < 0) {
- log_error("Could not get properties: %s", strerror(-r));
+ log_error_errno(r, "Could not get properties: %m");
goto finish;
}
@@ -562,7 +560,7 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
if (r < 0) {
- log_error("Could not get properties: %s", strerror(-r));
+ log_error_errno(r, "Could not get properties: %m");
goto finish;
}
@@ -617,7 +615,7 @@ static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
if (r < 0)
- log_error("Could not get properties: %s", strerror(-r));
+ log_error_errno(r, "Could not get properties: %m");
return r;
}
@@ -699,10 +697,8 @@ static int show_user(sd_bus *bus, char **args, unsigned n) {
uid_t uid;
r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
- if (r < 0) {
- log_error("Failed to look up user %s: %s", args[i], strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
r = sd_bus_call_method(
bus,
@@ -859,10 +855,8 @@ static int enable_linger(sd_bus *bus, char **args, unsigned n) {
uid_t uid;
r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
- if (r < 0) {
- log_error("Failed to look up user %s: %s", args[i], strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
r = sd_bus_call_method (
bus,
@@ -892,10 +886,8 @@ static int terminate_user(sd_bus *bus, char **args, unsigned n) {
uid_t uid;
r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
- if (r < 0) {
- log_error("Failed to look up user %s: %s", args[i], strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
r = sd_bus_call_method (
bus,
@@ -928,10 +920,8 @@ static int kill_user(sd_bus *bus, char **args, unsigned n) {
uid_t uid;
r = get_user_creds((const char**) (args+i), &uid, NULL, NULL, NULL);
- if (r < 0) {
- log_error("Failed to look up user %s: %s", args[i], strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to look up user %s: %m", args[i]);
r = sd_bus_call_method (
bus,
@@ -1308,7 +1298,7 @@ int main(int argc, char *argv[]) {
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
diff --git a/src/login/logind-button.c b/src/login/logind-button.c
index 57e619efe6..e22b106b3c 100644
--- a/src/login/logind-button.c
+++ b/src/login/logind-button.c
@@ -159,8 +159,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_POWER:
case KEY_POWER2:
log_struct(LOG_INFO,
- "MESSAGE=Power key pressed.",
- MESSAGE_ID(SD_MESSAGE_POWER_KEY),
+ LOG_MESSAGE("Power key pressed."),
+ LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY),
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
@@ -174,8 +174,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_SLEEP:
log_struct(LOG_INFO,
- "MESSAGE=Suspend key pressed.",
- MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
+ LOG_MESSAGE("Suspend key pressed."),
+ LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
@@ -183,8 +183,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
case KEY_SUSPEND:
log_struct(LOG_INFO,
- "MESSAGE=Hibernate key pressed.",
- MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
+ LOG_MESSAGE("Hibernate key pressed."),
+ LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
NULL);
manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
@@ -195,8 +195,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
if (ev.code == SW_LID) {
log_struct(LOG_INFO,
- "MESSAGE=Lid closed.",
- MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
+ LOG_MESSAGE("Lid closed."),
+ LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
NULL);
b->lid_closed = true;
@@ -205,8 +205,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
} else if (ev.code == SW_DOCK) {
log_struct(LOG_INFO,
- "MESSAGE=System docked.",
- MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
+ LOG_MESSAGE("System docked."),
+ LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
NULL);
b->docked = true;
@@ -216,8 +216,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
if (ev.code == SW_LID) {
log_struct(LOG_INFO,
- "MESSAGE=Lid opened.",
- MESSAGE_ID(SD_MESSAGE_LID_OPENED),
+ LOG_MESSAGE("Lid opened."),
+ LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED),
NULL);
b->lid_closed = false;
@@ -225,8 +225,8 @@ static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *u
} else if (ev.code == SW_DOCK) {
log_struct(LOG_INFO,
- "MESSAGE=System undocked.",
- MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
+ LOG_MESSAGE("System undocked."),
+ LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
NULL);
b->docked = false;
@@ -250,20 +250,18 @@ int button_open(Button *b) {
p = strappenda("/dev/input/", b->name);
b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
- if (b->fd < 0) {
- log_warning("Failed to open %s: %m", b->name);
- return -errno;
- }
+ if (b->fd < 0)
+ return log_warning_errno(errno, "Failed to open %s: %m", b->name);
if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
- log_error("Failed to get input name: %m");
+ log_error_errno(errno, "Failed to get input name: %m");
r = -errno;
goto fail;
}
r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
if (r < 0) {
- log_error("Failed to add button event: %s", strerror(-r));
+ log_error_errno(r, "Failed to add button event: %m");
goto fail;
}
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index ed7ea5da31..88694f9bac 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -551,7 +551,7 @@ bool manager_is_docked_or_multiple_displays(Manager *m) {
* assume that we are docked. */
n = manager_count_displays(m);
if (n < 0)
- log_warning("Display counting failed: %s", strerror(-n));
+ log_warning_errno(n, "Display counting failed: %m");
else if (n > 1) {
log_debug("Multiple (%i) displays connected.", n);
return true;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index f18d21055a..48395f6f94 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -41,7 +41,7 @@
#include "bus-util.h"
#include "bus-error.h"
#include "logind.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "udev-util.h"
static int property_get_idle_hint(
@@ -1159,7 +1159,7 @@ static int flush_devices(Manager *m) {
d = opendir("/etc/udev/rules.d");
if (!d) {
if (errno != ENOENT)
- log_warning("Failed to open /etc/udev/rules.d: %m");
+ log_warning_errno(errno, "Failed to open /etc/udev/rules.d: %m");
} else {
struct dirent *de;
@@ -1175,7 +1175,7 @@ static int flush_devices(Manager *m) {
continue;
if (unlinkat(dirfd(d), de->d_name, 0) < 0)
- log_warning("Failed to unlink %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to unlink %s: %m", de->d_name);
}
}
@@ -1300,9 +1300,11 @@ static int bus_manager_log_shutdown(
q = NULL;
}
- return log_struct(LOG_NOTICE, MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
+ return log_struct(LOG_NOTICE,
+ LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
p,
- q, NULL);
+ q,
+ NULL);
}
static int lid_switch_ignore_handler(sd_event_source *e, uint64_t usec, void *userdata) {
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index a9e14af8db..84fee0e773 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -138,7 +138,7 @@ int inhibitor_save(Inhibitor *i) {
finish:
if (r < 0)
- log_error("Failed to save inhibit data %s: %s", i->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
return r;
}
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 1a2f09c615..ff87f0f741 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -26,7 +26,7 @@
#include "util.h"
#include "bus-util.h"
#include "strv.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "bus-label.h"
#include "logind.h"
#include "logind-seat.h"
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 9992195151..8eb5e3ee0a 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -154,7 +154,7 @@ int seat_save(Seat *s) {
finish:
if (r < 0)
- log_error("Failed to save seat data %s: %s", s->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save seat data %s: %m", s->state_file);
return r;
}
@@ -201,7 +201,7 @@ int seat_preallocate_vts(Seat *s) {
q = vt_allocate(i);
if (q < 0) {
- log_error("Failed to preallocate VT %i: %s", i, strerror(-q));
+ log_error_errno(q, "Failed to preallocate VT %i: %m", i);
r = q;
}
}
@@ -221,7 +221,7 @@ int seat_apply_acls(Seat *s, Session *old_active) {
!!s->active, s->active ? s->active->user->uid : 0);
if (r < 0)
- log_error("Failed to apply ACLs: %s", strerror(-r));
+ log_error_errno(r, "Failed to apply ACLs: %m");
return r;
}
@@ -400,9 +400,9 @@ int seat_start(Seat *s) {
return 0;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SEAT_START),
+ LOG_MESSAGE_ID(SD_MESSAGE_SEAT_START),
"SEAT_ID=%s", s->id,
- "MESSAGE=New seat %s.", s->id,
+ LOG_MESSAGE("New seat %s.", s->id),
NULL);
/* Initialize VT magic stuff */
@@ -428,9 +428,9 @@ int seat_stop(Seat *s, bool force) {
if (s->started)
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SEAT_STOP),
+ LOG_MESSAGE_ID(SD_MESSAGE_SEAT_STOP),
"SEAT_ID=%s", s->id,
- "MESSAGE=Removed seat %s.", s->id,
+ LOG_MESSAGE("Removed seat %s.", s->id),
NULL);
seat_stop_sessions(s, force);
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 58836fce25..8607d03265 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -26,7 +26,7 @@
#include "util.h"
#include "strv.h"
#include "bus-util.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "bus-label.h"
#include "logind.h"
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 65bbb77750..ea1831dac6 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -292,7 +292,7 @@ int session_save(Session *s) {
finish:
if (r < 0)
- log_error("Failed to save session data %s: %s", s->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save session data %s: %m", s->state_file);
return r;
}
@@ -337,10 +337,8 @@ int session_load(Session *s) {
"CONTROLLER", &controller,
NULL);
- if (r < 0) {
- log_error("Failed to read %s: %s", s->state_file, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read %s: %m", s->state_file);
if (!s->user) {
uid_t u;
@@ -549,11 +547,11 @@ int session_start(Session *s) {
return r;
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SESSION_START),
+ LOG_MESSAGE_ID(SD_MESSAGE_SESSION_START),
"SESSION_ID=%s", s->id,
"USER_ID=%s", s->user->name,
"LEADER="PID_FMT, s->leader,
- "MESSAGE=New session %s of user %s.", s->id, s->user->name,
+ LOG_MESSAGE("New session %s of user %s.", s->id, s->user->name),
NULL);
if (!dual_timestamp_is_set(&s->timestamp))
@@ -652,11 +650,11 @@ int session_finalize(Session *s) {
if (s->started)
log_struct(s->class == SESSION_BACKGROUND ? LOG_DEBUG : LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
+ LOG_MESSAGE_ID(SD_MESSAGE_SESSION_STOP),
"SESSION_ID=%s", s->id,
"USER_ID=%s", s->user->name,
"LEADER="PID_FMT, s->leader,
- "MESSAGE=Removed session %s.", s->id,
+ LOG_MESSAGE("Removed session %s.", s->id),
NULL);
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
@@ -969,10 +967,8 @@ static int session_open_vt(Session *s) {
sprintf(path, "/dev/tty%u", s->vtnr);
s->vtfd = open(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
- if (s->vtfd < 0) {
- log_error("cannot open VT %s of session %s: %m", path, s->id);
- return -errno;
- }
+ if (s->vtfd < 0)
+ return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
return s->vtfd;
}
@@ -991,21 +987,21 @@ int session_prepare_vt(Session *s) {
r = fchown(vt, s->user->uid, -1);
if (r < 0) {
r = -errno;
- log_error("Cannot change owner of /dev/tty%u: %m", s->vtnr);
+ log_error_errno(errno, "Cannot change owner of /dev/tty%u: %m", s->vtnr);
goto error;
}
r = ioctl(vt, KDSKBMODE, K_OFF);
if (r < 0) {
r = -errno;
- log_error("Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
+ log_error_errno(errno, "Cannot set K_OFF on /dev/tty%u: %m", s->vtnr);
goto error;
}
r = ioctl(vt, KDSETMODE, KD_GRAPHICS);
if (r < 0) {
r = -errno;
- log_error("Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
+ log_error_errno(errno, "Cannot set KD_GRAPHICS on /dev/tty%u: %m", s->vtnr);
goto error;
}
@@ -1018,7 +1014,7 @@ int session_prepare_vt(Session *s) {
r = ioctl(vt, VT_SETMODE, &mode);
if (r < 0) {
r = -errno;
- log_error("Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
+ log_error_errno(errno, "Cannot set VT_PROCESS on /dev/tty%u: %m", s->vtnr);
goto error;
}
@@ -1075,7 +1071,7 @@ void session_leave_vt(Session *s) {
session_device_pause_all(s);
r = ioctl(s->vtfd, VT_RELDISP, 1);
if (r < 0)
- log_debug("Cannot release VT of session %s: %m", s->id);
+ log_debug_errno(errno, "Cannot release VT of session %s: %m", s->id);
}
bool session_is_controller(Session *s, const char *sender) {
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 1205b48abb..9ff1302663 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -252,7 +252,7 @@ int user_save(User *u) {
finish:
if (r < 0)
- log_error("Failed to save user data %s: %s", u->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save user data %s: %m", u->state_file);
return r;
}
@@ -278,7 +278,7 @@ int user_load(User *u) {
if (r == -ENOENT)
return 0;
- log_error("Failed to read %s: %s", u->state_file, strerror(-r));
+ log_error_errno(r, "Failed to read %s: %m", u->state_file);
return r;
}
@@ -310,10 +310,8 @@ static int user_mkdir_runtime_path(User *u) {
assert(u);
r = mkdir_safe_label("/run/user", 0755, 0, 0);
- if (r < 0) {
- log_error("Failed to create /run/user: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /run/user: %m");
if (!u->runtime_path) {
if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
@@ -338,7 +336,7 @@ static int user_mkdir_runtime_path(User *u) {
r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
if (r < 0) {
- log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
+ log_error_errno(r, "Failed to mount per-user tmpfs directory %s: %m", p);
goto fail;
}
}
@@ -510,14 +508,14 @@ static int user_remove_runtime_path(User *u) {
r = rm_rf(u->runtime_path, false, false, false);
if (r < 0)
- log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
+ log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
if (umount2(u->runtime_path, MNT_DETACH) < 0)
- log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
+ log_error_errno(errno, "Failed to unmount user runtime directory %s: %m", u->runtime_path);
r = rm_rf(u->runtime_path, false, true, false);
if (r < 0)
- log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
+ log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path);
free(u->runtime_path);
u->runtime_path = NULL;
diff --git a/src/login/logind.c b/src/login/logind.c
index 8f00c46339..b44f376427 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -290,7 +290,7 @@ static int manager_enumerate_seats(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /run/systemd/seats: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
return -errno;
}
@@ -327,7 +327,7 @@ static int manager_enumerate_linger_users(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /var/lib/systemd/linger/: %m");
+ log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
return -errno;
}
@@ -339,7 +339,7 @@ static int manager_enumerate_linger_users(Manager *m) {
k = manager_add_user_by_name(m, de->d_name, NULL);
if (k < 0) {
- log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
+ log_notice_errno(k, "Couldn't add lingering user %s: %m", de->d_name);
r = k;
}
}
@@ -363,7 +363,7 @@ static int manager_enumerate_users(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /run/systemd/users: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/users: %m");
return -errno;
}
@@ -375,7 +375,7 @@ static int manager_enumerate_users(Manager *m) {
k = manager_add_user_by_name(m, de->d_name, &u);
if (k < 0) {
- log_error("Failed to add user by file name %s: %s", de->d_name, strerror(-k));
+ log_error_errno(k, "Failed to add user by file name %s: %m", de->d_name);
r = k;
continue;
@@ -404,7 +404,7 @@ static int manager_enumerate_sessions(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /run/systemd/sessions: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
return -errno;
}
@@ -423,7 +423,7 @@ static int manager_enumerate_sessions(Manager *m) {
k = manager_add_session(m, de->d_name, &s);
if (k < 0) {
- log_error("Failed to add session by file name %s: %s", de->d_name, strerror(-k));
+ log_error_errno(k, "Failed to add session by file name %s: %m", de->d_name);
r = k;
continue;
@@ -451,7 +451,7 @@ static int manager_enumerate_inhibitors(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /run/systemd/inhibit: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
return -errno;
}
@@ -464,7 +464,7 @@ static int manager_enumerate_inhibitors(Manager *m) {
k = manager_add_inhibitor(m, de->d_name, &i);
if (k < 0) {
- log_notice("Couldn't add inhibitor %s: %s", de->d_name, strerror(-k));
+ log_notice_errno(k, "Couldn't add inhibitor %s: %m", de->d_name);
r = k;
continue;
}
@@ -568,7 +568,7 @@ static int manager_reserve_vt(Manager *m) {
/* Don't complain on VT-less systems */
if (errno != ENOENT)
- log_warning("Failed to pin reserved VT: %m");
+ log_warning_errno(errno, "Failed to pin reserved VT: %m");
return -errno;
}
@@ -583,52 +583,36 @@ static int manager_connect_bus(Manager *m) {
assert(!m->bus);
r = sd_bus_default_system(&m->bus);
- if (r < 0) {
- log_error("Failed to connect to system bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/login1", "org.freedesktop.login1.Manager", manager_vtable, m);
- if (r < 0) {
- log_error("Failed to add manager object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add manager object vtable: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/seat", "org.freedesktop.login1.Seat", seat_vtable, seat_object_find, m);
- if (r < 0) {
- log_error("Failed to add seat object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add seat object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/seat", seat_node_enumerator, m);
- if (r < 0) {
- log_error("Failed to add seat enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add seat enumerator: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/session", "org.freedesktop.login1.Session", session_vtable, session_object_find, m);
- if (r < 0) {
- log_error("Failed to add session object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add session object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/session", session_node_enumerator, m);
- if (r < 0) {
- log_error("Failed to add session enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add session enumerator: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/login1/user", "org.freedesktop.login1.User", user_vtable, user_object_find, m);
- if (r < 0) {
- log_error("Failed to add user object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add user object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/login1/user", user_node_enumerator, m);
- if (r < 0) {
- log_error("Failed to add user enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add user enumerator: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -638,10 +622,8 @@ static int manager_connect_bus(Manager *m) {
"member='NameOwnerChanged',"
"path='/org/freedesktop/DBus'",
match_name_owner_changed, m);
- if (r < 0) {
- log_error("Failed to add match for NameOwnerChanged: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for NameOwnerChanged: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -651,10 +633,8 @@ static int manager_connect_bus(Manager *m) {
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'",
match_job_removed, m);
- if (r < 0) {
- log_error("Failed to add match for JobRemoved: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for JobRemoved: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -664,10 +644,8 @@ static int manager_connect_bus(Manager *m) {
"member='UnitRemoved',"
"path='/org/freedesktop/systemd1'",
match_unit_removed, m);
- if (r < 0) {
- log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -676,10 +654,8 @@ static int manager_connect_bus(Manager *m) {
"interface='org.freedesktop.DBus.Properties',"
"member='PropertiesChanged'",
match_properties_changed, m);
- if (r < 0) {
- log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -689,10 +665,8 @@ static int manager_connect_bus(Manager *m) {
"member='Reloading',"
"path='/org/freedesktop/systemd1'",
match_reloading, m);
- if (r < 0) {
- log_error("Failed to add match for Reloading: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for Reloading: %m");
r = sd_bus_call_method(
m->bus,
@@ -708,16 +682,12 @@ static int manager_connect_bus(Manager *m) {
}
r = sd_bus_request_name(m->bus, "org.freedesktop.login1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
return 0;
}
@@ -783,7 +753,7 @@ static int manager_connect_console(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /sys/class/tty/tty0/active: %m");
+ log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
return -errno;
}
@@ -806,16 +776,12 @@ static int manager_connect_console(Manager *m) {
}
r = ignore_signals(SIGRTMIN + 1, -1);
- if (r < 0) {
- log_error("Cannot ignore SIGRTMIN + 1: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot ignore SIGRTMIN + 1: %m");
r = sigprocmask_many(SIG_BLOCK, SIGRTMIN, -1);
- if (r < 0) {
- log_error("Cannot block SIGRTMIN: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Cannot block SIGRTMIN: %m");
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
if (r < 0)
@@ -1016,28 +982,20 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
CLOCK_MONOTONIC,
elapse, USEC_PER_SEC*30,
manager_dispatch_idle_action, m);
- if (r < 0) {
- log_error("Failed to add idle event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add idle event source: %m");
r = sd_event_source_set_priority(m->idle_action_event_source, SD_EVENT_PRIORITY_IDLE+10);
- if (r < 0) {
- log_error("Failed to set idle event source priority: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set idle event source priority: %m");
} else {
r = sd_event_source_set_time(m->idle_action_event_source, elapse);
- if (r < 0) {
- log_error("Failed to set idle event timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set idle event timer: %m");
r = sd_event_source_set_enabled(m->idle_action_event_source, SD_EVENT_ONESHOT);
- if (r < 0) {
- log_error("Failed to enable idle event timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable idle event timer: %m");
}
return 0;
@@ -1061,10 +1019,8 @@ int manager_startup(Manager *m) {
/* Connect to udev */
r = manager_connect_udev(m);
- if (r < 0) {
- log_error("Failed to create udev watchers: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create udev watchers: %m");
/* Connect to the bus */
r = manager_connect_bus(m);
@@ -1073,39 +1029,37 @@ int manager_startup(Manager *m) {
/* Instantiate magic seat 0 */
r = manager_add_seat(m, "seat0", &m->seat0);
- if (r < 0) {
- log_error("Failed to add seat0: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add seat0: %m");
r = manager_set_lid_switch_ignore(m, 0 + IGNORE_LID_SWITCH_STARTUP_USEC);
if (r < 0)
- log_warning("Failed to set up lid switch ignore event source: %s", strerror(-r));
+ log_warning_errno(r, "Failed to set up lid switch ignore event source: %m");
/* Deserialize state */
r = manager_enumerate_devices(m);
if (r < 0)
- log_warning("Device enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "Device enumeration failed: %m");
r = manager_enumerate_seats(m);
if (r < 0)
- log_warning("Seat enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "Seat enumeration failed: %m");
r = manager_enumerate_users(m);
if (r < 0)
- log_warning("User enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "User enumeration failed: %m");
r = manager_enumerate_sessions(m);
if (r < 0)
- log_warning("Session enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "Session enumeration failed: %m");
r = manager_enumerate_inhibitors(m);
if (r < 0)
- log_warning("Inhibitor enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "Inhibitor enumeration failed: %m");
r = manager_enumerate_buttons(m);
if (r < 0)
- log_warning("Button enumeration failed: %s", strerror(-r));
+ log_warning_errno(r, "Button enumeration failed: %m");
/* Remove stale objects before we start them */
manager_gc(m, false);
@@ -1171,10 +1125,11 @@ int manager_run(Manager *m) {
static int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse(NULL, "/etc/systemd/logind.conf", NULL,
- "Login\0",
- config_item_perf_lookup, logind_gperf_lookup,
- false, false, true, m);
+ return config_parse_many("/etc/systemd/logind.conf",
+ CONF_DIRS_NULSTR("systemd/logind.conf"),
+ "Login\0",
+ config_item_perf_lookup, logind_gperf_lookup,
+ false, m);
}
int main(int argc, char *argv[]) {
@@ -1213,7 +1168,7 @@ int main(int argc, char *argv[]) {
r = manager_startup(m);
if (r < 0) {
- log_error("Failed to fully start up daemon: %s", strerror(-r));
+ log_error_errno(r, "Failed to fully start up daemon: %m");
goto finish;
}
diff --git a/src/login/logind.conf b/src/login/logind.conf
index 4608a2c0e2..6b1943a2d1 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/logind.conf.d/*.conf.
+#
# See logind.conf(5) for details
[Login]
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 0c71177deb..111e2b7c4c 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -114,7 +114,7 @@ static int get_user_data(
}
*ret_pw = pw;
- *ret_username = username ? username : pw->pw_name;
+ *ret_username = username;
return PAM_SUCCESS;
}
@@ -180,11 +180,10 @@ static int export_legacy_dbus_address(
int r;
/* skip export if kdbus is not active */
- if (access("/dev/kdbus", F_OK) < 0)
+ if (access("/sys/fs/kdbus", F_OK) < 0)
return PAM_SUCCESS;
- if (asprintf(&s, KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT,
- uid, runtime) < 0) {
+ if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0) {
pam_syslog(handle, LOG_ERR, "Failed to set bus variable.");
return PAM_BUF_ERR;
}
diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c
index 21d2339616..5379ffcaa1 100644
--- a/src/login/test-inhibit.c
+++ b/src/login/test-inhibit.c
@@ -42,11 +42,11 @@ static int inhibit(sd_bus *bus, const char *what) {
&error,
&reply,
"ssss", what, who, reason, mode);
- assert(r >= 0);
+ assert_se(r >= 0);
r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &fd);
- assert(r >= 0);
- assert(fd >= 0);
+ assert_se(r >= 0);
+ assert_se(fd >= 0);
return dup(fd);
}
@@ -67,10 +67,10 @@ static void print_inhibitors(sd_bus *bus) {
&error,
&reply,
"");
- assert(r >= 0);
+ assert_se(r >= 0);
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
- assert(r >= 0);
+ assert_se(r >= 0);
while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
printf("what=<%s> who=<%s> why=<%s> mode=<%s> uid=<"UID_FMT"> pid=<"PID_FMT">\n",
@@ -78,7 +78,7 @@ static void print_inhibitors(sd_bus *bus) {
n++;
}
- assert(r >= 0);
+ assert_se(r >= 0);
printf("%u inhibitors\n", n);
}
@@ -89,16 +89,16 @@ int main(int argc, char*argv[]) {
int r;
r = sd_bus_open_system(&bus);
- assert(r >= 0);
+ assert_se(r >= 0);
print_inhibitors(bus);
fd1 = inhibit(bus, "sleep");
- assert(fd1 >= 0);
+ assert_se(fd1 >= 0);
print_inhibitors(bus);
fd2 = inhibit(bus, "idle:shutdown");
- assert(fd2 >= 0);
+ assert_se(fd2 >= 0);
print_inhibitors(bus);
safe_close(fd1);
diff --git a/src/login/user-sessions.c b/src/login/user-sessions.c
index ca5de41f40..6edb823e8c 100644
--- a/src/login/user-sessions.c
+++ b/src/login/user-sessions.c
@@ -44,7 +44,7 @@ int main(int argc, char*argv[]) {
int r = 0;
if (unlink("/run/nologin") < 0 && errno != ENOENT) {
- log_error("Failed to remove /run/nologin file: %m");
+ log_error_errno(errno, "Failed to remove /run/nologin file: %m");
r = -errno;
}
@@ -55,7 +55,7 @@ int main(int argc, char*argv[]) {
* exist), don't complain */
if (errno != EROFS || access("/etc/nologin", F_OK) >= 0) {
- log_error("Failed to remove /etc/nologin file: %m");
+ log_error_errno(errno, "Failed to remove /etc/nologin file: %m");
return EXIT_FAILURE;
}
}
@@ -68,7 +68,7 @@ int main(int argc, char*argv[]) {
r = write_string_file_atomic("/run/nologin", "System is going down.");
if (r < 0) {
- log_error("Failed to create /run/nologin: %s", strerror(-r));
+ log_error_errno(r, "Failed to create /run/nologin: %m");
return EXIT_FAILURE;
}
diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c
new file mode 100644
index 0000000000..c7e4de8889
--- /dev/null
+++ b/src/machine-id-commit/machine-id-commit.c
@@ -0,0 +1,105 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Didier Roche
+
+ 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include "machine-id-setup.h"
+#include "log.h"
+#include "build.h"
+
+static const char *arg_root = "";
+
+static void help(void) {
+ printf("%s [OPTIONS...]\n\n"
+ "Commit a transient /etc/machine-id on disk if writable.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --root=ROOT Filesystem root\n",
+ program_invocation_short_name);
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ enum {
+ ARG_VERSION = 0x100,
+ ARG_ROOT,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "root", required_argument, NULL, ARG_ROOT },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
+ switch (c) {
+
+ case 'h':
+ help();
+ return 0;
+
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0;
+
+ case ARG_ROOT:
+ arg_root = optarg;
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ assert_not_reached("Unhandled option");
+ }
+
+ if (optind < argc) {
+ log_error("Extraneous arguments");
+ return -EINVAL;
+ }
+
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+
+ return machine_id_commit(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index f12ce98a84..72ae6c6535 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -27,7 +27,7 @@
#include "bus-util.h"
#include "bus-label.h"
#include "strv.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "copy.h"
#include "fileio.h"
#include "in-addr-util.h"
@@ -207,7 +207,7 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
_exit(EXIT_FAILURE);
- n = local_addresses(NULL, 0, &addresses);
+ n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
if (n < 0)
_exit(EXIT_FAILURE);
diff --git a/src/machine/machine.c b/src/machine/machine.c
index 13d3448adf..0d84213eea 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -216,7 +216,7 @@ finish:
if (temp_path)
unlink(temp_path);
- log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
}
return r;
@@ -259,8 +259,7 @@ int machine_load(Machine *m) {
if (r == -ENOENT)
return 0;
- log_error("Failed to read %s: %s", m->state_file, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to read %s: %m", m->state_file);
}
if (id)
@@ -377,10 +376,10 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
return r;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_MACHINE_START),
+ LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
"NAME=%s", m->name,
"LEADER="PID_FMT, m->leader,
- "MESSAGE=New machine %s.", m->name,
+ LOG_MESSAGE("New machine %s.", m->name),
NULL);
if (!dual_timestamp_is_set(&m->timestamp))
@@ -426,10 +425,10 @@ int machine_stop(Machine *m) {
if (m->started)
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
+ LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
"NAME=%s", m->name,
"LEADER="PID_FMT, m->leader,
- "MESSAGE=Machine %s terminated.", m->name,
+ LOG_MESSAGE("Machine %s terminated.", m->name),
NULL);
/* Kill cgroup */
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 7491d69c8b..f604263d8f 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -44,6 +44,7 @@
#include "cgroup-show.h"
#include "cgroup-util.h"
#include "ptyfwd.h"
+#include "event-util.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -413,10 +414,8 @@ static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_
path,
map,
&info);
- if (r < 0) {
- log_error("Could not get properties: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not get properties: %m");
if (*new_line)
printf("\n");
@@ -444,7 +443,7 @@ static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
if (r < 0)
- log_error("Could not get properties: %s", strerror(-r));
+ log_error_errno(r, "Could not get properties: %m");
return r;
}
@@ -662,12 +661,14 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL, *reply3 = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
+ _cleanup_event_unref_ sd_event *event = NULL;
_cleanup_close_ int master = -1;
_cleanup_free_ char *getty = NULL;
const char *path, *pty, *p;
uint32_t leader;
sigset_t mask;
- int r;
+ int r, ret = 0;
assert(bus);
assert(args);
@@ -677,6 +678,14 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
return -ENOTSUP;
}
+ r = sd_event_default(&event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get event loop: %m");
+
+ r = sd_bus_attach_event(bus, event, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
+
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
@@ -704,26 +713,20 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
&error,
&reply2,
"u");
- if (r < 0) {
- log_error("Failed to retrieve PID of leader: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve PID of leader: %m");
r = sd_bus_message_read(reply2, "u", &leader);
if (r < 0)
return bus_log_parse_error(r);
master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
- if (master < 0) {
- log_error("Failed to acquire pseudo tty: %s", strerror(-master));
- return master;
- }
+ if (master < 0)
+ return log_error_errno(master, "Failed to acquire pseudo tty: %m");
pty = ptsname(master);
- if (!pty) {
- log_error("Failed to get pty name: %m");
- return -errno;
- }
+ if (!pty)
+ return log_error_errno(errno, "Failed to get pty name: %m");
p = startswith(pty, "/dev/pts/");
if (!p) {
@@ -732,19 +735,15 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
}
r = sd_bus_open_system_container(&container_bus, args[1]);
- if (r < 0) {
- log_error("Failed to get container bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get container bus: %m");
getty = strjoin("container-getty@", p, ".service", NULL);
if (!getty)
return log_oom();
- if (unlockpt(master) < 0) {
- log_error("Failed to unlock tty: %m");
- return -errno;
- }
+ if (unlockpt(master) < 0)
+ return log_error_errno(errno, "Failed to unlock tty: %m");
r = sd_bus_call_method(container_bus,
"org.freedesktop.systemd1",
@@ -766,17 +765,25 @@ static int login_machine(sd_bus *bus, char **args, unsigned n) {
log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
- r = process_pty(master, &mask, 0, 0);
- if (r < 0) {
- log_error("Failed to process pseudo tty: %s", strerror(-r));
- return r;
- }
+ sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+
+ r = pty_forward_new(event, master, &forward);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create PTY forwarder: %m");
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ forward = pty_forward_free(forward);
fputc('\n', stdout);
log_info("Connection to container %s terminated.", args[1]);
- return 0;
+ sd_event_get_exit_code(event, &ret);
+ return ret;
}
static void help(void) {
@@ -1002,7 +1009,7 @@ int main(int argc, char*argv[]) {
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 3c7d4be8d2..0b57b3699c 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -36,7 +36,7 @@
#include "utf8.h"
#include "unit-name.h"
#include "bus-util.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "time-util.h"
#include "cgroup-util.h"
#include "machined.h"
@@ -442,8 +442,8 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
- SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
+ SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
@@ -622,6 +622,10 @@ int manager_start_scope(
if (r < 0)
return r;
+ r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
+ if (r < 0)
+ return r;
+
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
diff --git a/src/machine/machined.c b/src/machine/machined.c
index 966475b242..ef59497fb2 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -96,7 +96,7 @@ int manager_enumerate_machines(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open /run/systemd/machines: %m");
+ log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
return -errno;
}
@@ -113,7 +113,7 @@ int manager_enumerate_machines(Manager *m) {
k = manager_add_machine(m, de->d_name, &machine);
if (k < 0) {
- log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
+ log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
r = k;
continue;
@@ -137,28 +137,20 @@ static int manager_connect_bus(Manager *m) {
assert(!m->bus);
r = sd_bus_default_system(&m->bus);
- if (r < 0) {
- log_error("Failed to connect to system bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
- if (r < 0) {
- log_error("Failed to add manager object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add manager object vtable: %m");
r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
- if (r < 0) {
- log_error("Failed to add machine object vtable: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add machine object vtable: %m");
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
- if (r < 0) {
- log_error("Failed to add machine enumerator: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add machine enumerator: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -169,10 +161,8 @@ static int manager_connect_bus(Manager *m) {
"path='/org/freedesktop/systemd1'",
match_job_removed,
m);
- if (r < 0) {
- log_error("Failed to add match for JobRemoved: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for JobRemoved: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -183,10 +173,8 @@ static int manager_connect_bus(Manager *m) {
"path='/org/freedesktop/systemd1'",
match_unit_removed,
m);
- if (r < 0) {
- log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -196,10 +184,8 @@ static int manager_connect_bus(Manager *m) {
"member='PropertiesChanged'",
match_properties_changed,
m);
- if (r < 0) {
- log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
r = sd_bus_add_match(m->bus,
NULL,
@@ -210,10 +196,8 @@ static int manager_connect_bus(Manager *m) {
"path='/org/freedesktop/systemd1'",
match_reloading,
m);
- if (r < 0) {
- log_error("Failed to add match for Reloading: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match for Reloading: %m");
r = sd_bus_call_method(
m->bus,
@@ -229,16 +213,12 @@ static int manager_connect_bus(Manager *m) {
}
r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
return 0;
}
@@ -335,7 +315,7 @@ int main(int argc, char *argv[]) {
r = manager_startup(m);
if (r < 0) {
- log_error("Failed to fully start up daemon: %s", strerror(-r));
+ log_error_errno(r, "Failed to fully start up daemon: %m");
goto finish;
}
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index c77b092a62..5f678789ce 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -38,21 +38,13 @@
static char **arg_proc_cmdline_modules = NULL;
-static const char conf_file_dirs[] =
- "/etc/modules-load.d\0"
- "/run/modules-load.d\0"
- "/usr/local/lib/modules-load.d\0"
- "/usr/lib/modules-load.d\0"
-#ifdef HAVE_SPLIT_USR
- "/lib/modules-load.d\0"
-#endif
- ;
+static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load");
static void systemd_kmod_log(void *data, int priority, const char *file, int line,
const char *fn, const char *format, va_list args) {
DISABLE_WARNING_FORMAT_NONLITERAL;
- log_metav(priority, file, line, fn, format, args);
+ log_internalv(priority, 0, file, line, fn, format, args);
REENABLE_WARNING;
}
@@ -89,10 +81,8 @@ static int load_module(struct kmod_ctx *ctx, const char *m) {
log_debug("load: %s", m);
r = kmod_module_new_from_lookup(ctx, m, &modlist);
- if (r < 0) {
- log_error("Failed to lookup alias '%s': %s", m, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to lookup alias '%s': %m", m);
if (!modlist) {
log_error("Failed to find module '%s'", m);
@@ -124,8 +114,7 @@ static int load_module(struct kmod_ctx *ctx, const char *m) {
else if (err == KMOD_PROBE_APPLY_BLACKLIST)
log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
else {
- log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
- strerror(-err));
+ log_error_errno(err, "Failed to insert '%s': %m", kmod_module_get_name(mod));
r = err;
}
}
@@ -150,8 +139,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
if (ignore_enoent && r == -ENOENT)
return 0;
- log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to open %s, ignoring: %m", path);
}
log_debug("apply: %s", path);
@@ -163,7 +151,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
if (feof(f))
break;
- log_error("Failed to read file '%s', ignoring: %m", path);
+ log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
return -errno;
}
@@ -243,8 +231,9 @@ int main(int argc, char *argv[]) {
umask(0022);
- if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
- return EXIT_FAILURE;
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
ctx = kmod_new(NULL, NULL);
if (!ctx) {
@@ -278,7 +267,7 @@ int main(int argc, char *argv[]) {
k = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (k < 0) {
- log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
+ log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
if (r == 0)
r = k;
goto finish;
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index b374121fbc..815ea1698d 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -34,6 +34,7 @@
#include "arphrd-list.h"
#include "local-addresses.h"
#include "socket-util.h"
+#include "ether-addr-util.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -190,16 +191,12 @@ static int list_links(char **args, unsigned n) {
pager_open_if_enabled();
r = sd_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
- if (!udev) {
- log_error("Failed to connect to udev: %m");
- return -errno;
- }
+ if (!udev)
+ return log_error_errno(errno, "Failed to connect to udev: %m");
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
@@ -210,10 +207,8 @@ static int list_links(char **args, unsigned n) {
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0) {
- log_error("Failed to enumerate links: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate links: %m");
if (arg_legend)
printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
@@ -253,11 +248,171 @@ static int list_links(char **args, unsigned n) {
return 0;
}
+/* IEEE Organizationally Unique Identifier vendor string */
+static int ieee_oui(struct udev_hwdb *hwdb, struct ether_addr *mac, char **ret) {
+ struct udev_list_entry *entry;
+ char *description;
+ char str[strlen("OUI:XXYYXXYYXXYY") + 1];
+
+ /* skip commonly misused 00:00:00 (Xerox) prefix */
+ if (memcmp(mac, "\0\0\0", 3) == 0)
+ return -EINVAL;
+
+ snprintf(str, sizeof(str), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
+
+ udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, str, 0))
+ if (strcmp(udev_list_entry_get_name(entry), "ID_OUI_FROM_DATABASE") == 0) {
+ description = strdup(udev_list_entry_get_value(entry));
+ if (!description)
+ return -ENOMEM;
+
+ *ret = description;
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+static int get_gateway_description(sd_rtnl *rtnl, struct udev_hwdb *hwdb, int ifindex, int family,
+ union in_addr_union *gateway, char **gateway_description) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+ sd_rtnl_message *m;
+ int r;
+
+ assert(rtnl);
+ assert(ifindex >= 0);
+ assert(family == AF_INET || family == AF_INET6);
+ assert(gateway);
+ assert(gateway_description);
+
+ r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_call(rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (m = reply; m; m = sd_rtnl_message_next(m)) {
+ union in_addr_union gw = {};
+ struct ether_addr mac = {};
+ uint16_t type;
+ int ifi, fam;
+
+ r = sd_rtnl_message_get_errno(m);
+ if (r < 0) {
+ log_error_errno(r, "got error: %m");
+ continue;
+ }
+
+ r = sd_rtnl_message_get_type(m, &type);
+ if (r < 0) {
+ log_error_errno(r, "could not get type: %m");
+ continue;
+ }
+
+ if (type != RTM_NEWNEIGH) {
+ log_error("type is not RTM_NEWNEIGH");
+ continue;
+ }
+
+ r = sd_rtnl_message_neigh_get_family(m, &fam);
+ if (r < 0) {
+ log_error_errno(r, "could not get family: %m");
+ continue;
+ }
+
+ if (fam != family) {
+ log_error("family is not correct");
+ continue;
+ }
+
+ r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
+ if (r < 0) {
+ log_error_errno(r, "could not get ifindex: %m");
+ continue;
+ }
+
+ if (ifindex > 0 && ifi != ifindex)
+ continue;
+
+ switch (fam) {
+ case AF_INET:
+ r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
+ if (r < 0)
+ continue;
+
+ break;
+ case AF_INET6:
+ r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
+ if (r < 0)
+ continue;
+
+ break;
+ default:
+ continue;
+ }
+
+ if (!in_addr_equal(fam, &gw, gateway))
+ continue;
+
+ r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
+ if (r < 0)
+ continue;
+
+ r = ieee_oui(hwdb, &mac, gateway_description);
+ if (r < 0)
+ continue;
+
+ return 0;
+ }
+
+ return -ENODATA;
+}
+
+static int dump_gateways(sd_rtnl *rtnl, struct udev_hwdb *hwdb, const char *prefix, int ifindex) {
+ _cleanup_free_ struct local_address *local = NULL;
+ int r, n, i;
+
+ n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
+ if (n < 0)
+ return n;
+
+ for (i = 0; i < n; i++) {
+ _cleanup_free_ char *gateway = NULL, *description = NULL;
+
+ r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
+ if (r < 0)
+ return r;
+
+ r = get_gateway_description(rtnl, hwdb, ifindex, local[i].family, &local[i].address, &description);
+ if (r < 0)
+ log_debug_errno(r, "Could not get description of gateway: %m");
+
+ if (description)
+ printf("%*s%s (%s)\n",
+ (int) strlen(prefix),
+ i == 0 ? prefix : "",
+ gateway, description);
+ else
+ printf("%*s%s\n",
+ (int) strlen(prefix),
+ i == 0 ? prefix : "",
+ gateway);
+ }
+
+ return 0;
+}
+
static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
- n = local_addresses(rtnl, ifindex, &local);
+ n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
@@ -293,6 +448,7 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ _cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
@@ -322,10 +478,8 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0) {
- log_error("Failed to query link: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query link: %m");
r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
if (r < 0)
@@ -428,6 +582,10 @@ static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
if (mtu > 0)
printf(" MTU: %u\n", mtu);
+ hwdb = udev_hwdb_new(udev);
+
+ dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
+
dump_addresses(rtnl, " Address: ", ifindex);
if (!strv_isempty(dns))
@@ -447,16 +605,12 @@ static int link_status(char **args, unsigned n) {
int r;
r = sd_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
- if (!udev) {
- log_error("Failed to connect to udev: %m");
- return -errno;
- }
+ if (!udev)
+ return log_error_errno(errno, "Failed to connect to udev: %m");
if (n <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
@@ -470,7 +624,7 @@ static int link_status(char **args, unsigned n) {
printf(" State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
- c = local_addresses(rtnl, 0, &addresses);
+ c = local_addresses(rtnl, 0, AF_UNSPEC, &addresses);
for (i = 0; i < c; i++) {
_cleanup_free_ char *pretty = NULL;
@@ -513,10 +667,8 @@ static int link_status(char **args, unsigned n) {
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0) {
- log_error("Failed to enumerate links: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate links: %m");
c = decode_and_sort_links(reply, &links);
if (c < 0)
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index ce85109d22..a85e8fa21e 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -117,33 +117,23 @@ int address_drop(Address *address, Link *link,
r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
link->ifindex, address->family);
- if (r < 0) {
- log_error("Could not allocate RTM_DELADDR message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ 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) {
- log_error("Could not set prefixlen: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set prefixlen: %m");
if (address->family == AF_INET)
r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
else if (address->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
- if (r < 0) {
- log_error("Could not append IFA_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_error("Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -163,70 +153,47 @@ int address_update(Address *address, Link *link,
r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
link->ifindex, address->family);
- if (r < 0) {
- log_error("Could not allocate RTM_NEWADDR message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
- if (r < 0) {
- log_error("Could not set prefixlen: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set prefixlen: %m");
r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
- if (r < 0) {
- log_error("Could not set flags: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set flags: %m");
r = sd_rtnl_message_addr_set_scope(req, address->scope);
- if (r < 0) {
- log_error("Could not set scope: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set scope: %m");
if (address->family == AF_INET)
r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
else if (address->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
- if (r < 0) {
- log_error("Could not append IFA_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
if (address->family == AF_INET) {
r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
- if (r < 0) {
- log_error("Could not append IFA_BROADCAST attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
}
if (address->label) {
r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
- if (r < 0) {
- log_error("Could not append IFA_LABEL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
}
r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
- if (r < 0) {
- log_error("Could not append IFA_CACHEINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_error("Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -251,11 +218,11 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
* Then let's acquire something more useful from the pool. */
r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
if (r < 0) {
- log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r));
+ log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
return r;
}
if (r == 0) {
- log_error_link(link, "Couldn't find free address for interface, all taken.");
+ log_link_error(link, "Couldn't find free address for interface, all taken.");
return -EBUSY;
}
@@ -312,83 +279,57 @@ int address_configure(Address *address, Link *link,
r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
link->ifindex, address->family);
- if (r < 0) {
- log_error("Could not allocate RTM_NEWADDR message: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
- if (r < 0) {
- log_error("Could not set prefixlen: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set prefixlen: %m");
r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
- if (r < 0) {
- log_error("Could not set flags: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set flags: %m");
r = sd_rtnl_message_addr_set_scope(req, address->scope);
- if (r < 0) {
- log_error("Could not set scope: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set scope: %m");
if (address->family == AF_INET)
r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
else if (address->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
- if (r < 0) {
- log_error("Could not append IFA_LOCAL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
if (address->family == AF_INET)
r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
else if (address->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
- if (r < 0) {
- log_error("Could not append IFA_ADDRESS attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
} else {
if (address->family == AF_INET) {
r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
- if (r < 0) {
- log_error("Could not append IFA_BROADCAST attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
}
}
if (address->label) {
r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
- if (r < 0) {
- log_error("Could not append IFA_LABEL attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
}
r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
&address->cinfo);
- if (r < 0) {
- log_error("Could not append IFA_CACHEINFO attribute: %s",
- strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_error("Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 63bfa86f99..1c2edc5b87 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -38,7 +38,7 @@ static int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_error_link(link, "could not set DHCPv4 route: %s",
+ log_link_error(link, "could not set DHCPv4 route: %s",
strerror(-r));
link_enter_failed(link);
}
@@ -61,7 +61,7 @@ static int link_set_dhcp_routes(Link *link) {
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r < 0 && r != -ENOENT) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: could not get gateway: %s",
strerror(-r));
return r;
@@ -73,7 +73,7 @@ static int link_set_dhcp_routes(Link *link) {
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: could not get address: %s",
strerror(-r));
return r;
@@ -81,7 +81,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_new_dynamic(&route, RTPROT_DHCP);
if (r < 0) {
- log_error_link(link,
+ log_link_error(link,
"Could not allocate route: %s",
strerror(-r));
return r;
@@ -89,7 +89,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_new_dynamic(&route_gw, RTPROT_DHCP);
if (r < 0) {
- log_error_link(link,
+ log_link_error(link,
"Could not allocate route: %s",
strerror(-r));
return r;
@@ -107,7 +107,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_configure(route_gw, link, &dhcp4_route_handler);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not set host route: %s",
strerror(-r));
return r;
@@ -122,7 +122,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not set routes: %s",
strerror(-r));
link_enter_failed(link);
@@ -136,7 +136,7 @@ static int link_set_dhcp_routes(Link *link) {
if (n == -ENOENT)
return 0;
if (n < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: could not get routes: %s",
strerror(-n));
@@ -148,7 +148,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_new_dynamic(&route, RTPROT_DHCP);
if (r < 0) {
- log_error_link(link, "Could not allocate route: %s",
+ log_link_error(link, "Could not allocate route: %s",
strerror(-r));
return r;
}
@@ -161,7 +161,7 @@ static int link_set_dhcp_routes(Link *link) {
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not set host route: %s",
strerror(-r));
return r;
@@ -184,7 +184,7 @@ static int dhcp_lease_lost(Link *link) {
assert(link);
assert(link->dhcp_lease);
- log_warning_link(link, "DHCP lease lost");
+ log_link_warning(link, "DHCP lease lost");
if (link->network->dhcp_routes) {
struct sd_dhcp_route *routes;
@@ -258,7 +258,7 @@ static int dhcp_lease_lost(Link *link) {
if (r >= 0 && link->original_mtu != mtu) {
r = link_set_mtu(link, link->original_mtu);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: could not reset MTU");
link_enter_failed(link);
return r;
@@ -273,7 +273,7 @@ static int dhcp_lease_lost(Link *link) {
if (r >= 0 && hostname) {
r = link_set_hostname(link, "");
if (r < 0)
- log_error_link(link,
+ log_link_error(link,
"Failed to reset transient hostname");
}
}
@@ -293,14 +293,11 @@ static int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_error_link(link, "could not set DHCPv4 address: %s",
+ log_link_error(link, "could not set DHCPv4 address: %s",
strerror(-r));
link_enter_failed(link);
- } else if (r >= 0) {
- /* calling handler directly so take a ref */
- link_ref(link);
- link_get_address_handler(rtnl, m, link);
- }
+ } else if (r >= 0)
+ link_rtnl_process_address(rtnl, m, link->manager);
link_set_dhcp_routes(link);
@@ -354,7 +351,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_client_get_lease(client, &lease);
if (r < 0) {
- log_warning_link(link, "DHCP error: no lease %s",
+ log_link_warning(link, "DHCP error: no lease %s",
strerror(-r));
return r;
}
@@ -365,14 +362,14 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_address(lease, &address);
if (r < 0) {
- log_warning_link(link, "DHCP error: no address: %s",
+ log_link_warning(link, "DHCP error: no address: %s",
strerror(-r));
return r;
}
r = sd_dhcp_lease_get_netmask(lease, &netmask);
if (r < 0) {
- log_warning_link(link, "DHCP error: no netmask: %s",
+ log_link_warning(link, "DHCP error: no netmask: %s",
strerror(-r));
return r;
}
@@ -381,7 +378,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
&lifetime);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: no lifetime: %s",
strerror(-r));
return r;
@@ -390,7 +387,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
r = dhcp4_update_address(link, &address, &netmask, lifetime);
if (r < 0) {
- log_warning_link(link, "could not update IP address: %s",
+ log_link_warning(link, "could not update IP address: %s",
strerror(-r));
link_enter_failed(link);
return r;
@@ -413,21 +410,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_client_get_lease(client, &lease);
if (r < 0) {
- log_warning_link(link, "DHCP error: no lease: %s",
+ log_link_warning(link, "DHCP error: no lease: %s",
strerror(-r));
return r;
}
r = sd_dhcp_lease_get_address(lease, &address);
if (r < 0) {
- log_warning_link(link, "DHCP error: no address: %s",
+ log_link_warning(link, "DHCP error: no address: %s",
strerror(-r));
return r;
}
r = sd_dhcp_lease_get_netmask(lease, &netmask);
if (r < 0) {
- log_warning_link(link, "DHCP error: no netmask: %s",
+ log_link_warning(link, "DHCP error: no netmask: %s",
strerror(-r));
return r;
}
@@ -436,13 +433,13 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_router(lease, &gateway);
if (r < 0 && r != -ENOENT) {
- log_warning_link(link, "DHCP error: could not get gateway: %s",
+ log_link_warning(link, "DHCP error: could not get gateway: %s",
strerror(-r));
return r;
}
if (r >= 0)
- log_struct_link(LOG_INFO, link,
+ log_link_struct(link, LOG_INFO,
"MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
IFNAMSIZ,
link->ifname,
@@ -457,7 +454,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
ADDRESS_FMT_VAL(gateway),
NULL);
else
- log_struct_link(LOG_INFO, link,
+ log_link_struct(link, LOG_INFO,
"MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
IFNAMSIZ,
link->ifname,
@@ -478,7 +475,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (r >= 0) {
r = link_set_mtu(link, mtu);
if (r < 0)
- log_error_link(link, "Failed to set MTU "
+ log_link_error(link, "Failed to set MTU "
"to %" PRIu16, mtu);
}
}
@@ -490,7 +487,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
if (r >= 0) {
r = link_set_hostname(link, hostname);
if (r < 0)
- log_error_link(link,
+ log_link_error(link,
"Failed to set transient hostname to '%s'",
hostname);
}
@@ -500,7 +497,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
&lifetime);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: no lifetime: %s",
strerror(-r));
return r;
@@ -509,7 +506,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = dhcp4_update_address(link, &address, &netmask, lifetime);
if (r < 0) {
- log_warning_link(link, "could not update IP address: %s",
+ log_link_warning(link, "could not update IP address: %s",
strerror(-r));
link_enter_failed(link);
return r;
@@ -533,7 +530,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
case DHCP_EVENT_STOP:
case DHCP_EVENT_IP_CHANGE:
if (link->network->dhcp_critical) {
- log_error_link(link,
+ log_link_error(link,
"DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
return;
}
@@ -571,11 +568,11 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
break;
default:
if (event < 0)
- log_warning_link(link,
+ log_link_warning(link,
"DHCP error: client failed: %s",
strerror(-event));
else
- log_warning_link(link,
+ log_link_warning(link,
"DHCP unknown event: %d",
event);
break;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
new file mode 100644
index 0000000000..c31bd4ec30
--- /dev/null
+++ b/src/network/networkd-dhcp6.c
@@ -0,0 +1,210 @@
+/*-*- 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 <linux/if.h>
+
+#include "networkd-link.h"
+#include "network-internal.h"
+
+#include "sd-icmp6-nd.h"
+#include "sd-dhcp6-client.h"
+
+static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
+ Link *link = userdata;
+
+ assert(link);
+ assert(link->network);
+ assert(link->manager);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ switch(event) {
+ case DHCP6_EVENT_STOP:
+ case DHCP6_EVENT_RESEND_EXPIRE:
+ case DHCP6_EVENT_RETRANS_MAX:
+ case DHCP6_EVENT_IP_ACQUIRE:
+ case DHCP6_EVENT_INFORMATION_REQUEST:
+ log_link_debug(link, "DHCPv6 event %d", event);
+
+ break;
+
+ default:
+ if (event < 0)
+ log_link_warning(link, "DHCPv6 error: %s",
+ strerror(-event));
+ else
+ log_link_warning(link, "DHCPv6 unknown event: %d",
+ event);
+ return;
+ }
+}
+
+static int dhcp6_configure(Link *link, int event) {
+ int r;
+ bool information_request;
+
+ assert_return(link, -EINVAL);
+
+ if (link->dhcp6_client) {
+ if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED)
+ return 0;
+
+ r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
+ &information_request);
+ if (r < 0) {
+ log_link_warning(link, "Could not get DHCPv6 Information request setting");
+ link->dhcp6_client =
+ sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ if (!information_request)
+ return r;
+
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
+ false);
+ if (r < 0) {
+ log_link_warning(link, "Could not unset DHCPv6 Information request");
+ link->dhcp6_client =
+ sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ r = sd_dhcp6_client_start(link->dhcp6_client);
+ if (r < 0) {
+ log_link_warning(link, "Could not restart DHCPv6 after enabling Information request");
+ link->dhcp6_client =
+ sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ return r;
+ }
+
+ r = sd_dhcp6_client_new(&link->dhcp6_client);
+ if (r < 0)
+ return r;
+
+ r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
+ if (r < 0) {
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ r = sd_dhcp6_client_set_mac(link->dhcp6_client,
+ (const uint8_t *) &link->mac,
+ sizeof (link->mac), ARPHRD_ETHER);
+ if (r < 0) {
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
+ if (r < 0) {
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
+ link);
+ if (r < 0) {
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+
+ if (event == ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER) {
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
+ true);
+ if (r < 0) {
+ link->dhcp6_client =
+ sd_dhcp6_client_unref(link->dhcp6_client);
+ return r;
+ }
+ }
+
+ r = sd_dhcp6_client_start(link->dhcp6_client);
+ if (r < 0)
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+
+ return r;
+}
+
+static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
+ Link *link = userdata;
+
+ assert(link);
+ assert(link->network);
+ assert(link->manager);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
+ switch(event) {
+ case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
+ return;
+
+ case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
+ case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
+ case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
+ break;
+
+ default:
+ if (event < 0)
+ log_link_warning(link, "ICMPv6 error: %s",
+ strerror(-event));
+ else
+ log_link_warning(link, "ICMPv6 unknown event: %d",
+ event);
+
+ return;
+ }
+
+ dhcp6_configure(link, event);
+}
+
+int icmp6_configure(Link *link) {
+ int r;
+
+ assert_return(link, -EINVAL);
+
+ r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
+ if (r < 0)
+ return r;
+
+ r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac);
+ if (r < 0)
+ return r;
+
+ r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
+ icmp6_router_handler, link);
+
+ return r;
+}
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 5467bc372e..339bf4d190 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -40,12 +40,11 @@ static int ipv4ll_address_lost(Link *link) {
if (r < 0)
return 0;
- log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
- ADDRESS_FMT_VAL(addr));
+ log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
r = address_new_dynamic(&address);
if (r < 0) {
- log_error_link(link, "Could not allocate address: %s", strerror(-r));
+ log_link_error(link, "Could not allocate address: %s", strerror(-r));
return r;
}
@@ -58,7 +57,7 @@ static int ipv4ll_address_lost(Link *link) {
r = route_new_dynamic(&route, RTPROT_UNSPEC);
if (r < 0) {
- log_error_link(link, "Could not allocate route: %s",
+ log_link_error(link, "Could not allocate route: %s",
strerror(-r));
return r;
}
@@ -83,7 +82,7 @@ static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdat
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_error_link(link, "could not set ipv4ll route: %s", strerror(-r));
+ log_link_error(link, "could not set ipv4ll route: %s", strerror(-r));
link_enter_failed(link);
}
@@ -104,13 +103,10 @@ static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userd
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_error_link(link, "could not set ipv4ll address: %s", strerror(-r));
+ log_link_error(link, "could not set ipv4ll address: %s", strerror(-r));
link_enter_failed(link);
- } else if (r >= 0) {
- /* calling handler directly so take a ref */
- link_ref(link);
- link_get_address_handler(rtnl, m, link);
- }
+ } else if (r >= 0)
+ link_rtnl_process_address(rtnl, m, link->manager);
link->ipv4ll_address = true;
@@ -135,7 +131,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
else if (r < 0)
return r;
- log_debug_link(link, "IPv4 link-local claim %u.%u.%u.%u",
+ log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
ADDRESS_FMT_VAL(address));
r = address_new_dynamic(&ll_addr);
@@ -200,9 +196,9 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
break;
default:
if (event < 0)
- log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
+ log_link_warning(link, "IPv4 link-local error: %s", strerror(-event));
else
- log_warning_link(link, "IPv4 link-local unknown event: %d", event);
+ log_link_warning(link, "IPv4 link-local unknown event: %d", event);
break;
}
}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 26ef0feaae..08f724e127 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -89,7 +89,7 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
r = sd_rtnl_message_link_get_flags(m, &flags);
if (r < 0) {
- log_warning_link(link, "Could not get link flags");
+ log_link_warning(link, "Could not get link flags");
return r;
}
@@ -103,7 +103,7 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
return 0;
if (link->flags != flags) {
- log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ log_link_debug(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
@@ -136,12 +136,12 @@ static int link_update_flags(Link *link, sd_rtnl_message *m) {
/* link flags are currently at most 18 bits, let's align to
* printing 20 */
if (unknown_flags_added)
- log_debug_link(link,
+ log_link_debug(link,
"unknown link flags gained: %#.5x (ignoring)",
unknown_flags_added);
if (unknown_flags_removed)
- log_debug_link(link,
+ log_link_debug(link,
"unknown link flags lost: %#.5x (ignoring)",
unknown_flags_removed);
}
@@ -194,7 +194,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
if (r < 0)
- log_debug_link(link, "MAC address not found for new device, continuing without");
+ log_link_debug(link, "MAC address not found for new device, continuing without");
r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
link->ifindex);
@@ -299,7 +299,7 @@ void link_drop(Link *link) {
link->state = LINK_STATE_LINGER;
- log_debug_link(link, "link removed");
+ log_link_debug(link, "link removed");
link_unref(link);
@@ -309,7 +309,7 @@ void link_drop(Link *link) {
static void link_enter_unmanaged(Link *link) {
assert(link);
- log_debug_link(link, "unmanaged");
+ log_link_debug(link, "unmanaged");
link->state = LINK_STATE_UNMANAGED;
@@ -329,7 +329,7 @@ static int link_stop_clients(Link *link) {
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0) {
- log_warning_link(link, "Could not stop DHCPv4 client: %s",
+ log_link_warning(link, "Could not stop DHCPv4 client: %s",
strerror(-r));
r = k;
}
@@ -338,7 +338,7 @@ static int link_stop_clients(Link *link) {
if (link->ipv4ll) {
k = sd_ipv4ll_stop(link->ipv4ll);
if (k < 0) {
- log_warning_link(link, "Could not stop IPv4 link-local: %s",
+ log_link_warning(link, "Could not stop IPv4 link-local: %s",
strerror(-r));
r = k;
}
@@ -349,7 +349,7 @@ static int link_stop_clients(Link *link) {
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
if (k < 0) {
- log_warning_link(link, "Could not stop DHCPv6 client: %s",
+ log_link_warning(link, "Could not stop DHCPv6 client: %s",
strerror(-r));
r = k;
}
@@ -357,7 +357,7 @@ static int link_stop_clients(Link *link) {
k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
if (k < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"Could not stop ICMPv6 router discovery: %s",
strerror(-r));
r = k;
@@ -373,7 +373,7 @@ void link_enter_failed(Link *link) {
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return;
- log_warning_link(link, "failed");
+ log_link_warning(link, "failed");
link->state = LINK_STATE_FAILED;
@@ -425,13 +425,13 @@ static int link_enter_configured(Link *link) {
address = link_find_dhcp_server_address(link);
if (!address) {
- log_warning_link(link,
+ log_link_warning(link,
"Failed to find suitable address for DHCPv4 server instance.");
link_enter_failed(link);
return 0;
}
- log_debug_link(link, "offering DHCPv4 leases");
+ log_link_debug(link, "offering DHCPv4 leases");
r = sd_dhcp_server_set_address(link->dhcp_server,
&address->in_addr.in,
@@ -460,7 +460,7 @@ static int link_enter_configured(Link *link) {
r = sd_dhcp_server_start(link->dhcp_server);
if (r < 0) {
- log_warning_link(link, "could not start DHCPv4 server "
+ log_link_warning(link, "could not start DHCPv4 server "
"instance: %s", strerror(-r));
link_enter_failed(link);
@@ -469,7 +469,7 @@ static int link_enter_configured(Link *link) {
}
}
- log_info_link(link, "link configured");
+ log_link_info(link, "link configured");
link->state = LINK_STATE_CONFIGURED;
@@ -515,15 +515,10 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not set route: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_link_warning_errno(link, -r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
if (link->link_messages == 0) {
- log_debug_link(link, "routes set");
+ log_link_debug(link, "routes set");
link->static_configured = true;
link_client_handler(link);
}
@@ -544,7 +539,7 @@ static int link_enter_set_routes(Link *link) {
LIST_FOREACH(routes, rt, link->network->static_routes) {
r = route_configure(rt, link, &route_handler);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not set routes: %s",
strerror(-r));
link_enter_failed(link);
@@ -558,7 +553,7 @@ static int link_enter_set_routes(Link *link) {
link->static_configured = true;
link_client_handler(link);
} else
- log_debug_link(link, "setting routes");
+ log_link_debug(link, "setting routes");
return 0;
}
@@ -576,38 +571,7 @@ int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -ESRCH)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not drop route: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
-
- return 1;
-}
-
-int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
- _cleanup_link_unref_ Link *link = userdata;
- int r;
-
- assert(rtnl);
- assert(m);
- assert(link);
- assert(link->manager);
-
- for (; m; m = sd_rtnl_message_next(m)) {
- r = sd_rtnl_message_get_errno(m);
- if (r < 0) {
- log_debug_link(link, "getting address failed: %s",
- strerror(-r));
- continue;
- }
-
- r = link_rtnl_process_address(rtnl, m, link->manager);
- if (r < 0)
- log_warning_link(link, "could not process address: %s",
- strerror(-r));
- }
+ log_link_warning_errno(link, -r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -631,20 +595,12 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not set address: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
- else if (r >= 0) {
- /* calling handler directly so take a ref */
- link_ref(link);
- link_get_address_handler(rtnl, m, link);
- }
+ log_link_warning_errno(link, -r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+ else if (r >= 0)
+ link_rtnl_process_address(rtnl, m, link->manager);
if (link->link_messages == 0) {
- log_debug_link(link, "addresses set");
+ log_link_debug(link, "addresses set");
link_enter_set_routes(link);
}
@@ -664,7 +620,7 @@ static int link_enter_set_addresses(Link *link) {
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
r = address_configure(ad, link, &address_handler);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not set addresses: %s",
strerror(-r));
link_enter_failed(link);
@@ -677,7 +633,7 @@ static int link_enter_set_addresses(Link *link) {
if (link->link_messages == 0) {
link_enter_set_routes(link);
} else
- log_debug_link(link, "setting addresses");
+ log_link_debug(link, "setting addresses");
return 0;
}
@@ -695,14 +651,30 @@ int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata)
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not drop address: %s",
+ log_link_warning_errno(link, -r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+
+ return 1;
+}
+
+static int link_set_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+ _cleanup_link_unref_ Link *link = userdata;
+ int r;
+
+ log_link_debug(link, "set link");
+
+ r = sd_rtnl_message_get_errno(m);
+ if (r < 0 && r != -EEXIST) {
+ log_link_struct(link, LOG_ERR,
+ "MESSAGE=%-*s: could not join netdev: %s",
IFNAMSIZ,
link->ifname, strerror(-r),
"ERRNO=%d", -r,
NULL);
+ link_enter_failed(link);
+ return 1;
+ }
- return 1;
+ return 0;
}
static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
@@ -717,7 +689,7 @@ static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
r = sd_bus_message_get_errno(m);
if (r > 0)
- log_warning_link(link, "Could not set hostname: %s",
+ log_link_warning(link, "Could not set hostname: %s",
strerror(r));
return 1;
@@ -731,11 +703,11 @@ int link_set_hostname(Link *link, const char *hostname) {
assert(link->manager);
assert(hostname);
- log_debug_link(link, "Setting transient hostname: '%s'", hostname);
+ log_link_debug(link, "Setting transient hostname: '%s'", hostname);
if (!link->manager->bus) {
/* TODO: replace by assert when we can rely on kdbus */
- log_info_link(link,
+ log_link_info(link,
"Not connected to system bus, ignoring transient hostname.");
return 0;
}
@@ -757,7 +729,7 @@ int link_set_hostname(Link *link, const char *hostname) {
r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler,
link, 0);
if (r < 0) {
- log_error_link(link, "Could not set transient hostname: %s",
+ log_link_error(link, "Could not set transient hostname: %s",
strerror(-r));
return r;
}
@@ -780,11 +752,7 @@ static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
r = sd_rtnl_message_get_errno(m);
if (r < 0)
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not set MTU: %s",
- IFNAMSIZ, link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_link_warning_errno(link, -r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
return 1;
}
@@ -797,25 +765,25 @@ int link_set_mtu(Link *link, uint32_t mtu) {
assert(link->manager);
assert(link->manager->rtnl);
- log_debug_link(link, "setting MTU: %" PRIu32, mtu);
+ log_link_debug(link, "setting MTU: %" PRIu32, mtu);
r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
RTM_SETLINK, link->ifindex);
if (r < 0) {
- log_error_link(link, "Could not allocate RTM_SETLINK message");
+ log_link_error(link, "Could not allocate RTM_SETLINK message");
return r;
}
r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
if (r < 0) {
- log_error_link(link, "Could not append MTU: %s", strerror(-r));
+ log_link_error(link, "Could not append MTU: %s", strerror(-r));
return r;
}
r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link,
0, NULL);
if (r < 0) {
- log_error_link(link,
+ log_link_error(link,
"Could not send rtnetlink message: %s",
strerror(-r));
return r;
@@ -826,104 +794,67 @@ int link_set_mtu(Link *link, uint32_t mtu) {
return 0;
}
-static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
- Link *link = userdata;
-
- assert(link);
- assert(link->network);
- assert(link->manager);
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return;
-
- switch(event) {
- case DHCP6_EVENT_STOP:
- case DHCP6_EVENT_RESEND_EXPIRE:
- case DHCP6_EVENT_RETRANS_MAX:
- case DHCP6_EVENT_IP_ACQUIRE:
- log_debug_link(link, "DHCPv6 event %d", event);
-
- break;
-
- default:
- if (event < 0)
- log_warning_link(link, "DHCPv6 error: %s",
- strerror(-event));
- else
- log_warning_link(link, "DHCPv6 unknown event: %d",
- event);
- return;
- }
-}
-
-static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
- Link *link = userdata;
+static int link_set_bridge(Link *link) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = 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 ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
- return;
-
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
- break;
- default:
- if (event < 0)
- log_warning_link(link, "ICMPv6 error: %s",
- strerror(-event));
- else
- log_warning_link(link, "ICMPv6 unknown event: %d",
- event);
+ if(link->network->cost == 0)
+ return 0;
- return;
+ r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
+ RTM_SETLINK, link->ifindex);
+ if (r < 0) {
+ log_link_error(link, "Could not allocate RTM_SETLINK message");
+ return r;
}
- if (link->dhcp6_client)
- return;
-
- r = sd_dhcp6_client_new(&link->dhcp6_client);
- if (r < 0)
- return;
-
- r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
+ r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return;
+ log_link_error(link,
+ "Could not set message family %s", strerror(-r));
+ return r;
}
- r = sd_dhcp6_client_set_mac(link->dhcp6_client,
- (const uint8_t *) &link->mac,
- sizeof (link->mac), ARPHRD_ETHER);
+ r = sd_rtnl_message_open_container(req, IFLA_PROTINFO);
if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return;
+ log_link_error(link,
+ "Could not append IFLA_PROTINFO attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ if(link->network->cost != 0) {
+ r = sd_rtnl_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
+ if (r < 0) {
+ log_link_error(link,
+ "Could not append IFLA_BRPORT_COST attribute: %s",
+ strerror(-r));
+ return r;
+ }
}
- r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
+ r = sd_rtnl_message_close_container(req);
if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return;
+ log_link_error(link,
+ "Could not append IFLA_LINKINFO attribute: %s",
+ strerror(-r));
+ return r;
}
- r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
- link);
+ r = sd_rtnl_call_async(link->manager->rtnl, req, link_set_handler, link, 0, NULL);
if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return;
+ log_link_error(link,
+ "Could not send rtnetlink message: %s",
+ strerror(-r));
+ return r;
}
- r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0)
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ link_ref(link);
+
+ return r;
}
static int link_acquire_conf(Link *link) {
@@ -937,11 +868,11 @@ static int link_acquire_conf(Link *link) {
if (link_ipv4ll_enabled(link)) {
assert(link->ipv4ll);
- log_debug_link(link, "acquiring IPv4 link-local address");
+ log_link_debug(link, "acquiring IPv4 link-local address");
r = sd_ipv4ll_start(link->ipv4ll);
if (r < 0) {
- log_warning_link(link, "could not acquire IPv4 "
+ log_link_warning(link, "could not acquire IPv4 "
"link-local address");
return r;
}
@@ -950,11 +881,11 @@ static int link_acquire_conf(Link *link) {
if (link_dhcp4_enabled(link)) {
assert(link->dhcp_client);
- log_debug_link(link, "acquiring DHCPv4 lease");
+ log_link_debug(link, "acquiring DHCPv4 lease");
r = sd_dhcp_client_start(link->dhcp_client);
if (r < 0) {
- log_warning_link(link, "could not acquire DHCPv4 "
+ log_link_warning(link, "could not acquire DHCPv4 "
"lease");
return r;
}
@@ -963,11 +894,11 @@ static int link_acquire_conf(Link *link) {
if (link_dhcp6_enabled(link)) {
assert(link->icmp6_router_discovery);
- log_debug_link(link, "discovering IPv6 routers");
+ log_link_debug(link, "discovering IPv6 routers");
r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"could not start IPv6 router discovery");
return r;
}
@@ -1003,12 +934,7 @@ static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
if (r < 0) {
/* we warn but don't fail the link, as it may
be brought up later */
- log_struct_link(LOG_WARNING, link,
- "MESSAGE=%-*s: could not bring up interface: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_link_warning_errno(link, -r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
}
return 1;
@@ -1019,29 +945,46 @@ static int link_up(Link *link) {
int r;
assert(link);
+ assert(link->network);
assert(link->manager);
assert(link->manager->rtnl);
- log_debug_link(link, "bringing link up");
+ log_link_debug(link, "bringing link up");
r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
RTM_SETLINK, link->ifindex);
if (r < 0) {
- log_error_link(link, "Could not allocate RTM_SETLINK message");
+ log_link_error(link, "Could not allocate RTM_SETLINK message");
return r;
}
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
if (r < 0) {
- log_error_link(link, "Could not set link flags: %s",
+ log_link_error(link, "Could not set link flags: %s",
strerror(-r));
return r;
}
+ if (link->network->mac) {
+ r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, link->network->mac);
+ if (r < 0) {
+ log_link_error(link, "Could not set MAC address: %s", strerror(-r));
+ return r;
+ }
+ }
+
+ if (link->network->mtu) {
+ r = sd_rtnl_message_append_u32(req, IFLA_MTU, link->network->mtu);
+ if (r < 0) {
+ log_link_error(link, "Could not set MTU: %s", strerror(-r));
+ return r;
+ }
+ }
+
r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link,
0, NULL);
if (r < 0) {
- log_error_link(link,
+ log_link_error(link,
"Could not send rtnetlink message: %s",
strerror(-r));
return r;
@@ -1066,6 +1009,15 @@ static int link_joined(Link *link) {
}
}
+ if(link->network->bridge) {
+ r = link_set_bridge(link);
+ if (r < 0) {
+ log_link_error(link,
+ "Could not set bridge message: %s",
+ strerror(-r));
+ }
+ }
+
return link_enter_set_addresses(link);
}
@@ -1084,16 +1036,11 @@ static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_struct_link(LOG_ERR, link,
- "MESSAGE=%-*s: could not join netdev: %s",
- IFNAMSIZ,
- link->ifname, strerror(-r),
- "ERRNO=%d", -r,
- NULL);
+ log_link_error_errno(link, -r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
link_enter_failed(link);
return 1;
} else
- log_debug_link(link, "joined netdev");
+ log_link_debug(link, "joined netdev");
if (link->enslaving <= 0)
link_joined(link);
@@ -1120,7 +1067,7 @@ static int link_enter_join_netdev(Link *link) {
return link_joined(link);
if (link->network->bond) {
- log_struct_link(LOG_DEBUG, link,
+ log_link_struct(link, LOG_DEBUG,
"MESSAGE=%-*s: enslaving by '%s'",
IFNAMSIZ,
link->ifname, link->network->bond->ifname,
@@ -1129,7 +1076,7 @@ static int link_enter_join_netdev(Link *link) {
r = netdev_join(link->network->bond, link, &netdev_join_handler);
if (r < 0) {
- log_struct_link(LOG_WARNING, link,
+ log_link_struct(link, LOG_WARNING,
"MESSAGE=%-*s: could not join netdev '%s': %s",
IFNAMSIZ,
link->ifname, link->network->bond->ifname,
@@ -1144,7 +1091,7 @@ static int link_enter_join_netdev(Link *link) {
}
if (link->network->bridge) {
- log_struct_link(LOG_DEBUG, link,
+ log_link_struct(link, LOG_DEBUG,
"MESSAGE=%-*s: enslaving by '%s'",
IFNAMSIZ,
link->ifname, link->network->bridge->ifname,
@@ -1154,7 +1101,7 @@ static int link_enter_join_netdev(Link *link) {
r = netdev_join(link->network->bridge, link,
&netdev_join_handler);
if (r < 0) {
- log_struct_link(LOG_WARNING, link,
+ log_link_struct(link, LOG_WARNING,
"MESSAGE=%-*s: could not join netdev '%s': %s",
IFNAMSIZ,
link->ifname, link->network->bridge->ifname,
@@ -1169,7 +1116,7 @@ static int link_enter_join_netdev(Link *link) {
}
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
- log_struct_link(LOG_DEBUG, link,
+ log_link_struct(link, LOG_DEBUG,
"MESSAGE=%-*s: enslaving by '%s'",
IFNAMSIZ,
link->ifname, netdev->ifname, NETDEVIF(netdev),
@@ -1177,7 +1124,7 @@ static int link_enter_join_netdev(Link *link) {
r = netdev_join(netdev, link, &netdev_join_handler);
if (r < 0) {
- log_struct_link(LOG_WARNING, link,
+ log_link_struct(link, LOG_WARNING,
"MESSAGE=%-*s: could not join netdev '%s': %s",
IFNAMSIZ,
link->ifname, netdev->ifname,
@@ -1223,27 +1170,7 @@ static int link_configure(Link *link) {
}
if (link_dhcp6_enabled(link)) {
- r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
- if (r < 0)
- return r;
-
- r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery,
- NULL, 0);
- if (r < 0)
- return r;
-
- r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
- &link->mac);
- if (r < 0)
- return r;
-
- r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
- link->ifindex);
- if (r < 0)
- return r;
-
- r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
- icmp6_router_handler, link);
+ r = icmp6_configure(link);
if (r < 0)
return r;
}
@@ -1270,7 +1197,7 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
if (link->state != LINK_STATE_PENDING)
return 1;
- log_debug_link(link, "link state is up-to-date");
+ log_link_debug(link, "link state is up-to-date");
r = network_get(link->manager, link->udev_device, link->ifname,
&link->mac, &network);
@@ -1282,13 +1209,13 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
if (link->flags & IFF_LOOPBACK) {
if (network->ipv4ll)
- log_debug_link(link, "ignoring IPv4LL for loopback link");
+ log_link_debug(link, "ignoring IPv4LL for loopback link");
if (network->dhcp != DHCP_SUPPORT_NONE)
- log_debug_link(link, "ignoring DHCP clients for loopback link");
+ log_link_debug(link, "ignoring DHCP clients for loopback link");
if (network->dhcp_server)
- log_debug_link(link, "ignoring DHCP server for loopback link");
+ log_link_debug(link, "ignoring DHCP server for loopback link");
}
r = network_apply(link->manager, network, link);
@@ -1317,7 +1244,7 @@ int link_initialized(Link *link, struct udev_device *device) {
if (link->udev_device)
return 0;
- log_debug_link(link, "udev initialized link");
+ log_link_debug(link, "udev initialized link");
link->udev_device = udev_device_ref(device);
@@ -1341,8 +1268,7 @@ int link_initialized(Link *link, struct udev_device *device) {
return 0;
}
-int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
- void *userdata) {
+int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
uint16_t type;
@@ -1358,6 +1284,14 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
assert(message);
assert(m);
+ if (sd_rtnl_message_is_error(message)) {
+ r = sd_rtnl_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive address: %m");
+
+ return 0;
+ }
+
r = sd_rtnl_message_get_type(message, &type);
if (r < 0) {
log_warning("rtnl: could not get message type");
@@ -1365,13 +1299,16 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
}
r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
- if (r < 0 || ifindex <= 0) {
- log_warning("rtnl: received address message without valid ifindex, ignoring");
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex: %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) {
- log_warning("rtnl: received address for a nonexistent link (%d), ignoring", ifindex);
+ log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
return 0;
}
}
@@ -1382,28 +1319,28 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
r = sd_rtnl_message_addr_get_family(message, &address->family);
if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address with invalid family, ignoring");
return 0;
}
r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address with invalid prefixlen, ignoring");
return 0;
}
r = sd_rtnl_message_addr_get_scope(message, &address->scope);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address with invalid scope, ignoring");
return 0;
}
r = sd_rtnl_message_addr_get_flags(message, &address->flags);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address with invalid flags, ignoring");
return 0;
}
@@ -1413,7 +1350,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL,
&address->in_addr.in);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address without valid address, ignoring");
return 0;
}
@@ -1424,7 +1361,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS,
&address->in_addr.in6);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"rtnl: received address without valid address, ignoring");
return 0;
}
@@ -1437,7 +1374,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
if (!inet_ntop(address->family, &address->in_addr, buf,
INET6_ADDRSTRLEN)) {
- log_warning_link(link, "could not print address");
+ log_link_warning(link, "could not print address");
return 0;
}
@@ -1467,10 +1404,10 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
switch (type) {
case RTM_NEWADDR:
if (!address_dropped)
- log_debug_link(link, "added address: %s/%u (valid for %s)",
+ log_link_debug(link, "added address: %s/%u (valid for %s)",
buf, address->prefixlen, valid_str);
else
- log_debug_link(link, "updated address: %s/%u (valid for %s)",
+ log_link_debug(link, "updated address: %s/%u (valid for %s)",
buf, address->prefixlen, valid_str);
LIST_PREPEND(addresses, link->addresses, address);
@@ -1481,12 +1418,12 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
break;
case RTM_DELADDR:
if (address_dropped) {
- log_debug_link(link, "removed address: %s/%u (valid for %s)",
+ log_link_debug(link, "removed address: %s/%u (valid for %s)",
buf, address->prefixlen, valid_str);
link_save(link);
} else
- log_warning_link(link,
+ log_link_warning(link,
"removing non-existent address: %s/%u (valid for %s)",
buf, address->prefixlen, valid_str);
@@ -1500,7 +1437,6 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
Link *link;
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
char ifindex_str[2 + DECIMAL_STR_MAX(int)];
int r;
@@ -1516,33 +1452,21 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
link = *ret;
- log_debug_link(link, "link %d added", link->ifindex);
-
- r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex,
- 0);
- if (r < 0)
- return r;
-
- r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0,
- NULL);
- if (r < 0)
- return r;
-
- link_ref(link);
+ log_link_debug(link, "link %d added", link->ifindex);
if (detect_container(NULL) <= 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) {
- log_warning_link(link,
+ log_link_warning(link,
"could not find udev device: %m");
return -errno;
}
if (udev_device_get_is_initialized(device) <= 0) {
/* not yet ready */
- log_debug_link(link, "link pending udev initialization...");
+ log_link_debug(link, "link pending udev initialization...");
return 0;
}
@@ -1574,13 +1498,13 @@ int link_update(Link *link, sd_rtnl_message *m) {
if (link->state == LINK_STATE_LINGER) {
link_ref(link);
- log_info_link(link, "link readded");
+ log_link_info(link, "link readded");
link->state = LINK_STATE_ENSLAVING;
}
r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
if (r >= 0 && !streq(ifname, link->ifname)) {
- log_info_link(link, "renamed to %s", ifname);
+ log_link_info(link, "renamed to %s", ifname);
free(link->ifname);
link->ifname = strdup(ifname);
@@ -1593,7 +1517,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
link->mtu = mtu;
if (!link->original_mtu) {
link->original_mtu = mtu;
- log_debug_link(link, "saved original MTU: %"
+ log_link_debug(link, "saved original MTU: %"
PRIu32, link->original_mtu);
}
@@ -1601,7 +1525,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
r = sd_dhcp_client_set_mtu(link->dhcp_client,
link->mtu);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"Could not update MTU in DHCP client: %s",
strerror(-r));
return r;
@@ -1619,7 +1543,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet,
ETH_ALEN);
- log_debug_link(link, "MAC address: "
+ log_link_debug(link, "MAC address: "
"%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
mac.ether_addr_octet[0],
mac.ether_addr_octet[1],
@@ -1631,7 +1555,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
if (link->ipv4ll) {
r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"Could not update MAC address in IPv4LL client: %s",
strerror(-r));
return r;
@@ -1644,7 +1568,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
sizeof (link->mac),
ARPHRD_ETHER);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"Could not update MAC address in DHCP client: %s",
strerror(-r));
return r;
@@ -1657,7 +1581,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
sizeof (link->mac),
ARPHRD_ETHER);
if (r < 0) {
- log_warning_link(link,
+ log_link_warning(link,
"Could not update MAC address in DHCPv6 client: %s",
strerror(-r));
return r;
@@ -1676,7 +1600,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
carrier_lost = had_carrier && !link_has_carrier(link);
if (carrier_gained) {
- log_info_link(link, "gained carrier");
+ log_link_info(link, "gained carrier");
if (link->network) {
r = link_acquire_conf(link);
@@ -1686,7 +1610,7 @@ int link_update(Link *link, sd_rtnl_message *m) {
}
}
} else if (carrier_lost) {
- log_info_link(link, "lost carrier");
+ log_link_info(link, "lost carrier");
r = link_stop_clients(link);
if (r < 0) {
@@ -1857,7 +1781,7 @@ int link_save(Link *link) {
if (link->dhcp_lease) {
assert(link->network);
- r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
+ r = sd_dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
goto fail;
@@ -1878,7 +1802,7 @@ int link_save(Link *link) {
return 0;
fail:
- log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
+ log_link_error(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
unlink(link->state_file);
unlink(temp_path);
return r;
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 7acf404f87..05c34eef19 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -99,7 +99,6 @@ int link_get(Manager *m, int ifindex, Link **ret);
int link_add(Manager *manager, sd_rtnl_message *message, Link **ret);
void link_drop(Link *link);
-int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata);
@@ -120,6 +119,7 @@ int link_set_hostname(Link *link, const char *hostname);
int ipv4ll_configure(Link *link);
int dhcp4_configure(Link *link);
+int icmp6_configure(Link *link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
@@ -132,14 +132,22 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
/* Macros which append INTERFACE= to the message */
-#define log_full_link(level, link, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", link->ifname, "%-*s: " fmt, IFNAMSIZ, link->ifname, ##__VA_ARGS__)
-#define log_debug_link(link, ...) log_full_link(LOG_DEBUG, link, ##__VA_ARGS__)
-#define log_info_link(link, ...) log_full_link(LOG_INFO, link, ##__VA_ARGS__)
-#define log_notice_link(link, ...) log_full_link(LOG_NOTICE, link, ##__VA_ARGS__)
-#define log_warning_link(link, ...) log_full_link(LOG_WARNING, link, ##__VA_ARGS__)
-#define log_error_link(link, ...) log_full_link(LOG_ERR, link, ##__VA_ARGS__)
+#define log_link_full(link, level, error, fmt, ...) \
+ log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", link->ifname, "%-*s: " fmt, IFNAMSIZ, link->ifname, ##__VA_ARGS__)
-#define log_struct_link(level, link, ...) log_struct(level, "INTERFACE=%s", link->ifname, __VA_ARGS__)
+#define log_link_debug(link, ...) log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_link_info(link, ...) log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_link_notice(link, ...) log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_link_error(link, ...) log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_link_debug_errno(link, error, ...) log_link_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_link_info_errno(link, error, ...) log_link_full(link, LOG_INFO, error, ##__VA_ARGS__)
+#define log_link_notice_errno(link, error, ...) log_link_full(link, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_link_warning_errno(link, error, ...) log_link_full(link, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_link_error_errno(link, error, ...) log_link_full(link, LOG_ERR, error, ##__VA_ARGS__)
+
+#define log_link_struct(link, level, ...) log_struct(level, "INTERFACE=%s", link->ifname, __VA_ARGS__)
#define ADDRESS_FMT_VAL(address) \
(address).s_addr & 0xFF, \
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 2213ad717c..fe9008a3df 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -36,6 +36,9 @@
#include "sd-rtnl.h"
+/* use 8 MB for receive socket kernel queue. */
+#define RCVBUF_SIZE (8*1024*1024)
+
const char* const network_dirs[] = {
"/etc/systemd/network",
"/run/systemd/network",
@@ -98,6 +101,10 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
+ r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
+ if (r < 0)
+ return r;
+
r = sd_bus_default_system(&m->bus);
if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
return r;
@@ -229,22 +236,33 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
assert(message);
assert(m);
+ if (sd_rtnl_message_is_error(message)) {
+ r = sd_rtnl_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: could not receive link: %m");
+
+ return 0;
+ }
+
r = sd_rtnl_message_get_type(message, &type);
if (r < 0) {
- log_warning("rtnl: could not get message type");
+ log_warning_errno(r, "rtnl: could not get message type: %m");
return 0;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
- if (r < 0 || ifindex <= 0) {
- log_warning("rtnl: received link message without valid ifindex");
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
return 0;
} else
link_get(m, ifindex, &link);
r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
- if (r < 0 || !name) {
- log_warning("rtnl: received link message without valid ifname");
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: received link message without ifname: %m");
return 0;
} else
netdev_get(m, name, &netdev);
@@ -255,8 +273,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
/* link is new, so add it */
r = link_add(m, message, &link);
if (r < 0) {
- log_debug("could not add new link: %s",
- strerror(-r));
+ log_debug_errno(r, "could not add new link: %m");
return 0;
}
}
@@ -265,7 +282,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
/* netdev exists, so make sure the ifindex matches */
r = netdev_set_ifindex(netdev, message);
if (r < 0) {
- log_debug("could not set ifindex on netdev");
+ log_debug_errno(r, "could not set ifindex on netdev: %m");
return 0;
}
}
@@ -292,7 +309,7 @@ static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, vo
int manager_rtnl_enumerate_links(Manager *m) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
sd_rtnl_message *link;
- int r, k;
+ int r;
assert(m);
assert(m->rtnl);
@@ -310,16 +327,40 @@ int manager_rtnl_enumerate_links(Manager *m) {
return r;
for (link = reply; link; link = sd_rtnl_message_next(link)) {
- uint16_t type;
+ int k;
- k = sd_rtnl_message_get_type(link, &type);
+ k = manager_rtnl_process_link(m->rtnl, link, m);
if (k < 0)
- return k;
+ r = k;
+ }
- if (type != RTM_NEWLINK)
- continue;
+ return r;
+}
- k = manager_rtnl_process_link(m->rtnl, link, m);
+int manager_rtnl_enumerate_addresses(Manager *m) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+ sd_rtnl_message *addr;
+ int r;
+
+ assert(m);
+ assert(m->rtnl);
+
+ r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_call(m->rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
+ int k;
+
+ k = link_rtnl_process_address(m->rtnl, addr, m);
if (k < 0)
r = k;
}
@@ -349,10 +390,8 @@ int manager_udev_listen(Manager *m) {
assert(m->udev_monitor);
r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
- if (r < 0) {
- log_error("Could not add udev monitor filter: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not add udev monitor filter: %m");
r = udev_monitor_enable_receiving(m->udev_monitor);
if (r < 0) {
@@ -368,7 +407,7 @@ int manager_udev_listen(Manager *m) {
if (r < 0)
return r;
- r = sd_event_source_set_name(m->udev_event_source, "networkd-udev");
+ r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
if (r < 0)
return r;
@@ -590,7 +629,7 @@ int manager_save(Manager *m) {
return 0;
fail:
- log_error("Failed to save network state to %s: %s", m->state_file, strerror(-r));
+ log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
unlink(m->state_file);
unlink(temp_path);
return r;
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 46408213b7..88321ef84c 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -116,7 +116,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_u8(m, IFLA_BOND_MODE,
bond_mode_to_kernel(b->mode));
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_MODE attribute: %s",
strerror(-r));
return r;
@@ -127,7 +127,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %s",
strerror(-r));
return r;
@@ -138,7 +138,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
b->mode == NETDEV_BOND_MODE_802_3AD) {
r = sd_rtnl_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_AD_LACP_RATE attribute: %s",
strerror(-r));
return r;
@@ -148,7 +148,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
if (b->miimon != 0) {
r = sd_rtnl_message_append_u32(m, IFLA_BOND_MIIMON, b->miimon / USEC_PER_MSEC);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_BOND_MIIMON attribute: %s",
strerror(-r));
return r;
@@ -158,7 +158,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
if (b->downdelay != 0) {
r = sd_rtnl_message_append_u32(m, IFLA_BOND_DOWNDELAY, b->downdelay / USEC_PER_MSEC);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_DOWNDELAY attribute: %s",
strerror(-r));
return r;
@@ -168,7 +168,7 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
if (b->updelay != 0) {
r = sd_rtnl_message_append_u32(m, IFLA_BOND_UPDELAY, b->updelay / USEC_PER_MSEC);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_BOND_UPDELAY attribute: %s",
strerror(-r));
return r;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index c524ee5798..b311ebe4fb 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -18,42 +18,47 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
-NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
-NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
-NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
-NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
-NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
-VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id)
-MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
-Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
-Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
-Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
-Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
-Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
-Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
-Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
-VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
-VXLAN.Group, config_parse_tunnel_address, 0, offsetof(VxLan, group)
-VXLAN.TOS, config_parse_unsigned, 0, offsetof(VxLan, tos)
-VXLAN.TTL, config_parse_unsigned, 0, offsetof(VxLan, ttl)
-VXLAN.MacLearning, config_parse_bool, 0, offsetof(VxLan, learning)
-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)
-Tun.User, config_parse_string, 0, offsetof(TunTap, user_name)
-Tun.Group, config_parse_string, 0, offsetof(TunTap, group_name)
-Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
-Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
-Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
-Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
-Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
-Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
-Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
-Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
-Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
-Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
-Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
+Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
+Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
+Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
+NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
+NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
+NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind)
+NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu)
+NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac)
+VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id)
+MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode)
+Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
+Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
+Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
+Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
+Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc)
+Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer)
+Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer)
+VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id)
+VXLAN.Group, config_parse_vxlan_group_address, 0, offsetof(VxLan, group)
+VXLAN.TOS, config_parse_unsigned, 0, offsetof(VxLan, tos)
+VXLAN.TTL, config_parse_unsigned, 0, offsetof(VxLan, ttl)
+VXLAN.MacLearning, config_parse_bool, 0, offsetof(VxLan, learning)
+VXLAN.ARPProxy, config_parse_bool, 0, offsetof(VxLan, arp_proxy)
+VXLAN.L2MissNotification, config_parse_bool, 0, offsetof(VxLan, l2miss)
+VXLAN.L3MissNotification, config_parse_bool, 0, offsetof(VxLan, l3miss)
+VXLAN.RouteShortCircuit, config_parse_bool, 0, offsetof(VxLan, route_short_circuit)
+VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing)
+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)
+Tun.User, config_parse_string, 0, offsetof(TunTap, user_name)
+Tun.Group, config_parse_string, 0, offsetof(TunTap, group_name)
+Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue)
+Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue)
+Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info)
+Tap.User, config_parse_string, 0, offsetof(TunTap, user_name)
+Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name)
+Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode)
+Bond.TransmitHashPolicy, config_parse_bond_xmit_hash_policy, 0, offsetof(Bond, xmit_hash_policy)
+Bond.LACPTransmitRate, config_parse_bond_lacp_rate, 0, offsetof(Bond, lacp_rate)
+Bond.MIIMonitorSec, config_parse_sec, 0, offsetof(Bond, miimon)
+Bond.UpDelaySec, config_parse_sec, 0, offsetof(Bond, updelay)
+Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c
index 2e5554a172..198fb575ee 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/networkd-netdev-macvlan.c
@@ -48,7 +48,7 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_rtn
if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) {
r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_MACVLAN_MODE attribute: %s",
strerror(-r));
return r;
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 174fe234fd..31d34644ed 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -45,7 +45,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LINK attribute: %s",
strerror(-r));
return r;
@@ -53,7 +53,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LOCAL attribute: %s",
strerror(-r));
return r;
@@ -61,7 +61,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_REMOTE attribute: %s",
strerror(-r));
return r;
@@ -69,12 +69,20 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_TTL attribute: %s",
strerror(-r));
return r;
}
+ r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
return r;
}
@@ -90,7 +98,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LINK attribute: %s",
strerror(-r));
return r;
@@ -98,7 +106,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LOCAL attribute: %s",
strerror(-r));
return r;
@@ -106,7 +114,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_REMOTE attribute: %s",
strerror(-r));
return r;
@@ -114,12 +122,20 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_TTL attribute: %s",
strerror(-r));
return r;
}
+ r = sd_rtnl_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_IPTUN_PMTUDISC attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
return r;
}
@@ -135,7 +151,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_GRE_LINK attribute: %s",
strerror(-r));
return r;
@@ -143,7 +159,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_GRE_LOCAL attribute: %s",
strerror(-r));
return r;
@@ -151,7 +167,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_GRE_REMOTE attribute: %s",
strerror(-r));
return r;
@@ -159,7 +175,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_GRE_TTL attribute: %s",
strerror(-r));
return r;
@@ -167,12 +183,20 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u8(m, IFLA_GRE_TOS, t->tos);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_GRE_TOS attribute: %s",
strerror(-r));
return r;
}
+ r = sd_rtnl_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_GRE_PMTUDISC attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
return r;
}
@@ -188,7 +212,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LINK attribute: %s",
strerror(-r));
return r;
@@ -196,7 +220,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_LOCAL attribute: %s",
strerror(-r));
return r;
@@ -204,7 +228,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_me
r = sd_rtnl_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IPTUN_REMOTE attribute: %s",
strerror(-r));
return r;
@@ -238,11 +262,6 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
assert(t);
- if (t->local.in.s_addr == INADDR_ANY) {
- log_warning("Tunnel without local address configured in %s. Ignoring", filename);
- return -EINVAL;
- }
-
if (t->remote.in.s_addr == INADDR_ANY) {
log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
return -EINVAL;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index eaf5df4971..4f449aea48 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -70,13 +70,13 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
fd = open(TUN_DEV, O_RDWR);
if (fd < 0) {
- log_error_netdev(netdev, "Failed to open tun dev: %m");
+ log_netdev_error(netdev, "Failed to open tun dev: %m");
return -errno;
}
r = ioctl(fd, TUNSETIFF, ifr);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"TUNSETIFF failed on tun dev: %s",
strerror(-r));
return r;
@@ -95,14 +95,14 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
r = get_user_creds(&user, &uid, NULL, NULL, NULL);
if (r < 0) {
- log_error("Cannot resolve user name %s: %s",
- t->user_name, strerror(-r));
+ log_error_errno(r, "Cannot resolve user name %s: %m",
+ t->user_name);
return 0;
}
r = ioctl(fd, TUNSETOWNER, uid);
if ( r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"TUNSETOWNER failed on tun dev: %s",
strerror(-r));
}
@@ -114,14 +114,14 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
r = get_group_creds(&group, &gid);
if (r < 0) {
- log_error("Cannot resolve group name %s: %s",
- t->group_name, strerror(-r));
+ log_error_errno(r, "Cannot resolve group name %s: %m",
+ t->group_name);
return 0;
}
r = ioctl(fd, TUNSETGROUP, gid);
if( r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"TUNSETGROUP failed on tun dev: %s",
strerror(-r));
return r;
@@ -131,7 +131,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
r = ioctl(fd, TUNSETPERSIST, 1);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"TUNSETPERSIST failed on tun dev: %s",
strerror(-r));
return r;
@@ -171,17 +171,8 @@ static void tuntap_done(NetDev *netdev) {
}
static int tuntap_verify(NetDev *netdev, const char *filename) {
- TunTap *t = NULL;
-
assert(netdev);
- if (netdev->kind == NETDEV_KIND_TUN)
- t = TUN(netdev);
- else
- t = TAP(netdev);
-
- assert(t);
-
if (netdev->mtu) {
log_warning_netdev(netdev, "MTU configured for %s, ignoring",
netdev_kind_to_string(netdev->kind));
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index da09ef908f..251cf92aec 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -38,24 +38,22 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_open_container(m, VETH_INFO_PEER);
if (r < 0) {
- log_error_netdev(netdev,
- "Could not append IFLA_IPTUN_LINK attribute: %s",
+ log_netdev_error(netdev,
+ "Could not append VETH_INFO_PEER attribute: %s",
strerror(-r));
return r;
}
if (v->ifname_peer) {
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, v->ifname_peer);
- if (r < 0) {
- log_error("Failed to add netlink interface name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
}
if (v->mac_peer) {
r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, v->mac_peer);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_ADDRESS attribute: %s",
strerror(-r));
return r;
@@ -64,7 +62,7 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
r = sd_rtnl_message_close_container(m);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_INFO_DATA attribute: %s",
strerror(-r));
return r;
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index 13c4456733..665559f895 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -37,7 +37,7 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_m
if (v->id <= VLANID_MAX) {
r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, v->id);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VLAN_ID attribute: %s",
strerror(-r));
return r;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 326ac547a3..d5128cb7c0 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -26,6 +26,7 @@
#include "sd-rtnl.h"
#include "networkd-netdev-vxlan.h"
#include "networkd-link.h"
+#include "conf-parser.h"
#include "missing.h"
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_message *m) {
@@ -41,7 +42,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
if (v->id <= VXLAN_VID_MAX) {
r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_ID, v->id);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_ID attribute: %s",
strerror(-r));
return r;
@@ -50,7 +51,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
r = sd_rtnl_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_GROUP attribute: %s",
strerror(-r));
return r;
@@ -58,7 +59,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_LINK attribute: %s",
strerror(-r));
return r;
@@ -67,7 +68,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
if(v->ttl) {
r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_TTL attribute: %s",
strerror(-r));
return r;
@@ -77,7 +78,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
if(v->tos) {
r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_TOS attribute: %s",
strerror(-r));
return r;
@@ -86,15 +87,95 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_rtnl_
r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_LEARNING, v->learning);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_VXLAN_LEARNING attribute: %s",
strerror(-r));
return r;
}
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_RSC, v->route_short_circuit);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_RSC attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_PROXY, v->arp_proxy);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_PROXY attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_L2MISS, v->l2miss);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_L2MISS attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ r = sd_rtnl_message_append_u8(m, IFLA_VXLAN_L3MISS, v->l3miss);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_L3MISS attribute: %s",
+ strerror(-r));
+ return r;
+ }
+
+ if(v->fdb_ageing) {
+ r = sd_rtnl_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
+ if (r < 0) {
+ log_netdev_error(netdev,
+ "Could not append IFLA_VXLAN_AGEING attribute: %s",
+ strerror(-r));
+ return r;
+ }
+ }
+
return r;
}
+int config_parse_vxlan_group_address(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) {
+ VxLan *v = userdata;
+ union in_addr_union *addr = data, buffer;
+ int r, f;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ if(v->family != AF_UNSPEC && v->family != f) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "vxlan multicast group incompatible, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ v->family = f;
+ *addr = buffer;
+
+ return 0;
+}
+
static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
VxLan *v = VXLAN(netdev);
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index 8c906f1075..6339af9add 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -33,10 +33,20 @@ struct VxLan {
NetDev meta;
uint64_t id;
+
+ int family;
union in_addr_union group;
+
unsigned tos;
unsigned ttl;
+
+ usec_t fdb_ageing;
+
bool learning;
+ bool arp_proxy;
+ bool route_short_circuit;
+ bool l2miss;
+ bool l3miss;
};
extern const NetDevVTable vxlan_vtable;
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index fd1f51ec56..b75eab9cd8 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -65,7 +65,6 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
-
static void netdev_cancel_callbacks(NetDev *netdev) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
netdev_join_callback *callback;
@@ -137,7 +136,7 @@ void netdev_drop(NetDev *netdev) {
netdev->state = NETDEV_STATE_LINGER;
- log_debug_netdev(netdev, "netdev removed");
+ log_netdev_debug(netdev, "netdev removed");
netdev_cancel_callbacks(netdev);
@@ -185,7 +184,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
RTM_SETLINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not allocate RTM_SETLINK message: %s",
strerror(-r));
return r;
@@ -193,7 +192,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_MASTER attribute: %s",
strerror(-r));
return r;
@@ -201,7 +200,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not send rtnetlink message: %s",
strerror(-r));
return r;
@@ -209,7 +208,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_hand
link_ref(link);
- log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
+ log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
return 0;
}
@@ -252,7 +251,7 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
r = sd_rtnl_message_get_errno(m);
if (r == -EEXIST)
- log_debug_netdev(netdev, "netdev exists, using existing");
+ log_netdev_debug(netdev, "netdev exists, using existing");
else if (r < 0) {
log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
netdev_drop(netdev);
@@ -260,7 +259,7 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
return 1;
}
- log_debug_netdev(netdev, "created");
+ log_netdev_debug(netdev, "created");
return 1;
}
@@ -289,7 +288,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callbac
LIST_PREPEND(callbacks, netdev->callbacks, cb);
- log_debug_netdev(netdev, "will enslave '%s', when reday",
+ log_netdev_debug(netdev, "will enslave '%s', when reday",
link->ifname);
}
@@ -308,29 +307,29 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
r = sd_rtnl_message_get_type(message, &type);
if (r < 0) {
- log_error_netdev(netdev, "Could not get rtnl message type");
+ log_netdev_error(netdev, "Could not get rtnl message type");
return r;
}
if (type != RTM_NEWLINK) {
- log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
+ log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
return -EINVAL;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
if (r < 0) {
- log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
+ log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
netdev_enter_failed(netdev);
return r;
} else if (ifindex <= 0) {
- log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
+ log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
netdev_enter_failed(netdev);
return r;
}
if (netdev->ifindex > 0) {
if (netdev->ifindex != ifindex) {
- log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
+ log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
ifindex, netdev->ifindex);
netdev_enter_failed(netdev);
return -EEXIST;
@@ -341,12 +340,12 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
if (r < 0) {
- log_error_netdev(netdev, "Could not get IFNAME");
+ log_netdev_error(netdev, "Could not get IFNAME");
return r;
}
if (!streq(netdev->ifname, received_name)) {
- log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
+ log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
received_name);
netdev_enter_failed(netdev);
return r;
@@ -354,19 +353,19 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
if (r < 0) {
- log_error_netdev(netdev, "Could not get LINKINFO");
+ log_netdev_error(netdev, "Could not get LINKINFO");
return r;
}
r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
if (r < 0) {
- log_error_netdev(netdev, "Could not get KIND");
+ log_netdev_error(netdev, "Could not get KIND");
return r;
}
r = sd_rtnl_message_exit_container(message);
if (r < 0) {
- log_error_netdev(netdev, "Could not exit container");
+ log_netdev_error(netdev, "Could not exit container");
return r;
}
@@ -376,14 +375,14 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
else {
kind = netdev_kind_to_string(netdev->kind);
if (!kind) {
- log_error_netdev(netdev, "Could not get kind");
+ log_netdev_error(netdev, "Could not get kind");
netdev_enter_failed(netdev);
return -EINVAL;
}
}
if (!streq(kind, received_kind)) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Received newlink with wrong KIND %s, "
"expected %s", received_kind, kind);
netdev_enter_failed(netdev);
@@ -392,7 +391,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
netdev->ifindex = ifindex;
- log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
+ log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
netdev_enter_ready(netdev);
@@ -460,13 +459,13 @@ static int netdev_create(NetDev *netdev, Link *link,
if (r < 0)
return r;
- log_debug_netdev(netdev, "created");
+ log_netdev_debug(netdev, "created");
} else {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not allocate RTM_NEWLINK message: %s",
strerror(-r));
return r;
@@ -474,7 +473,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_IFNAME, attribute: %s",
strerror(-r));
return r;
@@ -483,7 +482,7 @@ static int netdev_create(NetDev *netdev, Link *link,
if (netdev->mac) {
r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_ADDRESS attribute: %s",
strerror(-r));
return r;
@@ -493,7 +492,7 @@ static int netdev_create(NetDev *netdev, Link *link,
if (netdev->mtu) {
r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_MTU attribute: %s",
strerror(-r));
return r;
@@ -503,8 +502,8 @@ static int netdev_create(NetDev *netdev, Link *link,
if (link) {
r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
if (r < 0) {
- log_error_netdev(netdev,
- "Colud not append IFLA_LINK attribute: %s",
+ log_netdev_error(netdev,
+ "Could not append IFLA_LINK attribute: %s",
strerror(-r));
return r;
}
@@ -512,7 +511,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_LINKINFO attribute: %s",
strerror(-r));
return r;
@@ -521,7 +520,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
netdev_kind_to_string(netdev->kind));
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_INFO_DATA attribute: %s",
strerror(-r));
return r;
@@ -535,7 +534,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_message_close_container(m);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_LINKINFO attribute: %s",
strerror(-r));
return r;
@@ -543,7 +542,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_message_close_container(m);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not append IFLA_LINKINFO attribute: %s",
strerror(-r));
return r;
@@ -554,7 +553,7 @@ static int netdev_create(NetDev *netdev, Link *link,
r = sd_rtnl_call_async(netdev->manager->rtnl, m,
callback, link, 0, NULL);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not send rtnetlink message: %s",
strerror(-r));
return r;
@@ -566,7 +565,7 @@ static int netdev_create(NetDev *netdev, Link *link,
netdev_create_handler, netdev, 0,
NULL);
if (r < 0) {
- log_error_netdev(netdev,
+ log_netdev_error(netdev,
"Could not send rtnetlink message: %s",
strerror(-r));
return r;
@@ -577,7 +576,7 @@ static int netdev_create(NetDev *netdev, Link *link,
netdev->state = NETDEV_STATE_CREATING;
- log_debug_netdev(netdev, "creating");
+ log_netdev_debug(netdev, "creating");
}
return 0;
@@ -714,7 +713,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(netdev->callbacks);
- log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
+ log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
switch (NETDEV_VTABLE(netdev)->create_type) {
case NETDEV_CREATE_MASTER:
@@ -744,10 +743,8 @@ int netdev_load(Manager *manager) {
netdev_unref(netdev);
r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
- if (r < 0) {
- log_error("Failed to enumerate netdev files: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate netdev files: %m");
STRV_FOREACH_BACKWARDS(f, files) {
r = netdev_load_one(manager, *f);
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index e9a8a169db..c1e05c21fb 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -25,7 +25,6 @@
#include "hashmap.h"
#include "list.h"
#include "set.h"
-#include "condition-util.h"
#include "in-addr-util.h"
typedef struct NetDevVTable NetDevVTable;
@@ -193,12 +192,12 @@ const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, unsign
/* Macros which append INTERFACE= to the message */
-#define log_full_netdev(level, netdev, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", netdev->ifname, "%-*s: " fmt, IFNAMSIZ, netdev->ifname, ##__VA_ARGS__)
-#define log_debug_netdev(netdev, ...) log_full_netdev(LOG_DEBUG, netdev, ##__VA_ARGS__)
+#define log_full_netdev(level, netdev, fmt, ...) log_object_internal(level, 0, __FILE__, __LINE__, __func__, "INTERFACE=", netdev->ifname, "%-*s: " fmt, IFNAMSIZ, netdev->ifname, ##__VA_ARGS__)
+#define log_netdev_debug(netdev, ...) log_full_netdev(LOG_DEBUG, netdev, ##__VA_ARGS__)
#define log_info_netdev(netdev, ...) log_full_netdev(LOG_INFO, netdev, ##__VA_ARGS__)
#define log_notice_netdev(netdev, ...) log_full_netdev(LOG_NOTICE, netdev, ##__VA_ARGS__)
#define log_warning_netdev(netdev, ...) log_full_netdev(LOG_WARNING, netdev,## __VA_ARGS__)
-#define log_error_netdev(netdev, ...) log_full_netdev(LOG_ERR, netdev, ##__VA_ARGS__)
+#define log_netdev_error(netdev, ...) log_full_netdev(LOG_ERR, netdev, ##__VA_ARGS__)
#define log_struct_netdev(level, netdev, ...) log_struct(level, "INTERFACE=%s", netdev->ifname, __VA_ARGS__)
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index a73646187e..640a3a20b8 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -24,6 +24,8 @@ Match.Host, config_parse_net_condition, CONDITION_HOST,
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
+Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
+Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
Network.Description, config_parse_string, 0, offsetof(Network, description)
Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge)
Network.Bond, config_parse_netdev, 0, offsetof(Network, bond)
@@ -47,6 +49,7 @@ Address.Broadcast, config_parse_broadcast, 0,
Address.Label, config_parse_label, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
+Route.Source, config_parse_destination, 0, 0
Route.Metric, config_parse_route_priority, 0, 0
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
@@ -58,6 +61,7 @@ DHCP.RequestBroadcast, config_parse_bool, 0,
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
+Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
/* backwards compatibility: do not add new entries to this section */
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index aad99236c4..ef9e0a8c35 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -90,7 +90,14 @@ static int network_load_one(Manager *manager, const char *filename) {
network->llmnr = LLMNR_SUPPORT_YES;
r = config_parse(NULL, filename, file,
- "Match\0Network\0Address\0Route\0DHCP\0DHCPv4\0",
+ "Match\0"
+ "Link\0"
+ "Network\0"
+ "Address\0"
+ "Route\0"
+ "DHCP\0"
+ "DHCPv4\0"
+ "Bridge\0",
config_item_perf_lookup, network_network_gperf_lookup,
false, false, true, network);
if (r < 0)
@@ -131,10 +138,8 @@ int network_load(Manager *manager) {
network_free(network);
r = conf_files_list_strv(&files, ".network", NULL, network_dirs);
- if (r < 0) {
- log_error("Failed to enumerate network files: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate network files: %m");
STRV_FOREACH_BACKWARDS(f, files) {
r = network_load_one(manager, *f);
@@ -165,6 +170,8 @@ void network_free(Network *network) {
free(network->description);
free(network->dhcp_vendor_class_identifier);
+ free(network->mac);
+
strv_free(network->ntp);
strv_free(network->dns);
strv_free(network->domains);
@@ -219,8 +226,22 @@ int network_get(Manager *manager, struct udev_device *device,
udev_device_get_property_value(device, "ID_NET_DRIVER"),
udev_device_get_devtype(device),
ifname)) {
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname,
- network->filename);
+ if (network->match_name) {
+ const char *attr;
+ uint8_t name_assign_type = NET_NAME_UNKNOWN;
+
+ attr = udev_device_get_sysattr_value(device, "name_assign_type");
+ if (attr)
+ (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);
+ else
+ log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ } else
+ log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+
*ret = network;
return 0;
}
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 10d8cd902a..590dd49df9 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -113,18 +113,16 @@ int route_drop(Route *route, Link *link,
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
RTM_DELROUTE, route->family,
route->protocol);
- if (r < 0) {
- log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
- if (route->family == AF_INET)
- r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
- else if (route->family == AF_INET6)
- r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
- return r;
+ if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (route->family == AF_INET)
+ r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ else if (route->family == AF_INET6)
+ r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
@@ -132,16 +130,25 @@ int route_drop(Route *route, Link *link,
r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
else if (route->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_DST attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_DST attribute: %m");
r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
- if (r < 0) {
- log_error("Could not set destination prefix length: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set destination prefix length: %m");
+ }
+
+ if (route->src_prefixlen) {
+ if (route->family == AF_INET)
+ r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ else if (route->family == AF_INET6)
+ r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_DST attribute: %m");
+
+ r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set source prefix length: %m");
}
if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
@@ -149,35 +156,25 @@ int route_drop(Route *route, Link *link,
r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
else if (route->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
r = sd_rtnl_message_route_set_scope(req, route->scope);
- if (r < 0) {
- log_error("Could not set scope: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set scope: %m");
r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
- if (r < 0) {
- log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
- if (r < 0) {
- log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_error("Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -198,18 +195,16 @@ int route_configure(Route *route, Link *link,
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
RTM_NEWROUTE, route->family,
route->protocol);
- if (r < 0) {
- log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
- if (route->family == AF_INET)
- r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
- else if (route->family == AF_INET6)
- r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
- return r;
+ if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (route->family == AF_INET)
+ r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ else if (route->family == AF_INET6)
+ r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
@@ -217,16 +212,25 @@ int route_configure(Route *route, Link *link,
r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
else if (route->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_DST attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_DST attribute: %m");
r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
- if (r < 0) {
- log_error("Could not set destination prefix length: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set destination prefix length: %m");
+ }
+
+ if (route->src_prefixlen) {
+ if (route->family == AF_INET)
+ r = sd_rtnl_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ else if (route->family == AF_INET6)
+ r = sd_rtnl_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
+
+ r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
+ if (r < 0)
+ return log_error_errno(r, "Could not set source prefix length: %m");
}
if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
@@ -234,35 +238,25 @@ int route_configure(Route *route, Link *link,
r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
else if (route->family == AF_INET6)
r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
- if (r < 0) {
- log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
r = sd_rtnl_message_route_set_scope(req, route->scope);
- if (r < 0) {
- log_error("Could not set scope: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not set scope: %m");
r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
- if (r < 0) {
- log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
- if (r < 0) {
- log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0) {
- log_error("Could not send rtnetlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not send rtnetlink message: %m");
link_ref(link);
@@ -330,6 +324,7 @@ int config_parse_destination(const char *unit,
_cleanup_route_free_ Route *n = NULL;
const char *address, *e;
union in_addr_union buffer;
+ unsigned char prefixlen;
int r, f;
assert(filename);
@@ -342,7 +337,7 @@ int config_parse_destination(const char *unit,
if (r < 0)
return r;
- /* Destination=address/prefixlen */
+ /* Destination|Source=address/prefixlen */
/* address */
e = strchr(rvalue, '/');
@@ -358,31 +353,41 @@ int config_parse_destination(const char *unit,
return 0;
}
+ if (f != AF_INET && f != AF_INET6) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Unknown address family, ignoring assignment: %s", address);
+ return 0;
+ }
+
/* prefixlen */
if (e) {
- unsigned i;
-
- r = safe_atou(e + 1, &i);
+ r = safe_atou8(e + 1, &prefixlen);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
-
- n->dst_prefixlen = (unsigned char) i;
} else {
- switch (n->family) {
+ switch (f) {
case AF_INET:
- n->dst_prefixlen = 32;
+ prefixlen = 32;
break;
case AF_INET6:
- n->dst_prefixlen = 128;
+ prefixlen = 128;
break;
}
}
n->family = f;
- n->dst_addr = buffer;
+ if (streq(lvalue, "Destination")) {
+ n->dst_addr = buffer;
+ n->dst_prefixlen = prefixlen;
+ } else if (streq(lvalue, "Source")) {
+ n->src_addr = buffer;
+ n->src_prefixlen = prefixlen;
+ } else
+ assert_not_reached(lvalue);
+
n = NULL;
return 0;
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c
index 6e3ec6935d..3f2b96688c 100644
--- a/src/network/networkd-wait-online-manager.c
+++ b/src/network/networkd-wait-online-manager.c
@@ -37,7 +37,7 @@ bool manager_all_configured(Manager *m) {
char **ifname;
bool one_ready = false;
- /* wait for all the links given on the commandline to appear */
+ /* wait for all the links given on the command line to appear */
STRV_FOREACH(ifname, m->interfaces) {
l = hashmap_get(m->links_by_name, *ifname);
if (!l) {
@@ -134,7 +134,7 @@ static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userda
return 0;
fail:
- log_warning("Failed to process RTNL link message: %s", strerror(-r));
+ log_warning_errno(r, "Failed to process RTNL link message: %m");
return 0;
}
@@ -211,7 +211,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
HASHMAP_FOREACH(l, m->links, i) {
r = link_update_monitor(l);
if (r < 0)
- log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
+ log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
}
if (manager_all_configured(m))
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index 714343656b..32a8d85301 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -113,7 +113,7 @@ int main(int argc, char *argv[]) {
r = manager_new(&m, arg_interfaces);
if (r < 0) {
- log_error("Could not create manager: %s", strerror(-r));
+ log_error_errno(r, "Could not create manager: %m");
goto finish;
}
@@ -128,7 +128,7 @@ int main(int argc, char *argv[]) {
r = sd_event_loop(m->event);
if (r < 0) {
- log_error("Event loop failed: %s", strerror(-r));
+ log_error_errno(r, "Event loop failed: %m");
goto finish;
}
diff --git a/src/network/networkd.c b/src/network/networkd.c
index fdb80368d4..0b386d4069 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
- log_error("Cannot resolve user name %s: %s", user, strerror(-r));
+ log_error_errno(r, "Cannot resolve user name %s: %m", user);
goto out;
}
@@ -54,18 +54,15 @@ int main(int argc, char *argv[]) {
* watches in. */
r = mkdir_safe_label("/run/systemd/netif", 0755, uid, gid);
if (r < 0)
- log_error("Could not create runtime directory: %s",
- strerror(-r));
+ log_error_errno(r, "Could not create runtime directory: %m");
r = mkdir_safe_label("/run/systemd/netif/links", 0755, uid, gid);
if (r < 0)
- log_error("Could not create runtime directory 'links': %s",
- strerror(-r));
+ log_error_errno(r, "Could not create runtime directory 'links': %m");
r = mkdir_safe_label("/run/systemd/netif/leases", 0755, uid, gid);
if (r < 0)
- log_error("Could not create runtime directory 'leases': %s",
- strerror(-r));
+ log_error_errno(r, "Could not create runtime directory 'leases': %m");
r = drop_privileges(uid, gid,
(1ULL << CAP_NET_ADMIN) |
@@ -79,37 +76,43 @@ int main(int argc, char *argv[]) {
r = manager_new(&m);
if (r < 0) {
- log_error("Could not create manager: %s", strerror(-r));
+ log_error_errno(r, "Could not create manager: %m");
goto out;
}
r = manager_udev_listen(m);
if (r < 0) {
- log_error("Could not connect to udev: %s", strerror(-r));
+ log_error_errno(r, "Could not connect to udev: %m");
goto out;
}
r = manager_rtnl_listen(m);
if (r < 0) {
- log_error("Could not connect to rtnl: %s", strerror(-r));
+ log_error_errno(r, "Could not connect to rtnl: %m");
goto out;
}
r = manager_bus_listen(m);
if (r < 0) {
- log_error("Could not connect to system bus: %s", strerror(-r));
+ log_error_errno(r, "Could not connect to system bus: %m");
goto out;
}
r = manager_load_config(m);
if (r < 0) {
- log_error("Could not load configuration files: %s", strerror(-r));
+ log_error_errno(r, "Could not load configuration files: %m");
goto out;
}
r = manager_rtnl_enumerate_links(m);
if (r < 0) {
- log_error("Could not enumerate links: %s", strerror(-r));
+ log_error_errno(r, "Could not enumerate links: %m");
+ goto out;
+ }
+
+ r = manager_rtnl_enumerate_addresses(m);
+ if (r < 0) {
+ log_error_errno(r, "Could not enumerate links: %m");
goto out;
}
@@ -119,7 +122,7 @@ int main(int argc, char *argv[]) {
r = sd_event_loop(m->event);
if (r < 0) {
- log_error("Event loop failed: %s", strerror(-r));
+ log_error_errno(r, "Event loop failed: %m");
goto out;
}
diff --git a/src/network/networkd.h b/src/network/networkd.h
index d4e79ab2f3..4cdcd73c5d 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -37,7 +37,7 @@
#include "hashmap.h"
#include "list.h"
#include "set.h"
-#include "condition-util.h"
+#include "condition.h"
#include "in-addr-util.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
@@ -106,6 +106,11 @@ struct Network {
bool dhcp_server;
+ unsigned cost;
+
+ struct ether_addr *mac;
+ unsigned mtu;
+
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
@@ -145,12 +150,14 @@ struct Route {
int family;
unsigned char dst_prefixlen;
+ unsigned char src_prefixlen;
unsigned char scope;
uint32_t metrics;
unsigned char protocol; /* RTPROT_* */
union in_addr_union in_addr;
union in_addr_union dst_addr;
+ union in_addr_union src_addr;
union in_addr_union prefsrc_addr;
LIST_FIELDS(Route, routes);
@@ -196,6 +203,7 @@ int manager_load_config(Manager *m);
bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
+int manager_rtnl_enumerate_addresses(Manager *m);
int manager_rtnl_listen(Manager *m);
int manager_udev_listen(Manager *m);
@@ -259,6 +267,17 @@ int config_parse_tunnel_address(const char *unit,
void *data,
void *userdata);
+int config_parse_vxlan_group_address(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);
+
/* gperf */
const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length);
@@ -333,20 +352,3 @@ int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, cons
void address_pool_free(AddressPool *p);
int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found);
-
-/* Macros which append INTERFACE= to the message */
-
-#define log_full_link(level, link, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", link->ifname, "%-*s: " fmt, IFNAMSIZ, link->ifname, ##__VA_ARGS__)
-#define log_debug_link(link, ...) log_full_link(LOG_DEBUG, link, ##__VA_ARGS__)
-#define log_info_link(link, ...) log_full_link(LOG_INFO, link, ##__VA_ARGS__)
-#define log_notice_link(link, ...) log_full_link(LOG_NOTICE, link, ##__VA_ARGS__)
-#define log_warning_link(link, ...) log_full_link(LOG_WARNING, link, ##__VA_ARGS__)
-#define log_error_link(link, ...) log_full_link(LOG_ERR, link, ##__VA_ARGS__)
-
-#define log_struct_link(level, link, ...) log_struct(level, "INTERFACE=%s", link->ifname, __VA_ARGS__)
-
-#define ADDRESS_FMT_VAL(address) \
- (address).s_addr & 0xFF, \
- ((address).s_addr >> 8) & 0xFF, \
- ((address).s_addr >> 16) & 0xFF, \
- (address).s_addr >> 24
diff --git a/src/notify/notify.c b/src/notify/notify.c
index a0f757a252..5bf901ec6a 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -193,7 +193,7 @@ int main(int argc, char* argv[]) {
r = sd_pid_notify(arg_pid, false, n);
if (r < 0) {
- log_error("Failed to notify init system: %s", strerror(-r));
+ log_error_errno(r, "Failed to notify init system: %m");
goto finish;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index b6d9bc631c..0466ddbff3 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -89,6 +89,8 @@
#include "copy.h"
#include "base-filesystem.h"
#include "barrier.h"
+#include "event-util.h"
+#include "cap-list.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
@@ -123,6 +125,7 @@ static bool arg_private_network = false;
static bool arg_read_only = false;
static bool arg_boot = false;
static LinkJournal arg_link_journal = LINK_AUTO;
+static bool arg_link_journal_try = false;
static uint64_t arg_retain =
(1ULL << CAP_CHOWN) |
(1ULL << CAP_DAC_OVERRIDE) |
@@ -201,8 +204,9 @@ static void help(void) {
" --capability=CAP In addition to the default, retain specified\n"
" capability\n"
" --drop-capability=CAP Drop the specified capability from the default set\n"
- " --link-journal=MODE Link up guest journal, one of no, auto, guest, host\n"
- " -j Equivalent to --link-journal=host\n"
+ " --link-journal=MODE Link up guest journal, one of no, auto, guest, host,\n"
+ " try-guest, try-host\n"
+ " -j Equivalent to --link-journal=try-guest\n"
" --read-only Mount the root directory read-only\n"
" --bind=PATH[:PATH] Bind mount a file or directory from the host into\n"
" the container\n"
@@ -299,7 +303,7 @@ static int parse_argv(int argc, char *argv[]) {
free(arg_directory);
arg_directory = canonicalize_file_name(optarg);
if (!arg_directory) {
- log_error("Invalid root directory: %m");
+ log_error_errno(errno, "Invalid root directory: %m");
return -ENOMEM;
}
@@ -398,7 +402,6 @@ static int parse_argv(int argc, char *argv[]) {
FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
_cleanup_free_ char *t;
- cap_value_t cap;
t = strndup(word, length);
if (!t)
@@ -410,7 +413,10 @@ static int parse_argv(int argc, char *argv[]) {
else
minus = (uint64_t) -1;
} else {
- if (cap_from_name(t, &cap) < 0) {
+ int cap;
+
+ cap = capability_from_name(t);
+ if (cap < 0) {
log_error("Failed to parse capability %s.", t);
return -EINVAL;
}
@@ -427,6 +433,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'j':
arg_link_journal = LINK_GUEST;
+ arg_link_journal_try = true;
break;
case ARG_LINK_JOURNAL:
@@ -438,7 +445,13 @@ static int parse_argv(int argc, char *argv[]) {
arg_link_journal = LINK_GUEST;
else if (streq(optarg, "host"))
arg_link_journal = LINK_HOST;
- else {
+ else if (streq(optarg, "try-guest")) {
+ arg_link_journal = LINK_GUEST;
+ arg_link_journal_try = true;
+ } else if (streq(optarg, "try-host")) {
+ arg_link_journal = LINK_HOST;
+ arg_link_journal_try = true;
+ } else {
log_error("Failed to parse link journal mode %s", optarg);
return -EINVAL;
}
@@ -663,7 +676,7 @@ static int mount_all(const char *dest) {
t = path_is_mount_point(where, true);
if (t < 0) {
- log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t));
+ log_error_errno(t, "Failed to detect whether %s is a mount point: %m", where);
if (r == 0)
r = t;
@@ -678,12 +691,12 @@ static int mount_all(const char *dest) {
t = mkdir_p(where, 0755);
if (t < 0) {
if (mount_table[k].fatal) {
- log_error("Failed to create directory %s: %s", where, strerror(-t));
+ log_error_errno(t, "Failed to create directory %s: %m", where);
if (r == 0)
r = t;
} else
- log_warning("Failed to create directory %s: %s", where, strerror(-t));
+ log_warning_errno(t, "Failed to create directory %s: %m", where);
continue;
}
@@ -708,12 +721,12 @@ static int mount_all(const char *dest) {
o) < 0) {
if (mount_table[k].fatal) {
- log_error("mount(%s) failed: %m", where);
+ log_error_errno(errno, "mount(%s) failed: %m", where);
if (r == 0)
r = -errno;
} else
- log_warning("mount(%s) failed: %m", where);
+ log_warning_errno(errno, "mount(%s) failed: %m", where);
}
}
@@ -728,10 +741,8 @@ static int mount_binds(const char *dest, char **l, bool ro) {
struct stat source_st, dest_st;
int r;
- if (stat(*x, &source_st) < 0) {
- log_error("Failed to stat %s: %m", *x);
- return -errno;
- }
+ if (stat(*x, &source_st) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", *x);
where = strappend(dest, *y);
if (!where)
@@ -745,12 +756,10 @@ static int mount_binds(const char *dest, char **l, bool ro) {
}
} else if (errno == ENOENT) {
r = mkdir_parents_label(where, 0755);
- if (r < 0) {
- log_error("Failed to bind mount %s: %s", *x, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind mount %s: %m", *x);
} else {
- log_error("Failed to bind mount %s: %m", *x);
+ log_error_errno(errno, "Failed to bind mount %s: %m", *x);
return -errno;
}
@@ -758,48 +767,32 @@ static int mount_binds(const char *dest, char **l, bool ro) {
* and char devices. */
if (S_ISDIR(source_st.st_mode)) {
r = mkdir_label(where, 0755);
- if (r < 0) {
- log_error("Failed to create mount point %s: %s", where, strerror(-r));
-
- return r;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(r, "Failed to create mount point %s: %m", where);
} else if (S_ISFIFO(source_st.st_mode)) {
r = mkfifo(where, 0644);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create mount point %s: %m", where);
-
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create mount point %s: %m", where);
} else if (S_ISSOCK(source_st.st_mode)) {
r = mknod(where, 0644 | S_IFSOCK, 0);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create mount point %s: %m", where);
-
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create mount point %s: %m", where);
} else if (S_ISREG(source_st.st_mode)) {
r = touch(where);
- if (r < 0) {
- log_error("Failed to create mount point %s: %s", where, strerror(-r));
-
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create mount point %s: %m", where);
} else {
log_error("Refusing to create mountpoint for file: %s", *x);
return -ENOTSUP;
}
- if (mount(*x, where, "bind", MS_BIND, NULL) < 0) {
- log_error("mount(%s) failed: %m", where);
- return -errno;
- }
+ if (mount(*x, where, "bind", MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "mount(%s) failed: %m", where);
if (ro) {
r = bind_remount_recursive(where, true);
- if (r < 0) {
- log_error("Read-Only bind mount failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Read-Only bind mount failed: %m");
}
}
@@ -818,16 +811,11 @@ static int mount_tmpfs(const char *dest) {
return log_oom();
r = mkdir_label(where, 0755);
- if (r < 0) {
- log_error("creating mount point for tmpfs %s failed: %s", where, strerror(-r));
-
- return r;
- }
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
- if (mount("tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, *o) < 0) {
- log_error("tmpfs mount to %s failed: %m", where);
- return -errno;
- }
+ if (mount("tmpfs", where, "tmpfs", MS_NODEV|MS_STRICTATIME, *o) < 0)
+ return log_error_errno(errno, "tmpfs mount to %s failed: %m", where);
}
return 0;
@@ -885,20 +873,20 @@ static int setup_timezone(const char *dest) {
r = mkdir_parents(where, 0755);
if (r < 0) {
- log_error("Failed to create directory for timezone info %s in container: %s", where, strerror(-r));
+ log_error_errno(r, "Failed to create directory for timezone info %s in container: %m", where);
return 0;
}
r = unlink(where);
if (r < 0 && errno != ENOENT) {
- log_error("Failed to remove existing timezone info %s in container: %m", where);
+ log_error_errno(errno, "Failed to remove existing timezone info %s in container: %m", where);
return 0;
}
if (symlink(what, where) < 0) {
- log_error("Failed to correct timezone of container: %m");
+ log_error_errno(errno, "Failed to correct timezone of container: %m");
return 0;
}
@@ -923,14 +911,14 @@ static int setup_resolv_conf(const char *dest) {
* fails, it fails, but meh... */
r = mkdir_parents(where, 0755);
if (r < 0) {
- log_warning("Failed to create parent directory for resolv.conf %s: %s", where, strerror(-r));
+ log_warning_errno(r, "Failed to create parent directory for resolv.conf %s: %m", where);
return 0;
}
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644);
if (r < 0) {
- log_warning("Failed to copy /etc/resolv.conf to %s: %s", where, strerror(-r));
+ log_warning_errno(r, "Failed to copy /etc/resolv.conf to %s: %m", where);
return 0;
}
@@ -951,22 +939,16 @@ static int setup_volatile_state(const char *directory) {
with a tmpfs, and the rest read-only. */
r = bind_remount_recursive(directory, true);
- if (r < 0) {
- log_error("Failed to remount %s read-only: %s", directory, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to remount %s read-only: %m", directory);
p = strappenda(directory, "/var");
r = mkdir(p, 0755);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create %s: %m", directory);
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create %s: %m", directory);
- if (mount("tmpfs", p, "tmpfs", MS_STRICTATIME, "mode=755") < 0) {
- log_error("Failed to mount tmpfs to /var: %m");
- return -errno;
- }
+ if (mount("tmpfs", p, "tmpfs", MS_STRICTATIME, "mode=755") < 0)
+ return log_error_errno(errno, "Failed to mount tmpfs to /var: %m");
return 0;
}
@@ -985,13 +967,11 @@ static int setup_volatile(const char *directory) {
/* --volatile=yes means we mount a tmpfs to the root dir, and
the original /usr to use inside it, and that read-only. */
- if (!mkdtemp(template)) {
- log_error("Failed to create temporary directory: %m");
- return -errno;
- }
+ if (!mkdtemp(template))
+ return log_error_errno(errno, "Failed to create temporary directory: %m");
if (mount("tmpfs", template, "tmpfs", MS_STRICTATIME, "mode=755") < 0) {
- log_error("Failed to mount tmpfs for root directory: %m");
+ log_error_errno(errno, "Failed to mount tmpfs for root directory: %m");
r = -errno;
goto fail;
}
@@ -1003,13 +983,13 @@ static int setup_volatile(const char *directory) {
r = mkdir(t, 0755);
if (r < 0 && errno != EEXIST) {
- log_error("Failed to create %s: %m", t);
+ log_error_errno(errno, "Failed to create %s: %m", t);
r = -errno;
goto fail;
}
if (mount(f, t, "bind", MS_BIND|MS_REC, NULL) < 0) {
- log_error("Failed to create /usr bind mount: %m");
+ log_error_errno(errno, "Failed to create /usr bind mount: %m");
r = -errno;
goto fail;
}
@@ -1018,12 +998,12 @@ static int setup_volatile(const char *directory) {
r = bind_remount_recursive(t, true);
if (r < 0) {
- log_error("Failed to remount %s read-only: %s", t, strerror(-r));
+ log_error_errno(r, "Failed to remount %s read-only: %m", t);
goto fail;
}
if (mount(template, directory, NULL, MS_MOVE, NULL) < 0) {
- log_error("Failed to move root mount: %m");
+ log_error_errno(errno, "Failed to move root mount: %m");
r = -errno;
goto fail;
}
@@ -1070,24 +1050,20 @@ static int setup_boot_id(const char *dest) {
return log_oom();
r = sd_id128_randomize(&rnd);
- if (r < 0) {
- log_error("Failed to generate random boot id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate random boot id: %m");
id128_format_as_uuid(rnd, as_uuid);
r = write_string_file(from, as_uuid);
- if (r < 0) {
- log_error("Failed to write boot id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to write boot id: %m");
if (mount(from, to, "bind", MS_BIND, NULL) < 0) {
- log_error("Failed to bind mount boot id: %m");
+ log_error_errno(errno, "Failed to bind mount boot id: %m");
r = -errno;
} else if (mount(from, to, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL))
- log_warning("Failed to make boot id read-only: %m");
+ log_warning_errno(errno, "Failed to make boot id read-only: %m");
unlink(from);
return r;
@@ -1123,10 +1099,8 @@ static int copy_devnodes(const char *dest) {
if (stat(from, &st) < 0) {
- if (errno != ENOENT) {
- log_error("Failed to stat %s: %m", from);
- return -errno;
- }
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to stat %s: %m", from);
} else if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
@@ -1136,14 +1110,12 @@ static int copy_devnodes(const char *dest) {
} else {
r = mkdir_parents(to, 0775);
if (r < 0) {
- log_error("Failed to create parent directory of %s: %s", to, strerror(-r));
+ log_error_errno(r, "Failed to create parent directory of %s: %m", to);
return -r;
}
- if (mknod(to, st.st_mode, st.st_rdev) < 0) {
- log_error("mknod(%s) failed: %m", dest);
- return -errno;
- }
+ if (mknod(to, st.st_mode, st.st_rdev) < 0)
+ return log_error_errno(errno, "mknod(%s) failed: %m", dest);
}
}
@@ -1157,10 +1129,8 @@ static int setup_ptmx(const char *dest) {
if (!p)
return log_oom();
- if (symlink("pts/ptmx", p) < 0) {
- log_error("Failed to create /dev/ptmx symlink: %m");
- return -errno;
- }
+ if (symlink("pts/ptmx", p) < 0)
+ return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m");
return 0;
}
@@ -1176,16 +1146,12 @@ static int setup_dev_console(const char *dest, const char *console) {
u = umask(0000);
- if (stat("/dev/null", &st) < 0) {
- log_error("Failed to stat /dev/null: %m");
- return -errno;
- }
+ if (stat("/dev/null", &st) < 0)
+ return log_error_errno(errno, "Failed to stat /dev/null: %m");
r = chmod_and_chown(console, 0600, 0, 0);
- if (r < 0) {
- log_error("Failed to correct access mode for TTY: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to correct access mode for TTY: %m");
/* We need to bind mount the right tty to /dev/console since
* ptys can only exist on pts file systems. To have something
@@ -1196,15 +1162,11 @@ static int setup_dev_console(const char *dest, const char *console) {
* matter here, since we mount it over anyway). */
to = strappenda(dest, "/dev/console");
- if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
- log_error("mknod() for /dev/console failed: %m");
- return -errno;
- }
+ if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0)
+ return log_error_errno(errno, "mknod() for /dev/console failed: %m");
- if (mount(console, to, "bind", MS_BIND, NULL) < 0) {
- log_error("Bind mount for /dev/console failed: %m");
- return -errno;
- }
+ if (mount(console, to, "bind", MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Bind mount for /dev/console failed: %m");
return 0;
}
@@ -1239,27 +1201,19 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
asprintf(&to, "%s/proc/kmsg", dest) < 0)
return log_oom();
- if (mkfifo(from, 0600) < 0) {
- log_error("mkfifo() for /dev/kmsg failed: %m");
- return -errno;
- }
+ if (mkfifo(from, 0600) < 0)
+ return log_error_errno(errno, "mkfifo() for /dev/kmsg failed: %m");
r = chmod_and_chown(from, 0600, 0, 0);
- if (r < 0) {
- log_error("Failed to correct access mode for /dev/kmsg: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to correct access mode for /dev/kmsg: %m");
- if (mount(from, to, "bind", MS_BIND, NULL) < 0) {
- log_error("Bind mount for /proc/kmsg failed: %m");
- return -errno;
- }
+ if (mount(from, to, "bind", MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Bind mount for /proc/kmsg failed: %m");
fd = open(from, O_RDWR|O_NDELAY|O_CLOEXEC);
- if (fd < 0) {
- log_error("Failed to open fifo: %m");
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open fifo: %m");
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
@@ -1274,10 +1228,8 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
k = sendmsg(kmsg_socket, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
safe_close(fd);
- if (k < 0) {
- log_error("Failed to send FIFO fd: %m");
- return -errno;
- }
+ if (k < 0)
+ return log_error_errno(errno, "Failed to send FIFO fd: %m");
/* And now make the FIFO unavailable as /dev/kmsg... */
unlink(from);
@@ -1308,10 +1260,8 @@ static int setup_journal(const char *directory) {
r = read_one_line_file(p, &b);
if (r == -ENOENT && arg_link_journal == LINK_AUTO)
return 0;
- else if (r < 0) {
- log_error("Failed to read machine ID from %s: %s", p, strerror(-r));
- return r;
- }
+ else if (r < 0)
+ return log_error_errno(r, "Failed to read machine ID from %s: %m", p);
id = strstrip(b);
if (isempty(id) && arg_link_journal == LINK_AUTO)
@@ -1319,16 +1269,12 @@ static int setup_journal(const char *directory) {
/* Verify validity */
r = sd_id128_from_string(id, &machine_id);
- if (r < 0) {
- log_error("Failed to parse machine ID from %s: %s", p, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse machine ID from %s: %m", p);
r = sd_id128_get_machine(&this_id);
- if (r < 0) {
- log_error("Failed to retrieve machine ID: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to retrieve machine ID: %m");
if (sd_id128_equal(machine_id, this_id)) {
log_full(arg_link_journal == LINK_AUTO ? LOG_WARNING : LOG_ERR,
@@ -1374,14 +1320,12 @@ static int setup_journal(const char *directory) {
r = mkdir_p(q, 0755);
if (r < 0)
- log_warning("Failed to create directory %s: %m", q);
+ log_warning_errno(errno, "Failed to create directory %s: %m", q);
return 0;
}
- if (unlink(p) < 0) {
- log_error("Failed to remove symlink %s: %m", p);
- return -errno;
- }
+ if (unlink(p) < 0)
+ return log_error_errno(errno, "Failed to remove symlink %s: %m", p);
} else if (r == -EINVAL) {
if (arg_link_journal == LINK_GUEST &&
@@ -1391,33 +1335,45 @@ static int setup_journal(const char *directory) {
log_error("%s already exists and is neither a symlink nor a directory", p);
return r;
} else {
- log_error("Failed to remove %s: %m", p);
+ log_error_errno(errno, "Failed to remove %s: %m", p);
return -errno;
}
}
} else if (r != -ENOENT) {
- log_error("readlink(%s) failed: %m", p);
+ log_error_errno(errno, "readlink(%s) failed: %m", p);
return r;
}
if (arg_link_journal == LINK_GUEST) {
if (symlink(q, p) < 0) {
- log_error("Failed to symlink %s to %s: %m", q, p);
- return -errno;
+ 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;
+ }
}
r = mkdir_p(q, 0755);
if (r < 0)
- log_warning("Failed to create directory %s: %m", q);
+ log_warning_errno(errno, "Failed to create directory %s: %m", q);
return 0;
}
if (arg_link_journal == LINK_HOST) {
- r = mkdir_p(p, 0755);
+ /* don't create parents here -- if the host doesn't have
+ * permanent journal set up, don't force it here */
+ r = mkdir(p, 0755);
if (r < 0) {
- log_error("Failed to create %s: %m", p);
- return r;
+ 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 if (access(p, F_OK) < 0)
@@ -1428,34 +1384,12 @@ static int setup_journal(const char *directory) {
r = mkdir_p(q, 0755);
if (r < 0) {
- log_error("Failed to create %s: %m", q);
+ log_error_errno(errno, "Failed to create %s: %m", q);
return r;
}
- if (mount(p, q, "bind", MS_BIND, NULL) < 0) {
- log_error("Failed to bind mount journal from host into guest: %m");
- return -errno;
- }
-
- return 0;
-}
-
-static int setup_kdbus(const char *dest, const char *path) {
- const char *p;
-
- if (!path)
- return 0;
-
- p = strappenda(dest, "/dev/kdbus");
- if (mkdir(p, 0755) < 0) {
- log_error("Failed to create kdbus path: %m");
- return -errno;
- }
-
- if (mount(path, p, "bind", MS_BIND, NULL) < 0) {
- log_error("Failed to mount kdbus domain path: %m");
- return -errno;
- }
+ if (mount(p, q, "bind", MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m");
return 0;
}
@@ -1473,10 +1407,8 @@ static int register_machine(pid_t pid, int local_ifindex) {
return 0;
r = sd_bus_default_system(&bus);
- if (r < 0) {
- log_error("Failed to open system bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open system bus: %m");
if (arg_keep_unit) {
r = sd_bus_call_method(
@@ -1505,10 +1437,8 @@ static int register_machine(pid_t pid, int local_ifindex) {
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"CreateMachineWithNetwork");
- if (r < 0) {
- log_error("Failed to create message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create message: %m");
r = sd_bus_message_append(
m,
@@ -1520,32 +1450,24 @@ static int register_machine(pid_t pid, int local_ifindex) {
(uint32_t) pid,
strempty(arg_directory),
local_ifindex > 0 ? 1 : 0, local_ifindex);
- if (r < 0) {
- log_error("Failed to append message arguments: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append message arguments: %m");
r = sd_bus_message_open_container(m, 'a', "(sv)");
- if (r < 0) {
- log_error("Failed to open container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open container: %m");
if (!isempty(arg_slice)) {
r = sd_bus_message_append(m, "(sv)", "Slice", "s", arg_slice);
- if (r < 0) {
- log_error("Failed to append slice: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append slice: %m");
}
r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");
- if (r < 0) {
- log_error("Failed to add device policy: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add device policy: %m");
- r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 11,
+ r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9,
/* Allow the container to
* access and create the API
* device nodes, so that
@@ -1565,28 +1487,13 @@ static int register_machine(pid_t pid, int local_ifindex) {
* container to ever create
* these device nodes. */
"/dev/pts/ptmx", "rw",
- "char-pts", "rw",
- /* Allow the container
- * access to all kdbus
- * devices. Again, the
- * container cannot create
- * these nodes, only use
- * them. We use a pretty
- * open match here, so that
- * the kernel API can still
- * change. */
- "char-kdbus", "rw",
- "char-kdbus/*", "rw");
- if (r < 0) {
- log_error("Failed to add device whitelist: %s", strerror(-r));
- return r;
- }
+ "char-pts", "rw");
+ if (r < 0)
+ return log_error_errno(r, "Failed to add device whitelist: %m");
r = sd_bus_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close container: %m");
r = sd_bus_call(bus, m, 0, &error, NULL);
}
@@ -1610,10 +1517,8 @@ static int terminate_machine(pid_t pid) {
return 0;
r = sd_bus_default_system(&bus);
- if (r < 0) {
- log_error("Failed to open system bus: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open system bus: %m");
r = sd_bus_call_method(
bus,
@@ -1664,10 +1569,8 @@ static int reset_audit_loginuid(void) {
r = read_one_line_file("/proc/self/loginuid", &p);
if (r == -ENOENT)
return 0;
- if (r < 0) {
- log_error("Failed to read /proc/self/loginuid: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read /proc/self/loginuid: %m");
/* Already reset? */
if (streq(p, "4294967295"))
@@ -1689,16 +1592,19 @@ static int reset_audit_loginuid(void) {
#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 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(struct ether_addr *mac, sd_id128_t hash_key) {
- int r;
-
+static int generate_mac(struct ether_addr *mac, sd_id128_t hash_key, uint64_t idx) {
uint8_t result[8];
size_t l, sz;
- uint8_t *v;
+ uint8_t *v, *i;
+ int r;
l = strlen(arg_machine);
sz = sizeof(sd_id128_t) + l;
+ if (idx > 0)
+ sz += sizeof(idx);
+
v = alloca(sz);
/* fetch some persistent data unique to the host */
@@ -1708,7 +1614,11 @@ static int generate_mac(struct ether_addr *mac, sd_id128_t hash_key) {
/* combine with some data unique (on this host) to this
* container instance */
- memcpy(v + sizeof(sd_id128_t), arg_machine, l);
+ i = mempcpy(v + sizeof(sd_id128_t), arg_machine, l);
+ if (idx > 0) {
+ idx = htole64(idx);
+ memcpy(i, &idx, sizeof(idx));
+ }
/* Let's hash the host machine ID plus the container name. We
* use a fixed, but originally randomly created hash key here. */
@@ -1741,107 +1651,73 @@ static int setup_veth(pid_t pid, char iface_name[IFNAMSIZ], int *ifi) {
snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
arg_network_bridge ? "vb" : "ve", arg_machine);
- r = generate_mac(&mac_container, CONTAINER_HASH_KEY);
- if (r < 0) {
- log_error("Failed to generate predictable MAC address for container side");
- return r;
- }
+ r = generate_mac(&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(&mac_host, HOST_HASH_KEY);
- if (r < 0) {
- log_error("Failed to generate predictable MAC address for host side");
- return r;
- }
+ r = generate_mac(&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_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
- if (r < 0) {
- log_error("Failed to allocate netlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, iface_name);
- if (r < 0) {
- log_error("Failed to add netlink interface name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host);
- if (r < 0) {
- log_error("Failed to add netlink MAC address: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink MAC address: %m");
r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
- if (r < 0) {
- log_error("Failed to open netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open netlink container: %m");
r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "veth");
- if (r < 0) {
- log_error("Failed to open netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open netlink container: %m");
r = sd_rtnl_message_open_container(m, VETH_INFO_PEER);
- if (r < 0) {
- log_error("Failed to open netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open netlink container: %m");
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, "host0");
- if (r < 0) {
- log_error("Failed to add netlink interface name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container);
- if (r < 0) {
- log_error("Failed to add netlink MAC address: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink MAC address: %m");
r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
- if (r < 0) {
- log_error("Failed to add netlink namespace field: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink namespace field: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close netlink container: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close netlink container: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close netlink container: %m");
r = sd_rtnl_call(rtnl, m, 0, NULL);
- if (r < 0) {
- log_error("Failed to add new veth interfaces: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add new veth interfaces: %m");
i = (int) if_nametoindex(iface_name);
- if (i <= 0) {
- log_error("Failed to resolve interface %s: %m", iface_name);
- return -errno;
- }
+ if (i <= 0)
+ return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
*ifi = i;
@@ -1863,48 +1739,34 @@ static int setup_bridge(const char veth_name[], int *ifi) {
return 0;
bridge = (int) if_nametoindex(arg_network_bridge);
- if (bridge <= 0) {
- log_error("Failed to resolve interface %s: %m", arg_network_bridge);
- return -errno;
- }
+ if (bridge <= 0)
+ return log_error_errno(errno, "Failed to resolve interface %s: %m", arg_network_bridge);
*ifi = bridge;
r = sd_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
- if (r < 0) {
- log_error("Failed to allocate netlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
- if (r < 0) {
- log_error("Failed to set IFF_UP flag: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set IFF_UP flag: %m");
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, veth_name);
- if (r < 0) {
- log_error("Failed to add netlink interface name field: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name field: %m");
r = sd_rtnl_message_append_u32(m, IFLA_MASTER, bridge);
- if (r < 0) {
- log_error("Failed to add netlink master field: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink master field: %m");
r = sd_rtnl_call(rtnl, m, 0, NULL);
- if (r < 0) {
- log_error("Failed to add veth interface to bridge: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add veth interface to bridge: %m");
return 0;
}
@@ -1915,17 +1777,13 @@ static int parse_interface(struct udev *udev, const char *name) {
int ifi;
ifi = (int) if_nametoindex(name);
- if (ifi <= 0) {
- log_error("Failed to resolve interface %s: %m", name);
- return -errno;
- }
+ if (ifi <= 0)
+ return log_error_errno(errno, "Failed to resolve interface %s: %m", name);
sprintf(ifi_str, "n%i", ifi);
d = udev_device_new_from_device_id(udev, ifi_str);
- if (!d) {
- log_error("Failed to get udev device for interface %s: %m", name);
- return -errno;
- }
+ if (!d)
+ return log_error_errno(errno, "Failed to get udev device for interface %s: %m", name);
if (udev_device_get_is_initialized(d) <= 0) {
log_error("Network interface %s is not initialized yet.", name);
@@ -1948,10 +1806,8 @@ static int move_network_interfaces(pid_t pid) {
return 0;
r = sd_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
if (!udev) {
@@ -1968,22 +1824,16 @@ static int move_network_interfaces(pid_t pid) {
return ifi;
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
- if (r < 0) {
- log_error("Failed to allocate netlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
- if (r < 0) {
- log_error("Failed to append namespace PID to netlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
r = sd_rtnl_call(rtnl, m, 0, NULL);
- if (r < 0) {
- log_error("Failed to move interface %s to namespace: %s", *i, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
}
return 0;
@@ -1992,6 +1842,7 @@ static int move_network_interfaces(pid_t pid) {
static int setup_macvlan(pid_t pid) {
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+ unsigned idx = 0;
char **i;
int r;
@@ -2002,10 +1853,8 @@ static int setup_macvlan(pid_t pid) {
return 0;
r = sd_rtnl_open(&rtnl, 0);
- if (r < 0) {
- log_error("Failed to connect to netlink: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
if (!udev) {
@@ -2016,23 +1865,24 @@ static int setup_macvlan(pid_t pid) {
STRV_FOREACH(i, arg_network_macvlan) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
_cleanup_free_ char *n = NULL;
+ struct ether_addr mac;
int ifi;
ifi = parse_interface(udev, *i);
if (ifi < 0)
return ifi;
+ r = generate_mac(&mac, MACVLAN_HASH_KEY, idx++);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
+
r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
- if (r < 0) {
- log_error("Failed to allocate netlink message: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
r = sd_rtnl_message_append_u32(m, IFLA_LINK, ifi);
- if (r < 0) {
- log_error("Failed to add netlink interface index: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface index: %m");
n = strappend("mv-", *i);
if (!n)
@@ -2041,52 +1891,40 @@ static int setup_macvlan(pid_t pid) {
strshorten(n, IFNAMSIZ-1);
r = sd_rtnl_message_append_string(m, IFLA_IFNAME, n);
- if (r < 0) {
- log_error("Failed to add netlink interface name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
+
+ r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink MAC address: %m");
r = sd_rtnl_message_append_u32(m, IFLA_NET_NS_PID, pid);
- if (r < 0) {
- log_error("Failed to add netlink namespace field: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink namespace field: %m");
r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
- if (r < 0) {
- log_error("Failed to open netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open netlink container: %m");
r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
- if (r < 0) {
- log_error("Failed to open netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to open netlink container: %m");
r = sd_rtnl_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
- if (r < 0) {
- log_error("Failed to append macvlan mode: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to append macvlan mode: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close netlink container: %m");
r = sd_rtnl_message_close_container(m);
- if (r < 0) {
- log_error("Failed to close netlink container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to close netlink container: %m");
r = sd_rtnl_call(rtnl, m, 0, NULL);
- if (r < 0) {
- log_error("Failed to add new macvlan interfaces: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
}
return 0;
@@ -2117,7 +1955,7 @@ static int setup_seccomp(void) {
r = seccomp_add_secondary_archs(seccomp);
if (r < 0) {
- log_error("Failed to add secondary archs to seccomp filter: %s", strerror(-r));
+ log_error_errno(r, "Failed to add secondary archs to seccomp filter: %m");
goto finish;
}
@@ -2126,7 +1964,7 @@ static int setup_seccomp(void) {
if (r == -EFAULT)
continue; /* unknown syscall */
if (r < 0) {
- log_error("Failed to block syscall: %s", strerror(-r));
+ log_error_errno(r, "Failed to block syscall: %m");
goto finish;
}
}
@@ -2149,19 +1987,19 @@ static int setup_seccomp(void) {
SCMP_A0(SCMP_CMP_EQ, AF_NETLINK),
SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT));
if (r < 0) {
- log_error("Failed to add audit seccomp rule: %s", strerror(-r));
+ log_error_errno(r, "Failed to add audit seccomp rule: %m");
goto finish;
}
r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
if (r < 0) {
- log_error("Failed to unset NO_NEW_PRIVS: %s", strerror(-r));
+ log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m");
goto finish;
}
r = seccomp_load(seccomp);
if (r < 0)
- log_error("Failed to install seccomp audit filter: %s", strerror(-r));
+ log_error_errno(r, "Failed to install seccomp audit filter: %m");
finish:
seccomp_release(seccomp);
@@ -2185,15 +2023,11 @@ static int setup_image(char **device_path, int *loop_nr) {
assert(loop_nr);
fd = open(arg_image, O_CLOEXEC|(arg_read_only ? O_RDONLY : O_RDWR)|O_NONBLOCK|O_NOCTTY);
- if (fd < 0) {
- log_error("Failed to open %s: %m", arg_image);
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open %s: %m", arg_image);
- if (fstat(fd, &st) < 0) {
- log_error("Failed to stat %s: %m", arg_image);
- return -errno;
- }
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", arg_image);
if (S_ISBLK(st.st_mode)) {
char *p;
@@ -2213,43 +2047,33 @@ static int setup_image(char **device_path, int *loop_nr) {
}
if (!S_ISREG(st.st_mode)) {
- log_error("%s is not a regular file or block device: %m", arg_image);
+ log_error_errno(errno, "%s is not a regular file or block device: %m", arg_image);
return -EINVAL;
}
control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
- if (control < 0) {
- log_error("Failed to open /dev/loop-control: %m");
- return -errno;
- }
+ if (control < 0)
+ return log_error_errno(errno, "Failed to open /dev/loop-control: %m");
nr = ioctl(control, LOOP_CTL_GET_FREE);
- if (nr < 0) {
- log_error("Failed to allocate loop device: %m");
- return -errno;
- }
+ if (nr < 0)
+ return log_error_errno(errno, "Failed to allocate loop device: %m");
if (asprintf(&loopdev, "/dev/loop%i", nr) < 0)
return log_oom();
loop = open(loopdev, O_CLOEXEC|(arg_read_only ? O_RDONLY : O_RDWR)|O_NONBLOCK|O_NOCTTY);
- if (loop < 0) {
- log_error("Failed to open loop device %s: %m", loopdev);
- return -errno;
- }
+ if (loop < 0)
+ return log_error_errno(errno, "Failed to open loop device %s: %m", loopdev);
- if (ioctl(loop, LOOP_SET_FD, fd) < 0) {
- log_error("Failed to set loopback file descriptor on %s: %m", loopdev);
- return -errno;
- }
+ if (ioctl(loop, LOOP_SET_FD, fd) < 0)
+ return log_error_errno(errno, "Failed to set loopback file descriptor on %s: %m", loopdev);
if (arg_read_only)
info.lo_flags |= LO_FLAGS_READ_ONLY;
- if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0) {
- log_error("Failed to set loopback settings on %s: %m", loopdev);
- return -errno;
- }
+ if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0)
+ return log_error_errno(errno, "Failed to set loopback settings on %s: %m", loopdev);
*device_path = loopdev;
loopdev = NULL;
@@ -2270,7 +2094,14 @@ static int dissect_image(
bool *secondary) {
#ifdef HAVE_BLKID
- int home_nr = -1, root_nr = -1, secondary_root_nr = -1, srv_nr = -1;
+ int home_nr = -1, srv_nr = -1;
+#ifdef GPT_ROOT_NATIVE
+ int root_nr = -1;
+#endif
+#ifdef GPT_ROOT_SECONDARY
+ int secondary_root_nr = -1;
+#endif
+
_cleanup_free_ char *home = NULL, *root = NULL, *secondary_root = NULL, *srv = NULL;
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
@@ -2299,7 +2130,7 @@ static int dissect_image(
if (errno == 0)
return log_oom();
- log_error("Failed to set device on blkid probe: %m");
+ log_error_errno(errno, "Failed to set device on blkid probe: %m");
return -errno;
}
@@ -2315,7 +2146,7 @@ static int dissect_image(
} else if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error("Failed to probe: %m");
+ log_error_errno(errno, "Failed to probe: %m");
return -errno;
}
@@ -2340,10 +2171,8 @@ static int dissect_image(
if (!udev)
return log_oom();
- if (fstat(fd, &st) < 0) {
- log_error("Failed to stat block device: %m");
- return -errno;
- }
+ if (fstat(fd, &st) < 0)
+ return log_error_errno(errno, "Failed to stat block device: %m");
d = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
if (!d)
@@ -2358,10 +2187,8 @@ static int dissect_image(
return log_oom();
r = udev_enumerate_scan_devices(e);
- if (r < 0) {
- log_error("Failed to scan for partition devices of %s: %s", arg_image, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to scan for partition devices of %s: %m", arg_image);
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
@@ -2379,7 +2206,7 @@ static int dissect_image(
if (!errno)
errno = ENOMEM;
- log_error("Failed to get partition device of %s: %m", arg_image);
+ log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image);
return -errno;
}
@@ -2534,7 +2361,7 @@ static int mount_device(const char *what, const char *where, const char *directo
if (!b) {
if (errno == 0)
return log_oom();
- log_error("Failed to allocate prober for %s: %m", what);
+ log_error_errno(errno, "Failed to allocate prober for %s: %m", what);
return -errno;
}
@@ -2549,7 +2376,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("Failed to probe %s: %m", what);
+ log_error_errno(errno, "Failed to probe %s: %m", what);
return -errno;
}
@@ -2566,10 +2393,8 @@ static int mount_device(const char *what, const char *where, const char *directo
return -ENOTSUP;
}
- if (mount(what, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), NULL) < 0) {
- log_error("Failed to mount %s: %m", what);
- return -errno;
- }
+ if (mount(what, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), NULL) < 0)
+ return log_error_errno(errno, "Failed to mount %s: %m", what);
return 0;
#else
@@ -2589,26 +2414,20 @@ static int mount_devices(
if (root_device) {
r = mount_device(root_device, arg_directory, NULL, root_device_rw);
- if (r < 0) {
- log_error("Failed to mount root directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to mount root directory: %m");
}
if (home_device) {
r = mount_device(home_device, arg_directory, "/home", home_device_rw);
- if (r < 0) {
- log_error("Failed to mount home directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to mount home directory: %m");
}
if (srv_device) {
r = mount_device(srv_device, arg_directory, "/srv", srv_device_rw);
- if (r < 0) {
- log_error("Failed to mount server data directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to mount server data directory: %m");
}
return 0;
@@ -2624,19 +2443,19 @@ static void loop_remove(int nr, int *image_fd) {
if (image_fd && *image_fd >= 0) {
r = ioctl(*image_fd, LOOP_CLR_FD);
if (r < 0)
- log_warning("Failed to close loop image: %m");
+ log_warning_errno(errno, "Failed to close loop image: %m");
*image_fd = safe_close(*image_fd);
}
control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (control < 0) {
- log_warning("Failed to open /dev/loop-control: %m");
+ log_warning_errno(errno, "Failed to open /dev/loop-control: %m");
return;
}
r = ioctl(control, LOOP_CTL_REMOVE, nr);
if (r < 0)
- log_warning("Failed to remove loop %d: %m", nr);
+ log_warning_errno(errno, "Failed to remove loop %d: %m", nr);
}
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
@@ -2647,16 +2466,13 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
assert(key);
assert(rpid);
- if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
- log_error("Failed to allocate pipe: %m");
- return -errno;
- }
+ if (pipe2(pipe_fds, O_CLOEXEC) < 0)
+ return log_error_errno(errno, "Failed to allocate pipe: %m");
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork getent child: %m");
- return -errno;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork getent child: %m");
+ else if (pid == 0) {
int nullfd;
char *empty_env = NULL;
@@ -2715,20 +2531,14 @@ static int change_uid_gid(char **_home) {
if (!arg_user || streq(arg_user, "root") || streq(arg_user, "0")) {
/* Reset everything fully to 0, just in case */
- if (setgroups(0, NULL) < 0) {
- log_error("setgroups() failed: %m");
- return -errno;
- }
+ if (setgroups(0, NULL) < 0)
+ return log_error_errno(errno, "setgroups() failed: %m");
- if (setresgid(0, 0, 0) < 0) {
- log_error("setregid() failed: %m");
- return -errno;
- }
+ if (setresgid(0, 0, 0) < 0)
+ return log_error_errno(errno, "setregid() failed: %m");
- if (setresuid(0, 0, 0) < 0) {
- log_error("setreuid() failed: %m");
- return -errno;
- }
+ if (setresuid(0, 0, 0) < 0)
+ return log_error_errno(errno, "setreuid() failed: %m");
*_home = NULL;
return 0;
@@ -2751,13 +2561,13 @@ static int change_uid_gid(char **_home) {
return -ESRCH;
}
- log_error("Failed to read from getent: %m");
+ log_error_errno(errno, "Failed to read from getent: %m");
return -errno;
}
truncate_nl(line);
- wait_for_terminate_and_warn("getent passwd", pid);
+ wait_for_terminate_and_warn("getent passwd", pid, true);
x = strchr(line, ':');
if (!x) {
@@ -2835,13 +2645,13 @@ static int change_uid_gid(char **_home) {
return -ESRCH;
}
- log_error("Failed to read from getent: %m");
+ log_error_errno(errno, "Failed to read from getent: %m");
return -errno;
}
truncate_nl(line);
- wait_for_terminate_and_warn("getent initgroups", pid);
+ wait_for_terminate_and_warn("getent initgroups", pid, true);
/* Skip over the username and subsequent separator whitespace */
x = line;
@@ -2865,35 +2675,25 @@ static int change_uid_gid(char **_home) {
}
r = mkdir_parents(home, 0775);
- if (r < 0) {
- log_error("Failed to make home root directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to make home root directory: %m");
r = mkdir_safe(home, 0755, uid, gid);
- if (r < 0 && r != -EEXIST) {
- log_error("Failed to make home directory: %s", strerror(-r));
- return r;
- }
+ if (r < 0 && r != -EEXIST)
+ return log_error_errno(r, "Failed to make home directory: %m");
fchown(STDIN_FILENO, uid, gid);
fchown(STDOUT_FILENO, uid, gid);
fchown(STDERR_FILENO, uid, gid);
- if (setgroups(n_uids, uids) < 0) {
- log_error("Failed to set auxiliary groups: %m");
- return -errno;
- }
+ if (setgroups(n_uids, uids) < 0)
+ return log_error_errno(errno, "Failed to set auxiliary groups: %m");
- if (setresgid(gid, gid, gid) < 0) {
- log_error("setregid() failed: %m");
- return -errno;
- }
+ if (setresgid(gid, gid, gid) < 0)
+ return log_error_errno(errno, "setregid() failed: %m");
- if (setresuid(uid, uid, uid) < 0) {
- log_error("setreuid() failed: %m");
- return -errno;
- }
+ if (setresuid(uid, uid, uid) < 0)
+ return log_error_errno(errno, "setreuid() failed: %m");
if (_home) {
*_home = home;
@@ -2911,8 +2711,8 @@ static int change_uid_gid(char **_home) {
* container argument.
* > 0 : The program executed in the container terminated with an
* error. The exit code of the program executed in the
- * container is returned. No change is made to the container
- * argument.
+ * container is returned. The container argument has been set
+ * to CONTAINER_TERMINATED.
* 0 : The container is being rebooted, has been shut down or exited
* successfully. The container argument has been set to either
* CONTAINER_TERMINATED or CONTAINER_REBOOTED.
@@ -2921,61 +2721,48 @@ static int change_uid_gid(char **_home) {
* error is indicated by a non-zero value.
*/
static int wait_for_container(pid_t pid, ContainerStatus *container) {
- int r;
siginfo_t status;
+ int r;
r = wait_for_terminate(pid, &status);
- if (r < 0) {
- log_warning("Failed to wait for container: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for container: %m");
switch (status.si_code) {
+
case CLD_EXITED:
- r = status.si_status;
- if (r == 0) {
- if (!arg_quiet)
- log_debug("Container %s exited successfully.",
- arg_machine);
+ if (status.si_status == 0) {
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine);
- *container = CONTAINER_TERMINATED;
- } else {
- log_error("Container %s failed with error code %i.",
- arg_machine, status.si_status);
- }
- break;
+ } else
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s failed with error code %i.", arg_machine, status.si_status);
+
+ *container = CONTAINER_TERMINATED;
+ return status.si_status;
case CLD_KILLED:
if (status.si_status == SIGINT) {
- if (!arg_quiet)
- log_info("Container %s has been shut down.",
- arg_machine);
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine);
*container = CONTAINER_TERMINATED;
- r = 0;
- break;
+ return 0;
+
} else if (status.si_status == SIGHUP) {
- if (!arg_quiet)
- log_info("Container %s is being rebooted.",
- arg_machine);
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine);
*container = CONTAINER_REBOOTED;
- r = 0;
- break;
+ return 0;
}
+
/* CLD_KILLED fallthrough */
case CLD_DUMPED:
- log_error("Container %s terminated by signal %s.",
- arg_machine, signal_to_string(status.si_status));
- r = -1;
- break;
+ log_error("Container %s terminated by signal %s.", arg_machine, signal_to_string(status.si_status));
+ return -EIO;
default:
- log_error("Container %s failed due to unknown reason.",
- arg_machine);
- r = -1;
- break;
+ log_error("Container %s failed due to unknown reason.", arg_machine);
+ return -EIO;
}
return r;
@@ -2983,11 +2770,27 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
static void nop_handler(int sig) {}
+static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ pid_t pid;
+
+ pid = PTR_TO_UINT32(userdata);
+ if (pid > 0) {
+ if (kill(pid, SIGRTMIN+3) >= 0) {
+ log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
+ sd_event_source_set_userdata(s, NULL);
+ return 0;
+ }
+ }
+
+ sd_event_exit(sd_event_source_get_event(s), 0);
+ return 0;
+}
+
int main(int argc, char *argv[]) {
- _cleanup_free_ char *kdbus_domain = NULL, *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL;
+ _cleanup_free_ char *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL;
bool root_device_rw = true, home_device_rw = true, srv_device_rw = true;
- _cleanup_close_ int master = -1, kdbus_fd = -1, image_fd = -1;
+ _cleanup_close_ int master = -1, image_fd = -1;
_cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 };
_cleanup_fdset_free_ FDSet *fds = NULL;
int r = EXIT_FAILURE, k, n_fd_passed, loop_nr = -1;
@@ -3054,7 +2857,7 @@ int main(int argc, char *argv[]) {
if (n_fd_passed > 0) {
k = fdset_new_listen_fds(&fds, false);
if (k < 0) {
- log_error("Failed to collect file descriptors: %s", strerror(-k));
+ log_error_errno(k, "Failed to collect file descriptors: %m");
goto finish;
}
}
@@ -3087,7 +2890,7 @@ int main(int argc, char *argv[]) {
char template[] = "/tmp/nspawn-root-XXXXXX";
if (!mkdtemp(template)) {
- log_error("Failed to create temporary directory: %m");
+ log_error_errno(errno, "Failed to create temporary directory: %m");
r = -errno;
goto finish;
}
@@ -3115,13 +2918,13 @@ int main(int argc, char *argv[]) {
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
if (master < 0) {
- log_error("Failed to acquire pseudo tty: %m");
+ log_error_errno(errno, "Failed to acquire pseudo tty: %m");
goto finish;
}
console = ptsname(master);
if (!console) {
- log_error("Failed to determine tty name: %m");
+ log_error_errno(errno, "Failed to determine tty name: %m");
goto finish;
}
@@ -3130,32 +2933,12 @@ int main(int argc, char *argv[]) {
arg_machine, arg_image ? arg_image : arg_directory);
if (unlockpt(master) < 0) {
- log_error("Failed to unlock tty: %m");
+ log_error_errno(errno, "Failed to unlock tty: %m");
goto finish;
}
- if (access("/dev/kdbus/control", F_OK) >= 0) {
-
- if (arg_share_system) {
- kdbus_domain = strdup("/dev/kdbus");
- if (!kdbus_domain) {
- log_oom();
- goto finish;
- }
- } else {
- const char *ns;
-
- ns = strappenda("machine-", arg_machine);
- kdbus_fd = bus_kernel_create_domain(ns, &kdbus_domain);
- if (r < 0)
- log_debug("Failed to create kdbus domain: %s", strerror(-r));
- else
- log_debug("Successfully created kdbus domain as %s", kdbus_domain);
- }
- }
-
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
- log_error("Failed to create kmsg socket pair: %m");
+ log_error_errno(errno, "Failed to create kmsg socket pair: %m");
goto finish;
}
@@ -3164,11 +2947,12 @@ int main(int argc, char *argv[]) {
"STATUS=Container running.");
assert_se(sigemptyset(&mask) == 0);
- assert_se(sigemptyset(&mask_chld) == 0);
- sigaddset(&mask_chld, SIGCHLD);
sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1);
assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
+ assert_se(sigemptyset(&mask_chld) == 0);
+ assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
+
for (;;) {
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
@@ -3179,7 +2963,7 @@ int main(int argc, char *argv[]) {
r = barrier_create(&barrier);
if (r < 0) {
- log_error("Cannot initialize IPC barrier: %s", strerror(-r));
+ log_error_errno(r, "Cannot initialize IPC barrier: %m");
goto finish;
}
@@ -3188,13 +2972,13 @@ int main(int argc, char *argv[]) {
* give it a chance to call wait() and terminate. */
r = sigprocmask(SIG_UNBLOCK, &mask_chld, NULL);
if (r < 0) {
- log_error("Failed to change the signal mask: %m");
+ log_error_errno(errno, "Failed to change the signal mask: %m");
goto finish;
}
r = sigaction(SIGCHLD, &sa, NULL);
if (r < 0) {
- log_error("Failed to install SIGCHLD handler: %m");
+ log_error_errno(errno, "Failed to install SIGCHLD handler: %m");
goto finish;
}
@@ -3203,9 +2987,9 @@ int main(int argc, char *argv[]) {
(arg_private_network ? CLONE_NEWNET : 0), NULL);
if (pid < 0) {
if (errno == EINVAL)
- log_error("clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m");
+ log_error_errno(errno, "clone() failed, do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in): %m");
else
- log_error("clone() failed: %m");
+ log_error_errno(errno, "clone() failed: %m");
r = pid;
goto finish;
@@ -3253,18 +3037,18 @@ int main(int argc, char *argv[]) {
k = -EINVAL;
}
- log_error("Failed to open console: %s", strerror(-k));
+ log_error_errno(k, "Failed to open console: %m");
_exit(EXIT_FAILURE);
}
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
- log_error("Failed to duplicate console: %m");
+ log_error_errno(errno, "Failed to duplicate console: %m");
_exit(EXIT_FAILURE);
}
if (setsid() < 0) {
- log_error("setsid() failed: %m");
+ log_error_errno(errno, "setsid() failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3272,7 +3056,7 @@ int main(int argc, char *argv[]) {
_exit(EXIT_FAILURE);
if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0) {
- log_error("PR_SET_PDEATHSIG failed: %m");
+ log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3280,7 +3064,7 @@ int main(int argc, char *argv[]) {
* receive mounts from the real root, but don't
* propagate mounts to the real root. */
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
- log_error("MS_SLAVE|MS_REC failed: %m");
+ log_error_errno(errno, "MS_SLAVE|MS_REC failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3292,7 +3076,7 @@ int main(int argc, char *argv[]) {
/* Turn directory into bind mount */
if (mount(arg_directory, arg_directory, "bind", MS_BIND|MS_REC, NULL) < 0) {
- log_error("Failed to make bind mount: %m");
+ log_error_errno(errno, "Failed to make bind mount: %m");
_exit(EXIT_FAILURE);
}
@@ -3310,7 +3094,7 @@ int main(int argc, char *argv[]) {
if (arg_read_only) {
k = bind_remount_recursive(arg_directory, true);
if (k < 0) {
- log_error("Failed to make tree read-only: %s", strerror(-k));
+ log_error_errno(k, "Failed to make tree read-only: %m");
_exit(EXIT_FAILURE);
}
}
@@ -3358,31 +3142,28 @@ int main(int argc, char *argv[]) {
if (mount_tmpfs(arg_directory) < 0)
_exit(EXIT_FAILURE);
- if (setup_kdbus(arg_directory, kdbus_domain) < 0)
- _exit(EXIT_FAILURE);
-
/* Tell the parent that we are ready, and that
* it can cgroupify us to that we lack access
* to certain devices and resources. */
- barrier_place(&barrier);
+ (void)barrier_place(&barrier);
if (chdir(arg_directory) < 0) {
- log_error("chdir(%s) failed: %m", arg_directory);
+ log_error_errno(errno, "chdir(%s) failed: %m", arg_directory);
_exit(EXIT_FAILURE);
}
if (mount(arg_directory, "/", NULL, MS_MOVE, NULL) < 0) {
- log_error("mount(MS_MOVE) failed: %m");
+ log_error_errno(errno, "mount(MS_MOVE) failed: %m");
_exit(EXIT_FAILURE);
}
if (chroot(".") < 0) {
- log_error("chroot() failed: %m");
+ log_error_errno(errno, "chroot() failed: %m");
_exit(EXIT_FAILURE);
}
if (chdir("/") < 0) {
- log_error("chdir() failed: %m");
+ log_error_errno(errno, "chdir() failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3392,7 +3173,7 @@ int main(int argc, char *argv[]) {
loopback_setup();
if (drop_capabilities() < 0) {
- log_error("drop_capabilities() failed: %m");
+ log_error_errno(errno, "drop_capabilities() failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3434,12 +3215,12 @@ int main(int argc, char *argv[]) {
if (arg_personality != 0xffffffffLU) {
if (personality(arg_personality) < 0) {
- log_error("personality() failed: %m");
+ log_error_errno(errno, "personality() failed: %m");
_exit(EXIT_FAILURE);
}
} else if (secondary) {
if (personality(PER_LINUX32) < 0) {
- log_error("personality() failed: %m");
+ log_error_errno(errno, "personality() failed: %m");
_exit(EXIT_FAILURE);
}
}
@@ -3447,7 +3228,7 @@ int main(int argc, char *argv[]) {
#ifdef HAVE_SELINUX
if (arg_selinux_context)
if (setexeccon((security_context_t) arg_selinux_context) < 0) {
- log_error("setexeccon(\"%s\") failed: %m", arg_selinux_context);
+ log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
_exit(EXIT_FAILURE);
}
#endif
@@ -3495,7 +3276,7 @@ int main(int argc, char *argv[]) {
execle("/bin/sh", "-sh", NULL, env_use);
}
- log_error("execv() failed: %m");
+ log_error_errno(errno, "execv() failed: %m");
_exit(EXIT_FAILURE);
}
@@ -3505,6 +3286,8 @@ int main(int argc, char *argv[]) {
/* wait for child-setup to be done */
if (barrier_place_and_sync(&barrier)) {
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
int ifi = 0;
r = move_network_interfaces(pid);
@@ -3541,14 +3324,39 @@ int main(int argc, char *argv[]) {
/* Notify the child that the parent is ready with all
* its setup, and that the child can now hand over
* control to the code to run inside the container. */
- barrier_place(&barrier);
+ (void)barrier_place(&barrier);
- k = process_pty(master, &mask, arg_boot ? pid : 0, SIGRTMIN+3);
- if (k < 0) {
- r = EXIT_FAILURE;
- break;
+ r = sd_event_new(&event);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get default event source: %m");
+ goto finish;
}
+ if (arg_boot) {
+ /* Try to kill the init system on SIGINT or SIGTERM */
+ sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ } else {
+ /* Immediately exit */
+ sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ }
+
+ /* simply exit on sigchld */
+ sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL);
+
+ r = pty_forward_new(event, master, &forward);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create PTY forwarder: %m");
+ goto finish;
+ }
+
+ r = sd_event_loop(event);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run event loop: %m");
+
+ forward = pty_forward_free(forward);
+
if (!arg_quiet)
putc('\n', stdout);
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 86e7be2aa1..aa92cc96e4 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -77,6 +77,18 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK);
+
+ } else if (streq(name, "gateway")) {
+
+ n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
+ if (n_addresses <= 0) {
+ *errnop = ENOENT;
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ canonical = "gateway";
+
} else {
hn = gethostname_malloc();
if (!hn) {
@@ -92,7 +104,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
return NSS_STATUS_NOTFOUND;
}
- n_addresses = local_addresses(NULL, 0, &addresses);
+ n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
if (n_addresses < 0)
n_addresses = 0;
@@ -314,7 +326,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
_cleanup_free_ struct local_address *addresses = NULL;
const char *canonical, *additional = NULL;
_cleanup_free_ char *hn = NULL;
- uint32_t local_address_ipv4;
+ uint32_t local_address_ipv4 = 0;
int n_addresses = 0;
assert(name);
@@ -335,6 +347,18 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
if (is_localhost(name)) {
canonical = "localhost";
local_address_ipv4 = htonl(INADDR_LOOPBACK);
+
+ } else if (streq(name, "gateway")) {
+
+ n_addresses = local_gateways(NULL, 0, af, &addresses);
+ if (n_addresses <= 0) {
+ *errnop = ENOENT;
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
+ }
+
+ canonical = "gateway";
+
} else {
hn = gethostname_malloc();
if (!hn) {
@@ -349,7 +373,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
return NSS_STATUS_NOTFOUND;
}
- n_addresses = local_addresses(NULL, 0, &addresses);
+ n_addresses = local_addresses(NULL, 0, af, &addresses);
if (n_addresses < 0)
n_addresses = 0;
@@ -425,16 +449,42 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
}
- n_addresses = local_addresses(NULL, 0, &addresses);
- if (n_addresses < 0)
- n_addresses = 0;
+ n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
+ if (n_addresses > 0) {
+ for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+ if (af != a->family)
+ continue;
- for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
- if (af != a->family)
- continue;
+ if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
- if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
- goto found;
+ hn = gethostname_malloc();
+ if (!hn) {
+ *errnop = ENOMEM;
+ *h_errnop = NO_RECOVERY;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ canonical = hn;
+ goto found;
+ }
+ }
+ }
+
+ free(addresses);
+ addresses = NULL;
+
+ n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
+ if (n_addresses > 0) {
+ for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+ if (af != a->family)
+ continue;
+
+ if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
+
+ canonical = "gateway";
+ goto found;
+ }
+ }
}
*errnop = ENOENT;
@@ -443,16 +493,6 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
return NSS_STATUS_NOTFOUND;
found:
- if (!canonical) {
- hn = gethostname_malloc();
- if (!hn) {
- *errnop = ENOMEM;
- *h_errnop = NO_RECOVERY;
- return NSS_STATUS_TRYAGAIN;
- }
-
- canonical = hn;
- }
return fill_in_hostent(
canonical, additional,
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index 6a029a331b..3f32ed0650 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -33,7 +33,7 @@
#include "sd-bus.h"
#include "bus-util.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "macro.h"
#include "nss-util.h"
#include "util.h"
diff --git a/src/path/path.c b/src/path/path.c
index 37f2571fab..2f0148f074 100644
--- a/src/path/path.c
+++ b/src/path/path.c
@@ -88,7 +88,7 @@ static int list_homes(void) {
if (q == -ENXIO)
continue;
if (q < 0) {
- log_error("Failed to query %s: %s", path_table[i], strerror(-r));
+ log_error_errno(r, "Failed to query %s: %m", path_table[i]);
r = q;
continue;
}
@@ -108,10 +108,8 @@ static int print_home(const char *n) {
_cleanup_free_ char *p = NULL;
r = sd_path_home(i, arg_suffix, &p);
- if (r < 0) {
- log_error("Failed to query %s: %s", n, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query %s: %m", n);
printf("%s\n", p);
return 0;
diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c
index ed95b48c63..9ae3abd990 100644
--- a/src/quotacheck/quotacheck.c
+++ b/src/quotacheck/quotacheck.c
@@ -74,6 +74,7 @@ int main(int argc, char *argv[]) {
};
pid_t pid;
+ int r;
if (argc > 1) {
log_error("This program takes no arguments.");
@@ -86,7 +87,10 @@ int main(int argc, char *argv[]) {
umask(0022);
- parse_proc_cmdline(parse_proc_cmdline_item);
+ r = parse_proc_cmdline(parse_proc_cmdline_item);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
+
test_files();
if (!arg_force) {
@@ -99,7 +103,7 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0) {
- log_error("fork(): %m");
+ log_error_errno(errno, "fork(): %m");
return EXIT_FAILURE;
} else if (pid == 0) {
/* Child */
@@ -107,5 +111,7 @@ int main(int argc, char *argv[]) {
_exit(1); /* Operational error */
}
- return wait_for_terminate_and_warn("quotacheck", pid) >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ r = wait_for_terminate_and_warn("quotacheck", pid, true);
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index af79ecf2a9..06c1239601 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -72,7 +72,7 @@ int main(int argc, char *argv[]) {
r = mkdir_parents_label(RANDOM_SEED, 0755);
if (r < 0) {
- log_error("Failed to create directory " RANDOM_SEED_DIR ": %s", strerror(-r));
+ log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
goto finish;
}
@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
if (seed_fd < 0) {
seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (seed_fd < 0) {
- log_error("Failed to open " RANDOM_SEED ": %m");
+ log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
r = -errno;
goto finish;
}
@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
if (random_fd < 0) {
random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600);
if (random_fd < 0) {
- log_error("Failed to open /dev/urandom: %m");
+ log_error_errno(errno, "Failed to open /dev/urandom: %m");
r = -errno;
goto finish;
}
@@ -106,33 +106,30 @@ int main(int argc, char *argv[]) {
if (k <= 0) {
if (r != 0)
- log_error("Failed to read seed from " RANDOM_SEED ": %m");
+ log_error_errno(errno, "Failed to read seed from " RANDOM_SEED ": %m");
r = k == 0 ? -EIO : (int) k;
} else {
lseek(seed_fd, 0, SEEK_SET);
- k = loop_write(random_fd, buf, (size_t) k, false);
- if (k <= 0) {
- log_error("Failed to write seed to /dev/urandom: %s", r < 0 ? strerror(-r) : "short write");
-
- r = k == 0 ? -EIO : (int) k;
- }
+ r = loop_write(random_fd, buf, (size_t) k, false);
+ if (r < 0)
+ log_error_errno(r, "Failed to write seed to /dev/urandom: %m");
}
} else if (streq(argv[1], "save")) {
seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0) {
- log_error("Failed to open " RANDOM_SEED ": %m");
+ log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
r = -errno;
goto finish;
}
random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (random_fd < 0) {
- log_error("Failed to open /dev/urandom: %m");
+ log_error_errno(errno, "Failed to open /dev/urandom: %m");
r = -errno;
goto finish;
}
@@ -155,10 +152,8 @@ int main(int argc, char *argv[]) {
r = k == 0 ? -EIO : (int) k;
} else {
r = loop_write(seed_fd, buf, (size_t) k, false);
- if (r <= 0) {
- log_error("Failed to write new random seed file: %s", r < 0 ? strerror(-r) : "short write");
- r = r == 0 ? -EIO : r;
- }
+ if (r < 0)
+ log_error_errno(r, "Failed to write new random seed file: %m");
}
finish:
diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c
index 01ff4702a7..d4e6ba4bf9 100644
--- a/src/rc-local-generator/rc-local-generator.c
+++ b/src/rc-local-generator/rc-local-generator.c
@@ -60,7 +60,7 @@ static int add_symlink(const char *service, const char *where) {
if (errno == EEXIST)
return 0;
- log_error("Failed to create symlink %s: %m", to);
+ log_error_errno(errno, "Failed to create symlink %s: %m", to);
return -errno;
}
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
index cd7cfe7a47..57b47021e4 100644
--- a/src/remount-fs/remount-fs.c
+++ b/src/remount-fs/remount-fs.c
@@ -60,7 +60,7 @@ int main(int argc, char *argv[]) {
if (errno == ENOENT)
return EXIT_SUCCESS;
- log_error("Failed to open /etc/fstab: %m");
+ log_error_errno(errno, "Failed to open /etc/fstab: %m");
return EXIT_FAILURE;
}
@@ -87,7 +87,7 @@ int main(int argc, char *argv[]) {
pid = fork();
if (pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
ret = EXIT_FAILURE;
continue;
}
@@ -104,7 +104,7 @@ int main(int argc, char *argv[]) {
execv("/bin/mount", (char **) arguments);
- log_error("Failed to execute /bin/mount: %m");
+ log_error_errno(errno, "Failed to execute /bin/mount: %m");
_exit(EXIT_FAILURE);
}
@@ -120,7 +120,7 @@ int main(int argc, char *argv[]) {
k = hashmap_put(pids, UINT_TO_PTR(pid), s);
if (k < 0) {
- log_error("Failed to add PID to set: %s", strerror(-k));
+ log_error_errno(k, "Failed to add PID to set: %m");
ret = EXIT_FAILURE;
continue;
}
@@ -135,7 +135,7 @@ int main(int argc, char *argv[]) {
if (errno == EINTR)
continue;
- log_error("waitid() failed: %m");
+ log_error_errno(errno, "waitid() failed: %m");
ret = EXIT_FAILURE;
break;
}
diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c
index 73c2d1bbdf..54683b6f4a 100644
--- a/src/reply-password/reply-password.c
+++ b/src/reply-password/reply-password.c
@@ -51,10 +51,8 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
- log_error("Failed to send: %m");
- return -errno;
- }
+ if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0)
+ return log_error_errno(errno, "Failed to send: %m");
return 0;
}
@@ -77,7 +75,7 @@ int main(int argc, char *argv[]) {
packet[0] = '+';
if (!fgets(packet+1, sizeof(packet)-1, stdin)) {
- log_error("Failed to read password: %m");
+ log_error_errno(errno, "Failed to read password: %m");
goto finish;
}
@@ -93,7 +91,7 @@ int main(int argc, char *argv[]) {
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
- log_error("socket() failed: %m");
+ log_error_errno(errno, "socket() failed: %m");
goto finish;
}
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 49049d2a25..43ecf81ef6 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -26,7 +26,7 @@
#include "sd-bus.h"
#include "bus-util.h"
#include "bus-error.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "in-addr-util.h"
#include "af-list.h"
#include "build.h"
@@ -155,7 +155,7 @@ static int resolve_host(sd_bus *bus, const char *name) {
r = in_addr_to_string(family, a, &pretty);
if (r < 0) {
- log_error("%s: failed to print address: %s", name, strerror(-r));
+ log_error_errno(r, "%s: failed to print address: %m", name);
continue;
}
@@ -513,10 +513,8 @@ static int parse_argv(int argc, char *argv[]) {
case 'i':
arg_ifindex = if_nametoindex(optarg);
- if (arg_ifindex <= 0) {
- log_error("Unknown interfaces %s: %m", optarg);
- return -errno;
- }
+ if (arg_ifindex <= 0)
+ return log_error_errno(errno, "Unknown interfaces %s: %m", optarg);
break;
case 't':
@@ -614,7 +612,7 @@ int main(int argc, char **argv) {
r = sd_bus_open_system(&bus);
if (r < 0) {
- log_error("sd_bus_open_system: %s", strerror(-r));
+ log_error_errno(r, "sd_bus_open_system: %m");
goto finish;
}
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 0029023bcc..8161b5321f 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-errors.h"
+#include "bus-common-errors.h"
#include "bus-util.h"
#include "resolved-dns-domain.h"
@@ -251,7 +251,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
finish:
if (r < 0) {
- log_error("Failed to send hostname reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send hostname reply: %m");
sd_bus_reply_method_errno(q->request, -r, NULL);
}
@@ -419,7 +419,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
finish:
if (r < 0) {
- log_error("Failed to send address reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send address reply: %m");
sd_bus_reply_method_errno(q->request, -r, NULL);
}
@@ -591,7 +591,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
finish:
if (r < 0) {
- log_error("Failed to send record reply: %s", strerror(-r));
+ log_error_errno(r, "Failed to send record reply: %m");
sd_bus_reply_method_errno(q->request, -r, NULL);
}
@@ -690,7 +690,7 @@ static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *u
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
- log_debug("Failed to parse PrepareForSleep signal: %s", strerror(-r));
+ log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
return 0;
}
@@ -717,34 +717,26 @@ int manager_connect_bus(Manager *m) {
* boot. Let's try in 5s again. As soon as we have
* kdbus we can stop doing this... */
- log_debug("Failed to connect to bus, trying again in 5s: %s", strerror(-r));
+ log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
- if (r < 0) {
- log_error("Failed to install bus reconnect time event: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to install bus reconnect time event: %m");
return 0;
}
r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/resolve1", "org.freedesktop.resolve1.Manager", resolve_vtable, m);
- if (r < 0) {
- log_error("Failed to register object: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register object: %m");
r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(m->bus, m->event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
"type='signal',"
@@ -755,7 +747,7 @@ int manager_connect_bus(Manager *m) {
match_prepare_for_sleep,
m);
if (r < 0)
- log_error("Failed to add match for PrepareForSleep: %s", strerror(-r));
+ log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
return 0;
}
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 63e87f8df5..7af63b0a82 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -120,14 +120,12 @@ int config_parse_support(
void *data,
void *userdata) {
- Manager *m = userdata;
Support support, *v = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(m);
support = support_from_string(rvalue);
if (support < 0) {
@@ -147,8 +145,9 @@ int config_parse_support(
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse(NULL, "/etc/systemd/resolved.conf", NULL,
- "Resolve\0",
- config_item_perf_lookup, resolved_gperf_lookup,
- false, false, true, m);
+ return config_parse_many("/etc/systemd/resolved.conf",
+ CONF_DIRS_NULSTR("systemd/resolved.conf"),
+ "Resolve\0",
+ config_item_perf_lookup, resolved_gperf_lookup,
+ false, m);
}
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 7375f77481..cf5b6189c5 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -22,6 +22,7 @@
#include "utf8.h"
#include "util.h"
#include "strv.h"
+#include "unaligned.h"
#include "resolved-dns-domain.h"
#include "resolved-dns-packet.h"
@@ -311,8 +312,7 @@ int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
if (r < 0)
return r;
- ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
- ((uint8_t*) d)[1] = (uint8_t) v;
+ unaligned_write_be16(d, v);
return 0;
}
@@ -327,10 +327,7 @@ int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
if (r < 0)
return r;
- ((uint8_t*) d)[0] = (uint8_t) (v >> 24);
- ((uint8_t*) d)[1] = (uint8_t) (v >> 16);
- ((uint8_t*) d)[2] = (uint8_t) (v >> 8);
- ((uint8_t*) d)[3] = (uint8_t) v;
+ unaligned_write_be32(d, v);
return 0;
}
@@ -550,10 +547,19 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
case DNS_TYPE_TXT: {
char **s;
- STRV_FOREACH(s, rr->txt.strings) {
- r = dns_packet_append_string(p, *s, NULL);
+ if (strv_isempty(rr->txt.strings)) {
+ /* RFC 6763, section 6.1 suggests to generate
+ * single empty string for an empty array. */
+
+ r = dns_packet_append_string(p, "", NULL);
if (r < 0)
goto fail;
+ } else {
+ STRV_FOREACH(s, rr->txt.strings) {
+ r = dns_packet_append_string(p, *s, NULL);
+ if (r < 0)
+ goto fail;
+ }
}
r = 0;
@@ -793,8 +799,8 @@ int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
if (r < 0)
return r;
- *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
- ((uint16_t) ((uint8_t*) d)[1]);
+ *ret = unaligned_read_be16(d);
+
return 0;
}
@@ -808,10 +814,7 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
if (r < 0)
return r;
- *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
- (((uint32_t) ((uint8_t*) d)[1]) << 16) |
- (((uint32_t) ((uint8_t*) d)[2]) << 8) |
- ((uint32_t) ((uint8_t*) d)[3]);
+ *ret = unaligned_read_be32(d);
return 0;
}
@@ -866,7 +869,7 @@ fail:
int dns_packet_read_name(DnsPacket *p, char **_ret,
bool allow_compression, size_t *start) {
- size_t saved_rindex, after_rindex = 0;
+ size_t saved_rindex, after_rindex = 0, jump_barrier;
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
@@ -876,6 +879,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret,
assert(_ret);
saved_rindex = p->rindex;
+ jump_barrier = p->rindex;
for (;;) {
uint8_t c, d;
@@ -922,7 +926,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret,
goto fail;
ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
- if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
+ if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
r = -EBADMSG;
goto fail;
}
@@ -930,9 +934,13 @@ int dns_packet_read_name(DnsPacket *p, char **_ret,
if (after_rindex == 0)
after_rindex = p->rindex;
+ /* Jumps are limited to a "prior occurence" (RFC-1035 4.1.4) */
+ jump_barrier = ptr;
p->rindex = ptr;
- } else
+ } else {
+ r = -EBADMSG;
goto fail;
+ }
}
if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
@@ -1112,22 +1120,31 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
break;
case DNS_TYPE_SPF: /* exactly the same as TXT */
- case DNS_TYPE_TXT: {
- char *s;
+ case DNS_TYPE_TXT:
+ if (rdlength <= 0) {
+ /* RFC 6763, section 6.1 suggests to treat
+ * empty TXT RRs as equivalent to a TXT record
+ * with a single empty string. */
- while (p->rindex < offset + rdlength) {
- r = dns_packet_read_string(p, &s, NULL);
+ r = strv_extend(&rr->txt.strings, "");
if (r < 0)
goto fail;
+ } else {
+ while (p->rindex < offset + rdlength) {
+ char *s;
- r = strv_consume(&rr->txt.strings, s);
- if (r < 0)
- goto fail;
+ r = dns_packet_read_string(p, &s, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = strv_consume(&rr->txt.strings, s);
+ if (r < 0)
+ goto fail;
+ }
}
r = 0;
break;
- }
case DNS_TYPE_A:
r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index fd5ecf413d..78d9e4a412 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -370,14 +370,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
strcaseeq(a->hinfo.os, b->hinfo.os);
case DNS_TYPE_SPF: /* exactly the same as TXT */
- case DNS_TYPE_TXT: {
- int i;
-
- for (i = 0; a->txt.strings[i] || b->txt.strings[i]; i++)
- if (!streq_ptr(a->txt.strings[i], b->txt.strings[i]))
- return false;
- return true;
- }
+ case DNS_TYPE_TXT:
+ return strv_equal(a->txt.strings, b->txt.strings);
case DNS_TYPE_A:
return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 1664b1328e..a43359f8c5 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -334,7 +334,8 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
if (s->protocol == DNS_PROTOCOL_LLMNR) {
if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
dns_name_endswith(domain, "ip6.arpa") > 0 ||
- dns_name_single_label(domain) > 0)
+ (dns_name_single_label(domain) > 0 &&
+ dns_name_equal(domain, "gateway") <= 0)) /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
@@ -386,7 +387,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
* one. This is necessary on some devices, such as
* veth. */
if (b)
- setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
+ (void)setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn));
if (setsockopt(fd, IPPROTO_IP, b ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreqn, sizeof(mreqn)) < 0)
return -errno;
@@ -402,7 +403,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {
return fd;
if (b)
- setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
+ (void)setsockopt(fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
if (setsockopt(fd, IPPROTO_IPV6, b ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
@@ -539,7 +540,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
r = dns_packet_extract(p);
if (r < 0) {
- log_debug("Failed to extract resources from incoming packet: %s", strerror(-r));
+ log_debug_errno(r, "Failed to extract resources from incoming packet: %m");
return;
}
@@ -551,7 +552,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative);
if (r < 0) {
- log_debug("Failed to lookup key: %s", strerror(-r));
+ log_debug_errno(r, "Failed to lookup key: %m");
return;
}
if (r == 0)
@@ -562,7 +563,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, p->question, answer, soa, tentative, &reply);
if (r < 0) {
- log_debug("Failed to build reply packet: %s", strerror(-r));
+ log_debug_errno(r, "Failed to build reply packet: %m");
return;
}
@@ -581,7 +582,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
return;
}
if (fd < 0) {
- log_debug("Failed to get reply socket: %s", strerror(-fd));
+ log_debug_errno(fd, "Failed to get reply socket: %m");
return;
}
@@ -594,7 +595,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
}
if (r < 0) {
- log_debug("Failed to send reply packet: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send reply packet: %m");
return;
}
}
@@ -688,13 +689,13 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
r = dns_scope_make_conflict_packet(scope, rr, &p);
if (r < 0) {
- log_error("Failed to make conflict packet: %s", strerror(-r));
+ log_error_errno(r, "Failed to make conflict packet: %m");
return 0;
}
r = dns_scope_emit(scope, p);
if (r < 0)
- log_debug("Failed to send conflict packet: %s", strerror(-r));
+ log_debug_errno(r, "Failed to send conflict packet: %m");
}
return 0;
@@ -721,10 +722,8 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
r = ordered_hashmap_put(scope->conflict_queue, rr->key, rr);
if (r == -EEXIST || r == 0)
return 0;
- if (r < 0) {
- log_debug("Failed to queue conflicting RR: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to queue conflicting RR: %m");
dns_resource_record_ref(rr);
@@ -740,10 +739,8 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
now(clock_boottime_or_monotonic()) + jitter,
LLMNR_JITTER_INTERVAL_USEC,
on_conflict_dispatch, scope);
- if (r < 0) {
- log_debug("Failed to add conflict dispatch event: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add conflict dispatch event: %m");
return 0;
}
@@ -772,7 +769,7 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
r = dns_packet_extract(p);
if (r < 0) {
- log_debug("Failed to extract packet: %s", strerror(-r));
+ log_debug_errno(r, "Failed to extract packet: %m");
return;
}
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 3690679ec6..4c0b557bad 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -172,11 +172,11 @@ static int dns_stream_identify(DnsStream *s) {
if (s->local.sa.sa_family == AF_INET) {
r = setsockopt(s->fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex));
if (r < 0)
- log_debug("Failed to invoke IP_UNICAST_IF: %m");
+ log_debug_errno(errno, "Failed to invoke IP_UNICAST_IF: %m");
} else if (s->local.sa.sa_family == AF_INET6) {
r = setsockopt(s->fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex, sizeof(ifindex));
if (r < 0)
- log_debug("Failed to invoke IPV6_UNICAST_IF: %m");
+ log_debug_errno(errno, "Failed to invoke IPV6_UNICAST_IF: %m");
}
}
diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c
index 8098ff5e70..a4c9b7d7af 100644
--- a/src/resolve/resolved-dns-zone.c
+++ b/src/resolve/resolved-dns-zone.c
@@ -570,7 +570,7 @@ static int dns_zone_item_verify(DnsZoneItem *i) {
i->state = DNS_ZONE_ITEM_VERIFYING;
r = dns_zone_item_probe_start(i);
if (r < 0) {
- log_error("Failed to start probing for verifying RR: %s", strerror(-r));
+ log_error_errno(r, "Failed to start probing for verifying RR: %m");
i->state = DNS_ZONE_ITEM_ESTABLISHED;
return r;
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index 4def672214..f94e4bb6f0 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -88,7 +88,7 @@ static void link_allocate_scopes(Link *l) {
if (!l->unicast_scope) {
r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
if (r < 0)
- log_warning("Failed to allocate DNS scope: %s", strerror(-r));
+ log_warning_errno(r, "Failed to allocate DNS scope: %m");
}
} else
l->unicast_scope = dns_scope_free(l->unicast_scope);
@@ -99,7 +99,7 @@ static void link_allocate_scopes(Link *l) {
if (!l->llmnr_ipv4_scope) {
r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
if (r < 0)
- log_warning("Failed to allocate LLMNR IPv4 scope: %s", strerror(-r));
+ log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
}
} else
l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
@@ -111,7 +111,7 @@ static void link_allocate_scopes(Link *l) {
if (!l->llmnr_ipv6_scope) {
r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
if (r < 0)
- log_warning("Failed to allocate LLMNR IPv6 scope: %s", strerror(-r));
+ log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
}
} else
l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
@@ -439,11 +439,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
if (r < 0)
- log_warning("Failed to add A record to LLMNR zone: %s", strerror(-r));
+ log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
if (r < 0)
- log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
+ log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
} else {
if (a->llmnr_address_rr) {
if (a->link->llmnr_ipv4_scope)
@@ -496,11 +496,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
if (r < 0)
- log_warning("Failed to add AAAA record to LLMNR zone: %s", strerror(-r));
+ log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
if (r < 0)
- log_warning("Failed to add IPv6 PTR record to LLMNR zone: %s", strerror(-r));
+ log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
} else {
if (a->llmnr_address_rr) {
if (a->link->llmnr_ipv6_scope)
@@ -519,7 +519,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
return;
fail:
- log_debug("Failed to update address RRs: %s", strerror(-r));
+ log_debug_errno(r, "Failed to update address RRs: %m");
}
int link_address_update_rtnl(LinkAddress *a, sd_rtnl_message *m) {
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index c4a5b08773..0594479787 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -100,7 +100,7 @@ static int manager_process_link(sd_rtnl *rtnl, sd_rtnl_message *mm, void *userda
return 0;
fail:
- log_warning("Failed to process RTNL link message: %s", strerror(-r));
+ log_warning_errno(r, "Failed to process RTNL link message: %m");
return 0;
}
@@ -185,7 +185,7 @@ static int manager_process_address(sd_rtnl *rtnl, sd_rtnl_message *mm, void *use
return 0;
fail:
- log_warning("Failed to process RTNL address message: %s", strerror(-r));
+ log_warning_errno(r, "Failed to process RTNL address message: %m");
return 0;
}
@@ -278,12 +278,12 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
HASHMAP_FOREACH(l, m->links, i) {
r = link_update_monitor(l);
if (r < 0)
- log_warning("Failed to update monitor information for %i: %s", l->ifindex, strerror(-r));
+ log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
}
r = manager_write_resolv_conf(m);
if (r < 0)
- log_warning("Could not update resolv.conf: %s", strerror(-r));
+ log_warning_errno(r, "Could not update resolv.conf: %m");
return 0;
}
@@ -370,7 +370,7 @@ static int manager_watch_hostname(Manager *m) {
m->hostname_fd = open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC|O_NDELAY|O_NOCTTY);
if (m->hostname_fd < 0) {
- log_warning("Failed to watch hostname: %m");
+ log_warning_errno(errno, "Failed to watch hostname: %m");
return 0;
}
@@ -379,10 +379,8 @@ static int manager_watch_hostname(Manager *m) {
if (r == -EPERM)
/* kernels prior to 3.2 don't support polling this file. Ignore the failure. */
m->hostname_fd = safe_close(m->hostname_fd);
- else {
- log_error("Failed to add hostname event source: %s", strerror(-r));
- return r;
- }
+ else
+ return log_error_errno(r, "Failed to add hostname event source: %m");
}
r = determine_hostname(&m->hostname);
@@ -593,7 +591,7 @@ int manager_read_resolv_conf(Manager *m) {
r = stat("/etc/resolv.conf", &st);
if (r < 0) {
if (errno != ENOENT)
- log_warning("Failed to open /etc/resolv.conf: %m");
+ log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
r = -errno;
goto clear;
}
@@ -616,13 +614,13 @@ int manager_read_resolv_conf(Manager *m) {
f = fopen("/etc/resolv.conf", "re");
if (!f) {
if (errno != ENOENT)
- log_warning("Failed to open /etc/resolv.conf: %m");
+ log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m");
r = -errno;
goto clear;
}
if (fstat(fileno(f), &st) < 0) {
- log_error("Failed to stat open file: %m");
+ log_error_errno(errno, "Failed to stat open file: %m");
r = -errno;
goto clear;
}
@@ -688,7 +686,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
r = in_addr_to_string(s->family, &s->address, &t);
if (r < 0) {
- log_warning("Invalid DNS address. Ignoring: %s", strerror(-r));
+ log_warning_errno(r, "Invalid DNS address. Ignoring: %m");
return;
}
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 7d258c9470..c0ab947c0e 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -49,20 +49,20 @@ int main(int argc, char *argv[]) {
r = mac_selinux_init(NULL);
if (r < 0) {
- log_error("SELinux setup failed: %s", strerror(-r));
+ log_error_errno(r, "SELinux setup failed: %m");
goto finish;
}
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
- log_error("Cannot resolve user name %s: %s", user, strerror(-r));
+ log_error_errno(r, "Cannot resolve user name %s: %m", user);
goto finish;
}
/* Always create the directory where resolv.conf will live */
r = mkdir_safe_label("/run/systemd/resolve", 0755, uid, gid);
if (r < 0) {
- log_error("Could not create runtime directory: %s", strerror(-r));
+ log_error_errno(r, "Could not create runtime directory: %m");
goto finish;
}
@@ -74,17 +74,17 @@ int main(int argc, char *argv[]) {
r = manager_new(&m);
if (r < 0) {
- log_error("Could not create manager: %s", strerror(-r));
+ log_error_errno(r, "Could not create manager: %m");
goto finish;
}
r = manager_parse_config_file(m);
if (r < 0)
- log_warning("Failed to parse configuration file: %s", strerror(-r));
+ log_warning_errno(r, "Failed to parse configuration file: %m");
r = manager_start(m);
if (r < 0) {
- log_error("Failed to start manager: %s", strerror(-r));
+ log_error_errno(r, "Failed to start manager: %m");
goto finish;
}
@@ -92,7 +92,7 @@ int main(int argc, char *argv[]) {
* symlink */
r = manager_write_resolv_conf(m);
if (r < 0)
- log_warning("Could not create resolv.conf: %s", strerror(-r));
+ log_warning_errno(r, "Could not create resolv.conf: %m");
sd_notify(false,
"READY=1\n"
@@ -100,7 +100,7 @@ int main(int argc, char *argv[]) {
r = sd_event_loop(m->event);
if (r < 0) {
- log_error("Event loop failed: %s", strerror(-r));
+ log_error_errno(r, "Event loop failed: %m");
goto finish;
}
@@ -108,7 +108,7 @@ int main(int argc, char *argv[]) {
finish:
sd_notify(false,
- "STOPPIN=1\n"
+ "STOPPING=1\n"
"STATUS=Shutting down...");
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in
index c8263d67f4..e5a19ee474 100644
--- a/src/resolve/resolved.conf.in
+++ b/src/resolve/resolved.conf.in
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/resolved.conf.d/*.conf.
+#
# See resolved.conf(5) for details
[Resolve]
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index c7c659292a..5a90c778fb 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -28,8 +28,8 @@
int main(int argc, char *argv[]) {
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
- _cleanup_free_ char *saved = NULL, *escaped_name = NULL, *escaped_path_id = NULL;
- const char *name, *path_id;
+ _cleanup_free_ char *saved = NULL, *escaped_type = NULL, *escaped_path_id = NULL;
+ const char *name, *type, *path_id;
int r;
if (argc != 3) {
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
r = mkdir_p("/var/lib/systemd/rfkill", 0755);
if (r < 0) {
- log_error("Failed to create rfkill directory: %s", strerror(-r));
+ log_error_errno(r, "Failed to create rfkill directory: %m");
return EXIT_FAILURE;
}
@@ -55,25 +55,28 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- errno = 0;
device = udev_device_new_from_subsystem_sysname(udev, "rfkill", argv[2]);
if (!device) {
- if (errno != 0)
- log_error("Failed to get rfkill device '%s': %m", argv[2]);
- else
- log_oom();
-
- return EXIT_FAILURE;
+ log_debug_errno(errno, "Failed to get rfkill device '%s', ignoring: %m", argv[2]);
+ return EXIT_SUCCESS;
}
name = udev_device_get_sysattr_value(device, "name");
if (!name) {
- log_error("rfkill device has no name?");
- return EXIT_FAILURE;
+ log_error("rfkill device has no name? Ignoring device.");
+ return EXIT_SUCCESS;
+ }
+
+ log_debug("Operating on rfkill device '%s'.", name);
+
+ type = udev_device_get_sysattr_value(device, "type");
+ if (!type) {
+ log_error("rfkill device has no type? Ignoring device.");
+ return EXIT_SUCCESS;
}
- escaped_name = cescape(name);
- if (!escaped_name) {
+ escaped_type = cescape(type);
+ if (!escaped_type) {
log_oom();
return EXIT_FAILURE;
}
@@ -86,9 +89,9 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_name, NULL);
+ saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_type, NULL);
} else
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_name, NULL);
+ saved = strjoin("/var/lib/systemd/rfkill/", escaped_type, NULL);
if (!saved) {
log_oom();
@@ -102,19 +105,17 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
r = read_one_line_file(saved, &value);
+ if (r == -ENOENT)
+ return EXIT_SUCCESS;
if (r < 0) {
-
- if (r == -ENOENT)
- return EXIT_SUCCESS;
-
- log_error("Failed to read %s: %s", saved, strerror(-r));
+ log_error_errno(r, "Failed to read %s: %m", saved);
return EXIT_FAILURE;
}
r = udev_device_set_sysattr_value(device, "soft", value);
if (r < 0) {
- log_error("Failed to write system attribute: %s", strerror(-r));
- return EXIT_FAILURE;
+ log_debug_errno(r, "Failed to write 'soft' attribute on rfkill device, ignoring: %m");
+ return EXIT_SUCCESS;
}
} else if (streq(argv[1], "save")) {
@@ -122,13 +123,13 @@ int main(int argc, char *argv[]) {
value = udev_device_get_sysattr_value(device, "soft");
if (!value) {
- log_error("Failed to read system attribute: %s", strerror(-r));
- return EXIT_FAILURE;
+ log_debug_errno(r, "Failed to read system attribute, ignoring device: %m");
+ return EXIT_SUCCESS;
}
r = write_string_file(saved, value);
if (r < 0) {
- log_error("Failed to write %s: %s", saved, strerror(-r));
+ log_error_errno(r, "Failed to write %s: %m", saved);
return EXIT_FAILURE;
}
diff --git a/src/run/run.c b/src/run/run.c
index e3b62939c7..7a80223918 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -30,6 +30,7 @@
#include "env-util.h"
#include "path-util.h"
#include "bus-error.h"
+#include "calendarspec.h"
static bool arg_scope = false;
static bool arg_remain_after_exit = false;
@@ -47,30 +48,51 @@ static int arg_nice = 0;
static bool arg_nice_set = false;
static char **arg_environment = NULL;
static char **arg_property = NULL;
+static usec_t arg_on_active = 0;
+static usec_t arg_on_boot = 0;
+static usec_t arg_on_startup = 0;
+static usec_t arg_on_unit_active = 0;
+static usec_t arg_on_unit_inactive = 0;
+static char *arg_on_calendar = NULL;
+static char **arg_timer_property = NULL;
static void help(void) {
- printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n"
- "Run the specified command in a transient scope or service unit.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --user Run as user unit\n"
- " -H --host=[USER@]HOST Operate on remote host\n"
- " -M --machine=CONTAINER Operate on local container\n"
- " --scope Run this as scope rather than service\n"
- " --unit=UNIT Run under the specified unit name\n"
- " -p --property=NAME=VALUE Set unit property\n"
- " --description=TEXT Description for unit\n"
- " --slice=SLICE Run in the specified slice\n"
- " -r --remain-after-exit Leave service around until explicitly stopped\n"
- " --send-sighup Send SIGHUP when terminating\n"
- " --service-type=TYPE Service type\n"
- " --uid=USER Run as system user\n"
- " --gid=GROUP Run as system group\n"
- " --nice=NICE Nice level\n"
- " --setenv=NAME=VALUE Set environment\n",
+ printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
+ "Run the specified command in a transient scope or service or timer\n"
+ "unit. If timer option is specified and unit is exist which is\n"
+ "specified with --unit option then command can be ommited.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --user Run as user unit\n"
+ " -H --host=[USER@]HOST Operate on remote host\n"
+ " -M --machine=CONTAINER Operate on local container\n"
+ " --scope Run this as scope rather than service\n"
+ " --unit=UNIT Run under the specified unit name\n"
+ " -p --property=NAME=VALUE Set unit property\n"
+ " --description=TEXT Description for unit\n"
+ " --slice=SLICE Run in the specified slice\n"
+ " -r --remain-after-exit Leave service around until explicitly stopped\n"
+ " --send-sighup Send SIGHUP when terminating\n"
+ " --service-type=TYPE Service type\n"
+ " --uid=USER Run as system user\n"
+ " --gid=GROUP Run as system group\n"
+ " --nice=NICE Nice level\n"
+ " --setenv=NAME=VALUE Set environment\n\n"
+ "Timer options:\n\n"
+ " --on-active=SEC Run after seconds\n"
+ " --on-boot=SEC Run after seconds from machine was booted up\n"
+ " --on-startup=SEC Run after seconds from systemd was first started\n"
+ " --on-unit-active=SEC Run after seconds from the last activation\n"
+ " --on-unit-inactive=SEC Run after seconds from the last deactivation\n"
+ " --on-calendar=SPEC Realtime timer\n"
+ " --timer-property=NAME=VALUE Set timer unit property\n",
program_invocation_short_name);
}
+static bool with_timer(void) {
+ return arg_on_active || arg_on_boot || arg_on_startup || arg_on_unit_active || arg_on_unit_inactive || arg_on_calendar;
+}
+
static int parse_argv(int argc, char *argv[]) {
enum {
@@ -86,32 +108,47 @@ static int parse_argv(int argc, char *argv[]) {
ARG_EXEC_GROUP,
ARG_SERVICE_TYPE,
ARG_NICE,
- ARG_SETENV
+ ARG_SETENV,
+ ARG_ON_ACTIVE,
+ ARG_ON_BOOT,
+ ARG_ON_STARTUP,
+ ARG_ON_UNIT_ACTIVE,
+ ARG_ON_UNIT_INACTIVE,
+ ARG_ON_CALENDAR,
+ ARG_TIMER_PROPERTY
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "user", no_argument, NULL, ARG_USER },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "scope", no_argument, NULL, ARG_SCOPE },
- { "unit", required_argument, NULL, ARG_UNIT },
- { "description", required_argument, NULL, ARG_DESCRIPTION },
- { "slice", required_argument, NULL, ARG_SLICE },
- { "remain-after-exit", no_argument, NULL, 'r' },
- { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
- { "host", required_argument, NULL, 'H' },
- { "machine", required_argument, NULL, 'M' },
- { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
- { "uid", required_argument, NULL, ARG_EXEC_USER },
- { "gid", required_argument, NULL, ARG_EXEC_GROUP },
- { "nice", required_argument, NULL, ARG_NICE },
- { "setenv", required_argument, NULL, ARG_SETENV },
- { "property", required_argument, NULL, 'p' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "user", no_argument, NULL, ARG_USER },
+ { "system", no_argument, NULL, ARG_SYSTEM },
+ { "scope", no_argument, NULL, ARG_SCOPE },
+ { "unit", required_argument, NULL, ARG_UNIT },
+ { "description", required_argument, NULL, ARG_DESCRIPTION },
+ { "slice", required_argument, NULL, ARG_SLICE },
+ { "remain-after-exit", no_argument, NULL, 'r' },
+ { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
+ { "host", required_argument, NULL, 'H' },
+ { "machine", required_argument, NULL, 'M' },
+ { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
+ { "uid", required_argument, NULL, ARG_EXEC_USER },
+ { "gid", required_argument, NULL, ARG_EXEC_GROUP },
+ { "nice", required_argument, NULL, ARG_NICE },
+ { "setenv", required_argument, NULL, ARG_SETENV },
+ { "property", required_argument, NULL, 'p' },
+ { "on-active", required_argument, NULL, ARG_ON_ACTIVE },
+ { "on-boot", required_argument, NULL, ARG_ON_BOOT },
+ { "on-startup", required_argument, NULL, ARG_ON_STARTUP },
+ { "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
+ { "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
+ { "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
+ { "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
{},
};
int r, c;
+ CalendarSpec *spec = NULL;
assert(argc >= 0);
assert(argv);
@@ -207,6 +244,74 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_ON_ACTIVE:
+
+ r = parse_sec(optarg, &arg_on_active);
+ if (r < 0) {
+ log_error("Failed to parse timer value: %s", optarg);
+ return r;
+ }
+
+ break;
+
+ case ARG_ON_BOOT:
+
+ r = parse_sec(optarg, &arg_on_boot);
+ if (r < 0) {
+ log_error("Failed to parse timer value: %s", optarg);
+ return r;
+ }
+
+ break;
+
+ case ARG_ON_STARTUP:
+
+ r = parse_sec(optarg, &arg_on_startup);
+ if (r < 0) {
+ log_error("Failed to parse timer value: %s", optarg);
+ return r;
+ }
+
+ break;
+
+ case ARG_ON_UNIT_ACTIVE:
+
+ r = parse_sec(optarg, &arg_on_unit_active);
+ if (r < 0) {
+ log_error("Failed to parse timer value: %s", optarg);
+ return r;
+ }
+
+ break;
+
+ case ARG_ON_UNIT_INACTIVE:
+
+ r = parse_sec(optarg, &arg_on_unit_inactive);
+ if (r < 0) {
+ log_error("Failed to parse timer value: %s", optarg);
+ return r;
+ }
+
+ break;
+
+ case ARG_ON_CALENDAR:
+
+ r = calendar_spec_from_string(optarg, &spec);
+ if (r < 0) {
+ log_error("Invalid calendar spec: %s", optarg);
+ return r;
+ }
+ free(spec);
+ arg_on_calendar = optarg;
+ break;
+
+ case ARG_TIMER_PROPERTY:
+
+ if (strv_extend(&arg_timer_property, optarg) < 0)
+ return log_oom();
+
+ break;
+
case '?':
return -EINVAL;
@@ -214,7 +319,7 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (optind >= argc) {
+ if ((optind >= argc) && (!arg_unit || !with_timer())) {
log_error("Command line to execute required.");
return -EINVAL;
}
@@ -234,44 +339,34 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_scope && with_timer()) {
+ log_error("Timer options are not supported in --scope mode.");
+ return -EINVAL;
+ }
+
+ if (arg_timer_property && !with_timer()) {
+ log_error("--timer-property= has no effect without any other timer options.");
+ return -EINVAL;
+ }
+
return 1;
}
-static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bus_message **ret) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+static int transient_unit_set_properties(sd_bus_message *m, UnitType t) {
char **i;
int r;
- assert(bus);
- assert(name);
- assert(ret);
-
- r = sd_bus_message_new_method_call(
- bus,
- &m,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "StartTransientUnit");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "ss", name, "fail");
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(m, 'a', "(sv)");
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, arg_property) {
+ STRV_FOREACH(i, t == UNIT_TIMER ? arg_timer_property : arg_property) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
return r;
r = bus_append_unit_property_assignment(m, *i);
- if (r < 0)
- return r;
+ if (r < 0) {
+ r = sd_bus_message_append(m, "sv", 0);
+ if (r < 0)
+ return r;
+ }
r = sd_bus_message_close_container(m);
if (r < 0)
@@ -294,152 +389,324 @@ static int message_start_transient_unit_new(sd_bus *bus, const char *name, sd_bu
return r;
}
- if (arg_send_sighup) {
+ if (arg_send_sighup && t != UNIT_TIMER) {
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
if (r < 0)
return r;
}
- *ret = m;
- m = NULL;
-
return 0;
}
-static int message_start_transient_unit_send(sd_bus *bus, sd_bus_message *m, sd_bus_error *error, sd_bus_message **reply) {
+static int transient_service_set_properties(sd_bus_message *m, char **argv) {
int r;
- assert(bus);
assert(m);
- r = sd_bus_message_close_container(m);
+ r = transient_unit_set_properties(m, UNIT_SERVICE);
if (r < 0)
return r;
- r = sd_bus_message_append(m, "a(sa(sv))", 0);
- if (r < 0)
- return r;
-
- return sd_bus_call(bus, m, 0, error, reply);
-}
-
-static int start_transient_service(
- sd_bus *bus,
- char **argv,
- sd_bus_error *error) {
-
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *name = NULL;
- int r;
-
- if (arg_unit) {
- name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
- if (!name)
- return log_oom();
- } else if (asprintf(&name, "run-"PID_FMT".service", getpid()) < 0)
- return log_oom();
-
- r = message_start_transient_unit_new(bus, name, &m);
- if (r < 0)
- return bus_log_create_error(r);
-
if (arg_remain_after_exit) {
r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
}
if (arg_service_type) {
r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
}
if (arg_exec_user) {
r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
}
if (arg_exec_group) {
r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
}
if (arg_nice_set) {
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
}
if (!strv_isempty(arg_environment)) {
r = sd_bus_message_open_container(m, 'r', "sv");
if (r < 0)
- return bus_log_create_error(r);
+ return r;
r = sd_bus_message_append(m, "s", "Environment");
if (r < 0)
- return bus_log_create_error(r);
+ return r;
r = sd_bus_message_open_container(m, 'v', "as");
if (r < 0)
- return bus_log_create_error(r);
+ return r;
r = sd_bus_message_append_strv(m, arg_environment);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
r = sd_bus_message_close_container(m);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
r = sd_bus_message_close_container(m);
if (r < 0)
- return bus_log_create_error(r);
+ return r;
+ }
+
+ /* Exec container */
+ {
+ r = sd_bus_message_open_container(m, 'r', "sv");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", "ExecStart");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'v', "a(sasb)");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'a', "(sasb)");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'r', "sasb");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", argv[0]);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_strv(m, argv);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "b", false);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int transient_timer_set_properties(sd_bus_message *m) {
+ int r;
+
+ assert(m);
+
+ r = transient_unit_set_properties(m, UNIT_TIMER);
+ if (r < 0)
+ return r;
+
+ if (arg_on_active) {
+ r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active);
+ if (r < 0)
+ return r;
+ }
+
+ if (arg_on_boot) {
+ r = sd_bus_message_append(m, "(sv)", "OnBootSec", "t", arg_on_boot);
+ if (r < 0)
+ return r;
+ }
+
+ if (arg_on_startup) {
+ r = sd_bus_message_append(m, "(sv)", "OnStartupSec", "t", arg_on_startup);
+ if (r < 0)
+ return r;
+ }
+
+ if (arg_on_unit_active) {
+ r = sd_bus_message_append(m, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active);
+ if (r < 0)
+ return r;
+ }
+
+ if (arg_on_unit_inactive) {
+ r = sd_bus_message_append(m, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive);
+ if (r < 0)
+ return r;
}
- r = sd_bus_message_open_container(m, 'r', "sv");
+ if (arg_on_calendar) {
+ r = sd_bus_message_append(m, "(sv)", "OnCalendar", "s", arg_on_calendar);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int transient_scope_set_properties(sd_bus_message *m) {
+ int r;
+
+ assert(m);
+
+ r = transient_unit_set_properties(m, UNIT_SCOPE);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int start_transient_service(
+ sd_bus *bus,
+ char **argv,
+ sd_bus_error *error) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_free_ char *service = NULL;
+ int r;
+
+ assert(bus);
+ assert(argv);
+
+ if (arg_unit) {
+ service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
+ if (!service)
+ return log_oom();
+ } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0)
+ return log_oom();
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append(m, "s", "ExecStart");
+ /* name and mode */
+ r = sd_bus_message_append(m, "ss", service, "fail");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_open_container(m, 'v', "a(sasb)");
+ /* properties */
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_open_container(m, 'a', "(sasb)");
+ r = transient_service_set_properties(m, argv);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_open_container(m, 'r', "sasb");
+ r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append(m, "s", argv[0]);
+ /* aux */
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_strv(m, argv);
+ /* send dbus */
+ r = sd_bus_call(bus, m, 0, error, NULL);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append(m, "b", false);
+ log_info("Running as unit %s.", service);
+
+ return 0;
+}
+
+static int start_transient_timer(
+ sd_bus *bus,
+ char **argv,
+ sd_bus_error *error) {
+
+ _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ _cleanup_free_ char *timer = NULL, *service = NULL;
+ int r;
+
+ assert(bus);
+ assert(argv);
+
+ if (arg_unit) {
+ switch(unit_name_to_type(arg_unit)) {
+ case UNIT_SERVICE:
+ service = strdup(arg_unit);
+ timer = unit_name_change_suffix(service, ".timer");
+ if (!timer)
+ return log_oom();
+ break;
+
+ case UNIT_TIMER:
+ timer = strdup(arg_unit);
+ service = unit_name_change_suffix(timer, ".service");
+ if (!service)
+ return log_oom();
+ break;
+
+ default:
+ service = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".service");
+ if (!service)
+ return log_oom();
+
+ timer = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".timer");
+ if (!timer)
+ return log_oom();
+
+ break;
+ }
+ } else if ((asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) ||
+ (asprintf(&timer, "run-"PID_FMT".timer", getpid()) < 0))
+ return log_oom();
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_close_container(m);
+ /* name and mode */
+ r = sd_bus_message_append(m, "ss", timer, "fail");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_close_container(m);
+ /* properties */
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_close_container(m);
+ r = transient_timer_set_properties(m);
if (r < 0)
return bus_log_create_error(r);
@@ -447,11 +714,52 @@ static int start_transient_service(
if (r < 0)
return bus_log_create_error(r);
- r = message_start_transient_unit_send(bus, m, error, NULL);
+ if (argv[0]) {
+ r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'r', "sa(sv)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", service);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = transient_service_set_properties(m, argv);
+ 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);
+ 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);
+ } else {
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ /* send dbus */
+ r = sd_bus_call(bus, m, 0, error, NULL);
if (r < 0)
return bus_log_create_error(r);
- log_info("Running as unit %s.", name);
+ log_info("Running as unit %s.", timer);
+ if (argv[0])
+ log_info("Will run as unit %s.", service);
return 0;
}
@@ -462,51 +770,72 @@ static int start_transient_scope(
sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *name = NULL;
+ _cleanup_free_ char *scope = NULL;
_cleanup_strv_free_ char **env = NULL, **user_env = NULL;
int r;
assert(bus);
+ assert(argv);
if (arg_unit) {
- name = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
- if (!name)
+ scope = unit_name_mangle_with_suffix(arg_unit, MANGLE_NOGLOB, ".scope");
+ if (!scope)
return log_oom();
- } else if (asprintf(&name, "run-"PID_FMT".scope", getpid()) < 0)
+ } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0)
return log_oom();
- r = message_start_transient_unit_new(bus, name, &m);
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "StartTransientUnit");
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
+ /* name and mode */
+ r = sd_bus_message_append(m, "ss", scope, "fail");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* properties */
+ r = sd_bus_message_open_container(m, 'a', "(sv)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = transient_scope_set_properties(m);
+ 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);
+
+ /* aux */
+ r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0)
return bus_log_create_error(r);
- r = message_start_transient_unit_send(bus, m, error, NULL);
+ /* send dbus */
+ r = sd_bus_call(bus, m, 0, error, NULL);
if (r < 0)
return bus_log_create_error(r);
if (arg_nice_set) {
- if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0) {
- log_error("Failed to set nice level: %m");
- return -errno;
- }
+ if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
+ return log_error_errno(errno, "Failed to set nice level: %m");
}
if (arg_exec_group) {
gid_t gid;
r = get_group_creds(&arg_exec_group, &gid);
- if (r < 0) {
- log_error("Failed to resolve group %s: %s", arg_exec_group, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
- if (setresgid(gid, gid, gid) < 0) {
- log_error("Failed to change GID to " GID_FMT ": %m", gid);
- return -errno;
- }
+ if (setresgid(gid, gid, gid) < 0)
+ return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
}
if (arg_exec_user) {
@@ -515,10 +844,8 @@ static int start_transient_scope(
gid_t gid;
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell);
- if (r < 0) {
- log_error("Failed to resolve user %s: %s", arg_exec_user, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
r = strv_extendf(&user_env, "HOME=%s", home);
if (r < 0)
@@ -537,26 +864,22 @@ static int start_transient_scope(
return log_oom();
if (!arg_exec_group) {
- if (setresgid(gid, gid, gid) < 0) {
- log_error("Failed to change GID to " GID_FMT ": %m", gid);
- return -errno;
- }
+ if (setresgid(gid, gid, gid) < 0)
+ return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
}
- if (setresuid(uid, uid, uid) < 0) {
- log_error("Failed to change UID to " UID_FMT ": %m", uid);
- return -errno;
- }
+ if (setresuid(uid, uid, uid) < 0)
+ return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
}
env = strv_env_merge(3, environ, user_env, arg_environment);
if (!env)
return log_oom();
- log_info("Running as unit %s.", name);
+ log_info("Running as unit %s.", scope);
execvpe(argv[0], argv, env);
- log_error("Failed to execute: %m");
+ log_error_errno(errno, "Failed to execute: %m");
return -errno;
}
@@ -573,12 +896,16 @@ int main(int argc, char* argv[]) {
if (r <= 0)
goto finish;
- r = find_binary(argv[optind], &command);
- if (r < 0) {
- log_error("Failed to find executable %s: %s", argv[optind], strerror(-r));
- goto finish;
+ if (argc > optind) {
+ r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &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");
+ goto finish;
+ }
+ argv[optind] = command;
}
- argv[optind] = command;
if (!arg_description) {
description = strv_join(argv + optind, " ");
@@ -587,23 +914,36 @@ int main(int argc, char* argv[]) {
goto finish;
}
+ if (arg_unit && isempty(description)) {
+ free(description);
+ description = strdup(arg_unit);
+
+ if (!description) {
+ r = log_oom();
+ goto finish;
+ }
+ }
+
arg_description = description;
}
r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
if (arg_scope)
r = start_transient_scope(bus, argv + optind, &error);
+ else if (with_timer())
+ r = start_transient_timer(bus, argv + optind, &error);
else
r = start_transient_service(bus, argv + optind, &error);
finish:
strv_free(arg_environment);
strv_free(arg_property);
+ strv_free(arg_timer_property);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/shared/architecture.c b/src/shared/architecture.c
index dc45f3589d..34c5a53fa9 100644
--- a/src/shared/architecture.c
+++ b/src/shared/architecture.c
@@ -23,7 +23,7 @@
#include "architecture.h"
-Architecture uname_architecture(void) {
+int uname_architecture(void) {
/* Return a sanitized enum identifying the architecture we are
* running on. This is based on uname(), and the user may
@@ -41,7 +41,7 @@ Architecture uname_architecture(void) {
static const struct {
const char *machine;
- Architecture arch;
+ int arch;
} arch_map[] = {
#if defined(__x86_64__) || defined(__i386__)
{ "x86_64", ARCHITECTURE_X86_64 },
@@ -121,7 +121,7 @@ Architecture uname_architecture(void) {
#endif
};
- static Architecture cached = _ARCHITECTURE_INVALID;
+ static int cached = _ARCHITECTURE_INVALID;
struct utsname u;
unsigned i;
@@ -168,4 +168,4 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
[ARCHITECTURE_CRIS] = "cris",
};
-DEFINE_STRING_TABLE_LOOKUP(architecture, Architecture);
+DEFINE_STRING_TABLE_LOOKUP(architecture, int);
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index 353d49bedf..cb82418a5e 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -30,7 +30,7 @@
* focus on general family, and distuignish word width and
* endianness. */
-typedef enum Architecture {
+enum {
ARCHITECTURE_X86 = 0,
ARCHITECTURE_X86_64,
ARCHITECTURE_PPC,
@@ -60,9 +60,9 @@ typedef enum Architecture {
ARCHITECTURE_CRIS,
_ARCHITECTURE_MAX,
_ARCHITECTURE_INVALID = -1
-} Architecture;
+};
-Architecture uname_architecture(void);
+int uname_architecture(void);
/*
* LIB_ARCH_TUPLE should resolve to the local library path
@@ -133,7 +133,7 @@ Architecture uname_architecture(void);
# else
# define native_architecture() ARCHITECTURE_MIPS_LE
# define LIB_ARCH_TUPLE "mipsel-linux-gnu"
-#endif
+# endif
#elif defined(__alpha__)
# define native_architecture() ARCHITECTURE_ALPHA
# define LIB_ARCH_TUPLE "alpha-linux-gnu"
@@ -185,8 +185,8 @@ Architecture uname_architecture(void);
# define native_architecture() ARCHITECTURE_CRIS
# error "Missing LIB_ARCH_TUPLE for CRIS"
#else
-#error "Please register your architecture here!"
+# error "Please register your architecture here!"
#endif
-const char *architecture_to_string(Architecture a) _const_;
-Architecture architecture_from_string(const char *s) _pure_;
+const char *architecture_to_string(int a) _const_;
+int architecture_from_string(const char *s) _pure_;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 94a27f9010..d6589a67f6 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -258,10 +258,8 @@ static int create_socket(char **name) {
assert(name);
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0) {
- log_error("socket() failed: %m");
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "socket() failed: %m");
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
@@ -271,13 +269,13 @@ static int create_socket(char **name) {
if (r < 0) {
r = -errno;
- log_error("bind(%s) failed: %m", sa.un.sun_path);
+ log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
goto fail;
}
if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
r = -errno;
- log_error("SO_PASSCRED failed: %m");
+ log_error_errno(errno, "SO_PASSCRED failed: %m");
goto fail;
}
@@ -330,7 +328,7 @@ int ask_password_agent(
fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- log_error("Failed to create password file: %m");
+ log_error_errno(errno, "Failed to create password file: %m");
r = -errno;
goto finish;
}
@@ -339,7 +337,7 @@ int ask_password_agent(
f = fdopen(fd, "w");
if (!f) {
- log_error("Failed to allocate FILE: %m");
+ log_error_errno(errno, "Failed to allocate FILE: %m");
r = -errno;
goto finish;
}
@@ -348,7 +346,7 @@ int ask_password_agent(
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0) {
- log_error("signalfd(): %m");
+ log_error_errno(errno, "signalfd(): %m");
r = -errno;
goto finish;
}
@@ -384,7 +382,7 @@ int ask_password_agent(
fflush(f);
if (ferror(f)) {
- log_error("Failed to write query file: %m");
+ log_error_errno(errno, "Failed to write query file: %m");
r = -errno;
goto finish;
}
@@ -396,7 +394,7 @@ int ask_password_agent(
final[sizeof(final)-9] = 'k';
if (rename(temp, final) < 0) {
- log_error("Failed to rename query file: %m");
+ log_error_errno(errno, "Failed to rename query file: %m");
r = -errno;
goto finish;
}
@@ -433,7 +431,7 @@ int ask_password_agent(
if (errno == EINTR)
continue;
- log_error("poll() failed: %m");
+ log_error_errno(errno, "poll() failed: %m");
r = -errno;
goto finish;
}
@@ -472,7 +470,7 @@ int ask_password_agent(
errno == EINTR)
continue;
- log_error("recvmsg() failed: %m");
+ log_error_errno(errno, "recvmsg() failed: %m");
r = -errno;
goto finish;
}
diff --git a/src/shared/audit.c b/src/shared/audit.c
index f101050825..4701c0a8de 100644
--- a/src/shared/audit.c
+++ b/src/shared/audit.c
@@ -80,3 +80,21 @@ int audit_loginuid_from_pid(pid_t pid, uid_t *uid) {
*uid = (uid_t) u;
return 0;
}
+
+bool use_audit(void) {
+ static int cached_use = -1;
+
+ if (cached_use < 0) {
+ int fd;
+
+ fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
+ if (fd < 0)
+ cached_use = errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT;
+ else {
+ cached_use = true;
+ safe_close(fd);
+ }
+ }
+
+ return cached_use;
+}
diff --git a/src/shared/audit.h b/src/shared/audit.h
index 0effc0baa0..b4aecffb30 100644
--- a/src/shared/audit.h
+++ b/src/shared/audit.h
@@ -27,3 +27,5 @@
int audit_session_from_pid(pid_t pid, uint32_t *id);
int audit_loginuid_from_pid(pid_t pid, uid_t *uid);
+
+bool use_audit(void);
diff --git a/src/shared/barrier.h b/src/shared/barrier.h
index c55e311344..d4ad2a419b 100644
--- a/src/shared/barrier.h
+++ b/src/shared/barrier.h
@@ -91,6 +91,6 @@ static inline bool barrier_is_aborted(Barrier *b) {
}
static inline bool barrier_place_and_sync(Barrier *b) {
- barrier_place(b);
+ (void)barrier_place(b);
return barrier_sync(b);
}
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index 4c65a495d3..73907c6354 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -58,10 +58,8 @@ int base_filesystem_create(const char *root) {
int r;
fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (fd < 0) {
- log_error("Failed to open root file system: %m");
- return -errno;
- }
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open root file system: %m");
for (i = 0; i < ELEMENTSOF(table); i ++) {
if (faccessat(fd, table[i].dir, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
@@ -95,19 +93,15 @@ int base_filesystem_create(const char *root) {
continue;
r = symlinkat(target, fd, table[i].dir);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create symlink at %s/%s: %m", root, table[i].dir);
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
continue;
}
RUN_WITH_UMASK(0000)
r = mkdirat(fd, table[i].dir, table[i].mode);
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create directory at %s/%s: %m", root, table[i].dir);
- return -errno;
- }
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir);
}
return 0;
diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c
index 7efcf7b371..19ae8a3233 100644
--- a/src/shared/calendarspec.c
+++ b/src/shared/calendarspec.c
@@ -24,6 +24,8 @@
#include "calendarspec.h"
+#define BITS_WEEKDAYS 127
+
static void free_chain(CalendarComponent *c) {
CalendarComponent *n;
@@ -120,7 +122,7 @@ static void fix_year(CalendarComponent *c) {
int calendar_spec_normalize(CalendarSpec *c) {
assert(c);
- if (c->weekdays_bits <= 0 || c->weekdays_bits >= 127)
+ if (c->weekdays_bits <= 0 || c->weekdays_bits >= BITS_WEEKDAYS)
c->weekdays_bits = -1;
fix_year(c->year);
@@ -154,7 +156,7 @@ _pure_ static bool chain_valid(CalendarComponent *c, int from, int to) {
_pure_ bool calendar_spec_valid(CalendarSpec *c) {
assert(c);
- if (c->weekdays_bits > 127)
+ if (c->weekdays_bits > BITS_WEEKDAYS)
return false;
if (!chain_valid(c->year, 1970, 2199))
@@ -194,7 +196,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
assert(f);
assert(c);
- assert(c->weekdays_bits > 0 && c->weekdays_bits <= 127);
+ assert(c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS);
for (x = 0, l = -1; x < (int) ELEMENTSOF(days); x++) {
@@ -259,7 +261,7 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
if (!f)
return -ENOMEM;
- if (c->weekdays_bits > 0 && c->weekdays_bits <= 127) {
+ if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) {
format_weekdays(f, c);
fputc(' ', f);
}
@@ -880,7 +882,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
struct tm t;
int k;
- if (weekdays_bits < 0 || weekdays_bits >= 127)
+ if (weekdays_bits < 0 || weekdays_bits >= BITS_WEEKDAYS)
return true;
t = *tm;
diff --git a/src/shared/cap-list.c b/src/shared/cap-list.c
new file mode 100644
index 0000000000..56d1488f48
--- /dev/null
+++ b/src/shared/cap-list.c
@@ -0,0 +1,62 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 <linux/capability.h>
+#include <string.h>
+
+#include "util.h"
+#include "cap-list.h"
+#include "missing.h"
+
+static const struct capability_name* lookup_capability(register const char *str, register unsigned int len);
+
+#include "cap-to-name.h"
+#include "cap-from-name.h"
+
+const char *capability_to_name(int id) {
+
+ if (id < 0)
+ return NULL;
+
+ if (id >= (int) ELEMENTSOF(capability_names))
+ return NULL;
+
+ return capability_names[id];
+}
+
+int capability_from_name(const char *name) {
+ const struct capability_name *sc;
+ int r, i;
+
+ assert(name);
+
+ /* Try to parse numeric capability */
+ r = safe_atoi(name, &i);
+ if (r >= 0 && i >= 0)
+ return i;
+
+ /* Try to parse string capability */
+ sc = lookup_capability(name, strlen(name));
+ if (!sc)
+ return -EINVAL;
+
+ return sc->id;
+}
diff --git a/src/core/condition.h b/src/shared/cap-list.h
index 6dd77bb658..c699e466a7 100644
--- a/src/core/condition.h
+++ b/src/shared/cap-list.h
@@ -5,7 +5,7 @@
/***
This file is part of systemd.
- Copyright 2010 Lennart Poettering
+ Copyright 2014 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
@@ -21,6 +21,5 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "condition-util.h"
-
-bool condition_test_list(const char *unit, Condition *c);
+const char *capability_to_name(int id);
+int capability_from_name(const char *name);
diff --git a/src/shared/capability.c b/src/shared/capability.c
index d2b901337f..65d7e038a7 100644
--- a/src/shared/capability.c
+++ b/src/shared/capability.c
@@ -227,37 +227,25 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
* binary has the capability configured in the file system,
* which we want to avoid. */
- if (setresgid(gid, gid, gid) < 0) {
- log_error("Failed change group ID: %m");
- return -errno;
- }
+ if (setresgid(gid, gid, gid) < 0)
+ return log_error_errno(errno, "Failed to change group ID: %m");
- if (setgroups(0, NULL) < 0) {
- log_error("Failed to drop auxiliary groups list: %m");
- return -errno;
- }
+ if (setgroups(0, NULL) < 0)
+ return log_error_errno(errno, "Failed to drop auxiliary groups list: %m");
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- log_error("Failed to enable keep capabilities flag: %m");
- return -errno;
- }
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0)
+ return log_error_errno(errno, "Failed to enable keep capabilities flag: %m");
r = setresuid(uid, uid, uid);
- if (r < 0) {
- log_error("Failed change user ID: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to change user ID: %m");
- if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
- log_error("Failed to disable keep capabilities flag: %m");
- return -errno;
- }
+ if (prctl(PR_SET_KEEPCAPS, 0) < 0)
+ return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
r = capability_bounding_set_drop(~keep_capabilities, true);
- if (r < 0) {
- log_error("Failed to drop capabilities: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to drop capabilities: %m");
d = cap_init();
if (!d)
@@ -273,15 +261,31 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
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("Failed to enable capabilities bits: %m");
+ log_error_errno(errno, "Failed to enable capabilities bits: %m");
return -errno;
}
}
- if (cap_set_proc(d) < 0) {
- log_error("Failed to increase capabilities: %m");
+ if (cap_set_proc(d) < 0)
+ return log_error_errno(errno, "Failed to increase capabilities: %m");
+
+ return 0;
+}
+
+int drop_capability(cap_value_t cv) {
+ _cleanup_cap_free_ cap_t tmp_cap = NULL;
+
+ tmp_cap = cap_get_proc();
+ if (!tmp_cap)
+ return -errno;
+
+ if ((cap_set_flag(tmp_cap, CAP_INHERITABLE, 1, &cv, CAP_CLEAR) < 0) ||
+ (cap_set_flag(tmp_cap, CAP_PERMITTED, 1, &cv, CAP_CLEAR) < 0) ||
+ (cap_set_flag(tmp_cap, CAP_EFFECTIVE, 1, &cv, CAP_CLEAR) < 0))
+ return -errno;
+
+ if (cap_set_proc(tmp_cap) < 0)
return -errno;
- }
return 0;
}
diff --git a/src/shared/capability.h b/src/shared/capability.h
index 3e6d9995f5..6f2f6f997d 100644
--- a/src/shared/capability.h
+++ b/src/shared/capability.h
@@ -34,6 +34,8 @@ int capability_bounding_set_drop_usermode(uint64_t drop);
int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites);
+int drop_capability(cap_value_t cv);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free);
#define _cleanup_cap_free_ _cleanup_(cap_freep)
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index da8e885226..1bcba01887 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -195,7 +195,7 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
if (ret >= 0 && errno != ESRCH)
ret = -errno;
} else {
- if (sigcont)
+ if (sigcont && sig != SIGKILL)
kill(pid, SIGCONT);
if (ret == 0)
@@ -682,7 +682,7 @@ int cg_set_group_access(
assert(path);
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
mode &= 0777;
r = cg_get_path(controller, path, NULL, &fs);
@@ -704,10 +704,10 @@ int cg_set_task_access(
assert(path);
- if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1)
+ if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
return 0;
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
mode &= 0666;
r = cg_get_path(controller, path, "cgroup.procs", &fs);
@@ -1624,7 +1624,7 @@ int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask ma
return 0;
}
-int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid) {
+int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
CGroupControllerMask bit = 1;
const char *n;
int r;
@@ -1634,8 +1634,18 @@ int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t
return r;
NULSTR_FOREACH(n, mask_names) {
- if (supported & bit)
+
+ if (supported & bit) {
+ const char *p = NULL;
+
+ if (path_callback)
+ p = path_callback(bit, userdata);
+
+ if (!p)
+ p = path;
+
cg_attach_fallback(n, path, pid);
+ }
bit <<= 1;
}
@@ -1643,7 +1653,7 @@ int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t
return 0;
}
-int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids) {
+int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t path_callback, void *userdata) {
Iterator i;
void *pidp;
int r = 0;
@@ -1652,7 +1662,7 @@ int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path,
pid_t pid = PTR_TO_LONG(pidp);
int q;
- q = cg_attach_everywhere(supported, path, pid);
+ q = cg_attach_everywhere(supported, path, pid, path_callback, userdata);
if (q < 0)
r = q;
}
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
index aca4e44c46..5e1e445c33 100644
--- a/src/shared/cgroup-util.h
+++ b/src/shared/cgroup-util.h
@@ -34,7 +34,8 @@ typedef enum CGroupControllerMask {
CGROUP_CPUACCT = 2,
CGROUP_BLKIO = 4,
CGROUP_MEMORY = 8,
- CGROUP_DEVICE = 16
+ CGROUP_DEVICE = 16,
+ _CGROUP_CONTROLLER_MASK_ALL = 31
} CGroupControllerMask;
/*
@@ -125,8 +126,8 @@ int cg_slice_to_path(const char *unit, char **ret);
typedef const char* (*cg_migrate_callback_t)(CGroupControllerMask mask, void *userdata);
int cg_create_everywhere(CGroupControllerMask supported, CGroupControllerMask mask, const char *path);
-int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid);
-int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids);
+int cg_attach_everywhere(CGroupControllerMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
+int cg_attach_many_everywhere(CGroupControllerMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
int cg_migrate_everywhere(CGroupControllerMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
int cg_trim_everywhere(CGroupControllerMask supported, const char *path, bool delete_root);
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index cb1722614e..39ab645133 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -44,7 +44,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning("Failed to open /proc/sysvipc/shm: %m");
+ log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
return -errno;
}
@@ -78,7 +78,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
if (errno == EIDRM || errno == EINVAL)
continue;
- log_warning("Failed to remove SysV shared memory segment %i: %m", shmid);
+ log_warning_errno(errno, "Failed to remove SysV shared memory segment %i: %m", shmid);
ret = -errno;
}
}
@@ -86,7 +86,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
return ret;
fail:
- log_warning("Failed to read /proc/sysvipc/shm: %m");
+ log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
return -errno;
}
@@ -101,7 +101,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning("Failed to open /proc/sysvipc/sem: %m");
+ log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
return -errno;
}
@@ -130,7 +130,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
if (errno == EIDRM || errno == EINVAL)
continue;
- log_warning("Failed to remove SysV semaphores object %i: %m", semid);
+ log_warning_errno(errno, "Failed to remove SysV semaphores object %i: %m", semid);
ret = -errno;
}
}
@@ -138,7 +138,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
return ret;
fail:
- log_warning("Failed to read /proc/sysvipc/sem: %m");
+ log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
return -errno;
}
@@ -153,7 +153,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning("Failed to open /proc/sysvipc/msg: %m");
+ log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
return -errno;
}
@@ -183,7 +183,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
if (errno == EIDRM || errno == EINVAL)
continue;
- log_warning("Failed to remove SysV message queue %i: %m", msgid);
+ log_warning_errno(errno, "Failed to remove SysV message queue %i: %m", msgid);
ret = -errno;
}
}
@@ -191,7 +191,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
return ret;
fail:
- log_warning("Failed to read /proc/sysvipc/msg: %m");
+ log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
return -errno;
}
@@ -211,7 +211,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
if (errno == ENOENT)
continue;
- log_warning("Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
ret = -errno;
continue;
}
@@ -225,7 +225,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
kid = xopendirat(dirfd(dir), de->d_name, O_NOFOLLOW|O_NOATIME);
if (!kid) {
if (errno != ENOENT) {
- log_warning("Failed to enter shared memory directory %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
ret = -errno;
}
} else {
@@ -239,7 +239,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
if (errno == ENOENT)
continue;
- log_warning("Failed to remove POSIX shared memory directory %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
ret = -errno;
}
} else {
@@ -249,7 +249,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
if (errno == ENOENT)
continue;
- log_warning("Failed to remove POSIX shared memory segment %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to remove POSIX shared memory segment %s: %m", de->d_name);
ret = -errno;
}
}
@@ -258,7 +258,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
return ret;
fail:
- log_warning("Failed to read /dev/shm: %m");
+ log_warning_errno(errno, "Failed to read /dev/shm: %m");
return -errno;
}
@@ -270,7 +270,7 @@ static int clean_posix_shm(uid_t uid) {
if (errno == ENOENT)
return 0;
- log_warning("Failed to open /dev/shm: %m");
+ log_warning_errno(errno, "Failed to open /dev/shm: %m");
return -errno;
}
@@ -287,7 +287,7 @@ static int clean_posix_mq(uid_t uid) {
if (errno == ENOENT)
return 0;
- log_warning("Failed to open /dev/mqueue: %m");
+ log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
return -errno;
}
@@ -302,7 +302,7 @@ static int clean_posix_mq(uid_t uid) {
if (errno == ENOENT)
continue;
- log_warning("Failed to stat() MQ segment %s: %m", de->d_name);
+ log_warning_errno(errno, "Failed to stat() MQ segment %s: %m", de->d_name);
ret = -errno;
continue;
}
@@ -317,7 +317,7 @@ static int clean_posix_mq(uid_t uid) {
if (errno == ENOENT)
continue;
- log_warning("Failed to unlink POSIX message queue %s: %m", fn);
+ log_warning_errno(errno, "Failed to unlink POSIX message queue %s: %m", fn);
ret = -errno;
}
}
@@ -325,7 +325,7 @@ static int clean_posix_mq(uid_t uid) {
return ret;
fail:
- log_warning("Failed to read /dev/mqueue: %m");
+ log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
return -errno;
}
diff --git a/src/shared/condition-util.c b/src/shared/condition-util.c
deleted file mode 100644
index ff4a8ecd15..0000000000
--- a/src/shared/condition-util.c
+++ /dev/null
@@ -1,267 +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 <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/statvfs.h>
-#include <fnmatch.h>
-
-#include "systemd/sd-id128.h"
-#include "util.h"
-#include "condition-util.h"
-#include "virt.h"
-#include "path-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "architecture.h"
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
- Condition *c;
-
- assert(type < _CONDITION_TYPE_MAX);
-
- c = new0(Condition, 1);
- if (!c)
- return NULL;
-
- c->type = type;
- c->trigger = trigger;
- c->negate = negate;
-
- if (parameter) {
- c->parameter = strdup(parameter);
- if (!c->parameter) {
- free(c);
- return NULL;
- }
- }
-
- return c;
-}
-
-void condition_free(Condition *c) {
- assert(c);
-
- free(c->parameter);
- free(c);
-}
-
-void condition_free_list(Condition *first) {
- Condition *c, *n;
-
- LIST_FOREACH_SAFE(conditions, c, n, first)
- condition_free(c);
-}
-
-bool condition_test_kernel_command_line(Condition *c) {
- char *line, *word = NULL;
- const char *w, *state;
- bool equal;
- int r;
- size_t l, pl;
- bool found = false;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
-
- r = proc_cmdline(&line);
- if (r < 0)
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- if (r <= 0)
- return c->negate;
-
- equal = !!strchr(c->parameter, '=');
- pl = strlen(c->parameter);
-
- FOREACH_WORD_QUOTED(w, l, line, state) {
-
- free(word);
- word = strndup(w, l);
- if (!word)
- break;
-
- if (equal) {
- if (streq(word, c->parameter)) {
- found = true;
- break;
- }
- } else {
- if (startswith(word, c->parameter) && (word[pl] == '=' || word[pl] == 0)) {
- found = true;
- break;
- }
- }
-
- }
- if (!isempty(state))
- log_warning("Trailing garbage and the end of kernel commandline, ignoring.");
-
- free(word);
- free(line);
-
- return found == !c->negate;
-}
-
-bool condition_test_virtualization(Condition *c) {
- int b, v;
- const char *id;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_VIRTUALIZATION);
-
- v = detect_virtualization(&id);
- if (v < 0) {
- log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
- return c->negate;
- }
-
- /* First, compare with yes/no */
- b = parse_boolean(c->parameter);
-
- if (v > 0 && b > 0)
- return !c->negate;
-
- if (v == 0 && b == 0)
- return !c->negate;
-
- /* Then, compare categorization */
- if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm"))
- return !c->negate;
-
- if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container"))
- return !c->negate;
-
- /* Finally compare id */
- return (v > 0 && streq(c->parameter, id)) == !c->negate;
-}
-
-bool condition_test_architecture(Condition *c) {
- Architecture a, b;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_ARCHITECTURE);
-
- a = uname_architecture();
- if (a < 0)
- return c->negate;
-
- if (streq(c->parameter, "native"))
- b = native_architecture();
- else
- b = architecture_from_string(c->parameter);
-
- if (b < 0)
- return c->negate;
-
- return (a == b) == !c->negate;
-}
-
-bool condition_test_host(Condition *c) {
- _cleanup_free_ char *h = NULL;
- sd_id128_t x, y;
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_HOST);
-
- if (sd_id128_from_string(c->parameter, &x) >= 0) {
-
- r = sd_id128_get_machine(&y);
- if (r < 0)
- return c->negate;
-
- return sd_id128_equal(x, y) == !c->negate;
- }
-
- h = gethostname_malloc();
- if (!h)
- return c->negate;
-
- return (fnmatch(c->parameter, h, FNM_CASEFOLD) == 0) == !c->negate;
-}
-
-bool condition_test_ac_power(Condition *c) {
- int r;
-
- assert(c);
- assert(c->parameter);
- assert(c->type == CONDITION_AC_POWER);
-
- r = parse_boolean(c->parameter);
- if (r < 0)
- return !c->negate;
-
- return ((on_ac_power() != 0) == !!r) == !c->negate;
-}
-
-void condition_dump(Condition *c, FILE *f, const char *prefix) {
- assert(c);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%s\t%s: %s%s%s %s\n",
- prefix,
- condition_type_to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- c->state < 0 ? "failed" : c->state > 0 ? "succeeded" : "untested");
-}
-
-void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
- Condition *c;
-
- LIST_FOREACH(conditions, c, first)
- condition_dump(c, f, prefix);
-}
-
-static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
- [CONDITION_PATH_EXISTS] = "ConditionPathExists",
- [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
- [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
- [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
- [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
- [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
- [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
- [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
- [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
- [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
- [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
- [CONDITION_SECURITY] = "ConditionSecurity",
- [CONDITION_CAPABILITY] = "ConditionCapability",
- [CONDITION_HOST] = "ConditionHost",
- [CONDITION_AC_POWER] = "ConditionACPower",
- [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
- [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
- [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
- [CONDITION_NULL] = "ConditionNull"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
diff --git a/src/shared/condition.c b/src/shared/condition.c
new file mode 100644
index 0000000000..dcbf9a7e86
--- /dev/null
+++ b/src/shared/condition.c
@@ -0,0 +1,527 @@
+/*-*- 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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <fnmatch.h>
+
+#include "sd-id128.h"
+#include "util.h"
+#include "virt.h"
+#include "path-util.h"
+#include "fileio.h"
+#include "unit.h"
+#include "architecture.h"
+#include "smack-util.h"
+#include "apparmor-util.h"
+#include "ima-util.h"
+#include "selinux-util.h"
+#include "audit.h"
+#include "condition.h"
+#include "cap-list.h"
+
+Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
+ Condition *c;
+ int r;
+
+ assert(type >= 0);
+ assert(type < _CONDITION_TYPE_MAX);
+ assert(!parameter == (type == CONDITION_NULL));
+
+ c = new0(Condition, 1);
+ if (!c)
+ return NULL;
+
+ c->type = type;
+ c->trigger = trigger;
+ c->negate = negate;
+
+ r = free_and_strdup(&c->parameter, parameter);
+ if (r < 0) {
+ free(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+void condition_free(Condition *c) {
+ assert(c);
+
+ free(c->parameter);
+ free(c);
+}
+
+void condition_free_list(Condition *first) {
+ Condition *c, *n;
+
+ LIST_FOREACH_SAFE(conditions, c, n, first)
+ condition_free(c);
+}
+
+static int condition_test_kernel_command_line(Condition *c) {
+ _cleanup_free_ char *line = NULL;
+ const char *p;
+ bool equal;
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ equal = !!strchr(c->parameter, '=');
+ p = line;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ bool found;
+
+ r = unquote_first_word(&p, &word, true);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (equal)
+ found = streq(word, c->parameter);
+ else {
+ const char *f;
+
+ f = startswith(word, c->parameter);
+ found = f && (*f == '=' || *f == 0);
+ }
+
+ if (found)
+ return true;
+ }
+
+ return false;
+}
+
+static int condition_test_virtualization(Condition *c) {
+ int b, v;
+ const char *id;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_VIRTUALIZATION);
+
+ v = detect_virtualization(&id);
+ if (v < 0)
+ return v;
+
+ /* First, compare with yes/no */
+ b = parse_boolean(c->parameter);
+
+ if (v > 0 && b > 0)
+ return true;
+
+ if (v == 0 && b == 0)
+ return true;
+
+ /* Then, compare categorization */
+ if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm"))
+ return true;
+
+ if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container"))
+ return true;
+
+ /* Finally compare id */
+ return v > 0 && streq(c->parameter, id);
+}
+
+static int condition_test_architecture(Condition *c) {
+ int a, b;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_ARCHITECTURE);
+
+ a = uname_architecture();
+ if (a < 0)
+ return a;
+
+ if (streq(c->parameter, "native"))
+ b = native_architecture();
+ else
+ b = architecture_from_string(c->parameter);
+ if (b < 0)
+ return b;
+
+ return a == b;
+}
+
+static int condition_test_host(Condition *c) {
+ _cleanup_free_ char *h = NULL;
+ sd_id128_t x, y;
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_HOST);
+
+ if (sd_id128_from_string(c->parameter, &x) >= 0) {
+
+ r = sd_id128_get_machine(&y);
+ if (r < 0)
+ return r;
+
+ return sd_id128_equal(x, y);
+ }
+
+ h = gethostname_malloc();
+ if (!h)
+ return -ENOMEM;
+
+ return fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
+}
+
+static int condition_test_ac_power(Condition *c) {
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_AC_POWER);
+
+ r = parse_boolean(c->parameter);
+ if (r < 0)
+ return r;
+
+ return (on_ac_power() != 0) == !!r;
+}
+
+static int condition_test_security(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_SECURITY);
+
+ if (streq(c->parameter, "selinux"))
+ return mac_selinux_use();
+ if (streq(c->parameter, "smack"))
+ return mac_smack_use();
+ if (streq(c->parameter, "apparmor"))
+ return mac_apparmor_use();
+ if (streq(c->parameter, "audit"))
+ return use_audit();
+ if (streq(c->parameter, "ima"))
+ return use_ima();
+
+ return false;
+}
+
+static int condition_test_capability(Condition *c) {
+ _cleanup_fclose_ FILE *f = NULL;
+ int value;
+ char line[LINE_MAX];
+ unsigned long long capabilities = -1;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_CAPABILITY);
+
+ /* If it's an invalid capability, we don't have it */
+ value = capability_from_name(c->parameter);
+ if (value < 0)
+ return -EINVAL;
+
+ /* If it's a valid capability we default to assume
+ * that we have it */
+
+ f = fopen("/proc/self/status", "re");
+ if (!f)
+ return -errno;
+
+ while (fgets(line, sizeof(line), f)) {
+ truncate_nl(line);
+
+ if (startswith(line, "CapBnd:")) {
+ (void) sscanf(line+7, "%llx", &capabilities);
+ break;
+ }
+ }
+
+ return !!(capabilities & (1ULL << value));
+}
+
+static int condition_test_needs_update(Condition *c) {
+ const char *p;
+ struct stat usr, other;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_NEEDS_UPDATE);
+
+ /* If the file system is read-only we shouldn't suggest an update */
+ if (path_is_read_only_fs(c->parameter) > 0)
+ return false;
+
+ /* Any other failure means we should allow the condition to be true,
+ * so that we rather invoke too many update tools then too
+ * few. */
+
+ if (!path_is_absolute(c->parameter))
+ return true;
+
+ p = strappenda(c->parameter, "/.updated");
+ if (lstat(p, &other) < 0)
+ return true;
+
+ if (lstat("/usr/", &usr) < 0)
+ return true;
+
+ return usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
+ (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec);
+}
+
+static int condition_test_first_boot(Condition *c) {
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_FIRST_BOOT);
+
+ r = parse_boolean(c->parameter);
+ if (r < 0)
+ return r;
+
+ return (access("/run/systemd/first-boot", F_OK) >= 0) == !!r;
+}
+
+static int condition_test_path_exists(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_EXISTS);
+
+ return access(c->parameter, F_OK) >= 0;
+}
+
+static int condition_test_path_exists_glob(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_EXISTS_GLOB);
+
+ return glob_exists(c->parameter) > 0;
+}
+
+static int condition_test_path_is_directory(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_IS_DIRECTORY);
+
+ return is_dir(c->parameter, true) > 0;
+}
+
+static int condition_test_path_is_symbolic_link(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_IS_SYMBOLIC_LINK);
+
+ return is_symlink(c->parameter) > 0;
+}
+
+static int condition_test_path_is_mount_point(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_IS_MOUNT_POINT);
+
+ return path_is_mount_point(c->parameter, true) > 0;
+}
+
+static int condition_test_path_is_read_write(Condition *c) {
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_PATH_IS_READ_WRITE);
+
+ return path_is_read_only_fs(c->parameter) <= 0;
+}
+
+static int condition_test_directory_not_empty(Condition *c) {
+ int r;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_DIRECTORY_NOT_EMPTY);
+
+ r = dir_is_empty(c->parameter);
+ return r <= 0 && r != -ENOENT;
+}
+
+static int condition_test_file_not_empty(Condition *c) {
+ struct stat st;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_FILE_NOT_EMPTY);
+
+ return (stat(c->parameter, &st) >= 0 &&
+ S_ISREG(st.st_mode) &&
+ st.st_size > 0);
+}
+
+static int condition_test_file_is_executable(Condition *c) {
+ struct stat st;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_FILE_IS_EXECUTABLE);
+
+ return (stat(c->parameter, &st) >= 0 &&
+ S_ISREG(st.st_mode) &&
+ (st.st_mode & 0111));
+}
+
+static int condition_test_null(Condition *c) {
+ assert(c);
+ assert(c->type == CONDITION_NULL);
+
+ /* Note that during parsing we already evaluate the string and
+ * store it in c->negate */
+ return true;
+}
+
+int condition_test(Condition *c) {
+
+ static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c) = {
+ [CONDITION_PATH_EXISTS] = condition_test_path_exists,
+ [CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
+ [CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
+ [CONDITION_PATH_IS_SYMBOLIC_LINK] = condition_test_path_is_symbolic_link,
+ [CONDITION_PATH_IS_MOUNT_POINT] = condition_test_path_is_mount_point,
+ [CONDITION_PATH_IS_READ_WRITE] = condition_test_path_is_read_write,
+ [CONDITION_DIRECTORY_NOT_EMPTY] = condition_test_directory_not_empty,
+ [CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
+ [CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
+ [CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
+ [CONDITION_VIRTUALIZATION] = condition_test_virtualization,
+ [CONDITION_SECURITY] = condition_test_security,
+ [CONDITION_CAPABILITY] = condition_test_capability,
+ [CONDITION_HOST] = condition_test_host,
+ [CONDITION_AC_POWER] = condition_test_ac_power,
+ [CONDITION_ARCHITECTURE] = condition_test_architecture,
+ [CONDITION_NEEDS_UPDATE] = condition_test_needs_update,
+ [CONDITION_FIRST_BOOT] = condition_test_first_boot,
+ [CONDITION_NULL] = condition_test_null,
+ };
+
+ int r, b;
+
+ assert(c);
+ assert(c->type >= 0);
+ assert(c->type < _CONDITION_TYPE_MAX);
+
+ r = condition_tests[c->type](c);
+ if (r < 0) {
+ c->result = CONDITION_ERROR;
+ return r;
+ }
+
+ b = (r > 0) == !c->negate;
+ c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
+ return b;
+}
+
+void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+ assert(c);
+ assert(f);
+
+ if (!prefix)
+ prefix = "";
+
+ fprintf(f,
+ "%s\t%s: %s%s%s %s\n",
+ prefix,
+ to_string(c->type),
+ c->trigger ? "|" : "",
+ c->negate ? "!" : "",
+ c->parameter,
+ condition_result_to_string(c->result));
+}
+
+void condition_dump_list(Condition *first, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
+ Condition *c;
+
+ LIST_FOREACH(conditions, c, first)
+ condition_dump(c, f, prefix, to_string);
+}
+
+static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
+ [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
+ [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
+ [CONDITION_HOST] = "ConditionHost",
+ [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
+ [CONDITION_SECURITY] = "ConditionSecurity",
+ [CONDITION_CAPABILITY] = "ConditionCapability",
+ [CONDITION_AC_POWER] = "ConditionACPower",
+ [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
+ [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
+ [CONDITION_PATH_EXISTS] = "ConditionPathExists",
+ [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
+ [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
+ [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
+ [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
+ [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
+ [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
+ [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
+ [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
+ [CONDITION_NULL] = "ConditionNull"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
+
+static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
+ [CONDITION_ARCHITECTURE] = "AssertArchitecture",
+ [CONDITION_VIRTUALIZATION] = "AssertVirtualization",
+ [CONDITION_HOST] = "AssertHost",
+ [CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
+ [CONDITION_SECURITY] = "AssertSecurity",
+ [CONDITION_CAPABILITY] = "AssertCapability",
+ [CONDITION_AC_POWER] = "AssertACPower",
+ [CONDITION_NEEDS_UPDATE] = "AssertNeedsUpdate",
+ [CONDITION_FIRST_BOOT] = "AssertFirstBoot",
+ [CONDITION_PATH_EXISTS] = "AssertPathExists",
+ [CONDITION_PATH_EXISTS_GLOB] = "AssertPathExistsGlob",
+ [CONDITION_PATH_IS_DIRECTORY] = "AssertPathIsDirectory",
+ [CONDITION_PATH_IS_SYMBOLIC_LINK] = "AssertPathIsSymbolicLink",
+ [CONDITION_PATH_IS_MOUNT_POINT] = "AssertPathIsMountPoint",
+ [CONDITION_PATH_IS_READ_WRITE] = "AssertPathIsReadWrite",
+ [CONDITION_DIRECTORY_NOT_EMPTY] = "AssertDirectoryNotEmpty",
+ [CONDITION_FILE_NOT_EMPTY] = "AssertFileNotEmpty",
+ [CONDITION_FILE_IS_EXECUTABLE] = "AssertFileIsExecutable",
+ [CONDITION_NULL] = "AssertNull"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
+
+static const char* const condition_result_table[_CONDITION_RESULT_MAX] = {
+ [CONDITION_UNTESTED] = "untested",
+ [CONDITION_SUCCEEDED] = "succeeded",
+ [CONDITION_FAILED] = "failed",
+ [CONDITION_ERROR] = "error",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(condition_result, ConditionResult);
diff --git a/src/shared/condition-util.h b/src/shared/condition.h
index 047fdbfd86..28d1d94ff4 100644
--- a/src/shared/condition-util.h
+++ b/src/shared/condition.h
@@ -28,6 +28,17 @@
#include "macro.h"
typedef enum ConditionType {
+ CONDITION_ARCHITECTURE,
+ CONDITION_VIRTUALIZATION,
+ CONDITION_HOST,
+ CONDITION_KERNEL_COMMAND_LINE,
+ CONDITION_SECURITY,
+ CONDITION_CAPABILITY,
+ CONDITION_AC_POWER,
+
+ CONDITION_NEEDS_UPDATE,
+ CONDITION_FIRST_BOOT,
+
CONDITION_PATH_EXISTS,
CONDITION_PATH_EXISTS_GLOB,
CONDITION_PATH_IS_DIRECTORY,
@@ -37,29 +48,31 @@ typedef enum ConditionType {
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_FILE_NOT_EMPTY,
CONDITION_FILE_IS_EXECUTABLE,
- CONDITION_KERNEL_COMMAND_LINE,
- CONDITION_VIRTUALIZATION,
- CONDITION_SECURITY,
- CONDITION_CAPABILITY,
- CONDITION_HOST,
- CONDITION_AC_POWER,
- CONDITION_ARCHITECTURE,
- CONDITION_NEEDS_UPDATE,
- CONDITION_FIRST_BOOT,
+
CONDITION_NULL,
+
_CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1
} ConditionType;
+typedef enum ConditionResult {
+ CONDITION_UNTESTED,
+ CONDITION_SUCCEEDED,
+ CONDITION_FAILED,
+ CONDITION_ERROR,
+ _CONDITION_RESULT_MAX,
+ _CONDITION_RESULT_INVALID = -1
+} ConditionResult;
+
typedef struct Condition {
- ConditionType type;
+ ConditionType type:8;
bool trigger:1;
bool negate:1;
- char *parameter;
+ ConditionResult result:6;
- int state;
+ char *parameter;
LIST_FIELDS(struct Condition, conditions);
} Condition;
@@ -68,14 +81,16 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
void condition_free(Condition *c);
void condition_free_list(Condition *c);
-bool condition_test_kernel_command_line(Condition *c);
-bool condition_test_virtualization(Condition *c);
-bool condition_test_architecture(Condition *c);
-bool condition_test_host(Condition *c);
-bool condition_test_ac_power(Condition *c);
+int condition_test(Condition *c);
-void condition_dump(Condition *c, FILE *f, const char *prefix);
-void condition_dump_list(Condition *c, FILE *f, const char *prefix);
+void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
+void condition_dump_list(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
const char* condition_type_to_string(ConditionType t) _const_;
-int condition_type_from_string(const char *s) _pure_;
+ConditionType condition_type_from_string(const char *s) _pure_;
+
+const char* assert_type_to_string(ConditionType t) _const_;
+ConditionType assert_type_from_string(const char *s) _pure_;
+
+const char* condition_result_to_string(ConditionResult r) _const_;
+ConditionResult condition_result_from_string(const char *s) _pure_;
diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c
index e6ee97a978..51f4e0105c 100644
--- a/src/shared/conf-files.c
+++ b/src/shared/conf-files.c
@@ -118,8 +118,8 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
if (r == -ENOMEM) {
return r;
} else if (r < 0)
- log_debug("Failed to search for files in %s: %s",
- *p, strerror(-r));
+ log_debug_errno(r, "Failed to search for files in %s: %m",
+ *p);
}
files = hashmap_get_strv(fh);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index ee6de653e1..5fe983a847 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -27,6 +27,7 @@
#include <netinet/ether.h>
#include "conf-parser.h"
+#include "conf-files.h"
#include "util.h"
#include "macro.h"
#include "strv.h"
@@ -37,10 +38,16 @@
#include "exit-status.h"
#include "sd-messages.h"
-int log_syntax_internal(const char *unit, int level,
- const char *file, unsigned line, const char *func,
- const char *config_file, unsigned config_line,
- int error, const char *format, ...) {
+int log_syntax_internal(
+ const char *unit,
+ int level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *config_file,
+ unsigned config_line,
+ int error,
+ const char *format, ...) {
_cleanup_free_ char *msg = NULL;
int r;
@@ -54,22 +61,22 @@ int log_syntax_internal(const char *unit, int level,
if (unit)
r = log_struct_internal(level,
+ error > 0 ? error : EINVAL,
file, line, func,
getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit,
- MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
+ LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
"CONFIG_FILE=%s", config_file,
"CONFIG_LINE=%u", config_line,
- "ERRNO=%d", error > 0 ? error : EINVAL,
- "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
+ LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
NULL);
else
r = log_struct_internal(level,
+ error > 0 ? error : EINVAL,
file, line, func,
- MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
+ LOG_MESSAGE_ID(SD_MESSAGE_CONFIG_ERROR),
"CONFIG_FILE=%s", config_file,
"CONFIG_LINE=%u", config_line,
- "ERRNO=%d", error > 0 ? error : EINVAL,
- "MESSAGE=[%s:%u] %s", config_file, config_line, msg,
+ LOG_MESSAGE("[%s:%u] %s", config_file, config_line, msg),
NULL);
return r;
@@ -360,7 +367,7 @@ int config_parse(const char *unit,
if (feof(f))
break;
- log_error("Failed to read configuration file '%s': %m", filename);
+ log_error_errno(errno, "Failed to read configuration file '%s': %m", filename);
return -errno;
}
@@ -421,8 +428,8 @@ int config_parse(const char *unit,
if (r < 0) {
if (warn)
- log_warning("Failed to parse file '%s': %s",
- filename, strerror(-r));
+ log_warning_errno(r, "Failed to parse file '%s': %m",
+ filename);
return r;
}
}
@@ -430,6 +437,37 @@ int config_parse(const char *unit,
return 0;
}
+/* Parse each config file in the specified directories. */
+int config_parse_many(const char *conf_file,
+ const char *conf_file_dirs,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata) {
+ _cleanup_strv_free_ char **files = NULL;
+ char **fn;
+ int r;
+
+ r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+ if (r < 0)
+ return r;
+
+ if (conf_file) {
+ r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
+ if (r < 0)
+ return r;
+ }
+
+ STRV_FOREACH(fn, files) {
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
#define DEFINE_PARSER(type, vartype, conv_func) \
int config_parse_##type(const char *unit, \
const char *filename, \
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 62f2a01e5e..2507a44444 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -92,6 +92,14 @@ int config_parse(const char *unit,
bool warn,
void *userdata);
+int config_parse_many(const char *conf_file, /* possibly NULL */
+ const char *conf_file_dirs, /* nulstr */
+ const char *sections, /* nulstr */
+ ConfigItemLookup lookup,
+ const void *table,
+ bool relaxed,
+ void *userdata);
+
/* Generic parsers */
int config_parse_int(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unsigned(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -111,10 +119,16 @@ int config_parse_mode(const char *unit, const char *filename, unsigned line, con
int config_parse_log_facility(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_log_level(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 log_syntax_internal(const char *unit, int level,
- const char *file, unsigned line, const char *func,
- const char *config_file, unsigned config_line,
- int error, const char *format, ...) _printf_(9, 10);
+int log_syntax_internal(
+ const char *unit,
+ int level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *config_file,
+ unsigned config_line,
+ int error,
+ const char *format, ...) _printf_(9, 10);
#define log_syntax(unit, level, config_file, config_line, error, ...) \
log_syntax_internal(unit, level, \
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 3744797b95..b8b1ba1866 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -19,40 +19,65 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/sendfile.h>
+
#include "util.h"
#include "copy.h"
int copy_bytes(int fdf, int fdt, off_t max_bytes) {
+ bool try_sendfile = true;
+
assert(fdf >= 0);
assert(fdt >= 0);
for (;;) {
- char buf[PIPE_BUF];
- ssize_t n, k;
- size_t m = sizeof(buf);
+ size_t m = PIPE_BUF;
+ ssize_t n;
if (max_bytes != (off_t) -1) {
if (max_bytes <= 0)
- return -E2BIG;
+ return -EFBIG;
if ((off_t) m > max_bytes)
m = (size_t) max_bytes;
}
- n = read(fdf, buf, m);
- if (n < 0)
- return -errno;
- if (n == 0)
- break;
+ /* First try sendfile(), unless we already tried */
+ if (try_sendfile) {
+
+ n = sendfile(fdt, fdf, NULL, m);
+ if (n < 0) {
+ if (errno != EINVAL && errno != ENOSYS)
+ return -errno;
+
+ try_sendfile = false;
+ /* use fallback below */
+ } else if (n == 0) /* EOF */
+ break;
+ else if (n > 0)
+ /* Succcess! */
+ goto next;
+ }
+
+ /* As a fallback just copy bits by hand */
+ {
+ char buf[m];
+ int r;
- errno = 0;
- k = loop_write(fdt, buf, n, false);
- if (k < 0)
- return k;
- if (k != n)
- return errno ? -errno : -EIO;
+ n = read(fdf, buf, m);
+ if (n < 0)
+ return -errno;
+ if (n == 0) /* EOF */
+ break;
+
+ r = loop_write(fdt, buf, n, false);
+ if (r < 0)
+ return r;
+
+ }
+ next:
if (max_bytes != (off_t) -1) {
assert(max_bytes >= n);
max_bytes -= n;
@@ -262,34 +287,39 @@ int copy_tree(const char *from, const char *to, bool merge) {
return -ENOTSUP;
}
-int copy_file(const char *from, const char *to, int flags, mode_t mode) {
- _cleanup_close_ int fdf = -1, fdt = -1;
- int r;
+int copy_file_fd(const char *from, int fdt) {
+ _cleanup_close_ int fdf = -1;
assert(from);
- assert(to);
+ assert(fdt >= 0);
fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fdf < 0)
return -errno;
+ return copy_bytes(fdf, fdt, (off_t) -1);
+}
+
+int copy_file(const char *from, const char *to, int flags, mode_t mode) {
+ int fdt, r;
+
+ assert(from);
+ assert(to);
+
fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode);
if (fdt < 0)
return -errno;
- r = copy_bytes(fdf, fdt, (off_t) -1);
+ r = copy_file_fd(from, fdt);
if (r < 0) {
+ close(fdt);
unlink(to);
return r;
}
- r = close(fdt);
- fdt = -1;
-
- if (r < 0) {
- r = -errno;
- unlink(to);
- return r;
+ if (close(fdt) < 0) {
+ unlink_noerrno(to);
+ return -errno;
}
return 0;
diff --git a/src/shared/copy.h b/src/shared/copy.h
index 0bf2598f60..62932112af 100644
--- a/src/shared/copy.h
+++ b/src/shared/copy.h
@@ -21,6 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
+#include <sys/types.h>
+
+int copy_file_fd(const char *from, int to);
int copy_file(const char *from, const char *to, int flags, mode_t mode);
int copy_tree(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, off_t max_bytes);
diff --git a/src/shared/def.h b/src/shared/def.h
index 92394e8183..96c45a6b72 100644
--- a/src/shared/def.h
+++ b/src/shared/def.h
@@ -61,17 +61,17 @@
"/usr/lib/kbd/keymaps/\0"
#endif
-#define UNIX_SYSTEM_BUS_PATH "unix:path=/var/run/dbus/system_bus_socket"
-#define KERNEL_SYSTEM_BUS_PATH "kernel:path=/dev/kdbus/0-system/bus"
+#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
+#define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus"
#ifdef ENABLE_KDBUS
-# define DEFAULT_SYSTEM_BUS_PATH KERNEL_SYSTEM_BUS_PATH ";" UNIX_SYSTEM_BUS_PATH
+# define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS
#else
-# define DEFAULT_SYSTEM_BUS_PATH UNIX_SYSTEM_BUS_PATH
+# define DEFAULT_SYSTEM_BUS_ADDRESS UNIX_SYSTEM_BUS_ADDRESS
#endif
-#define UNIX_USER_BUS_FMT "unix:path=%s/bus"
-#define KERNEL_USER_BUS_FMT "kernel:path=/dev/kdbus/"UID_FMT"-user/bus"
+#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
+#define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus"
#define PLYMOUTH_SOCKET { \
.un.sun_family = AF_UNIX, \
diff --git a/src/shared/env-util.c b/src/shared/env-util.c
index d90b878d19..fbdc73dd2c 100644
--- a/src/shared/env-util.c
+++ b/src/shared/env-util.c
@@ -425,7 +425,7 @@ char **strv_env_clean_log(char **e, const char *unit_id, const char *message) {
if (!env_assignment_is_valid(*p)) {
if (message)
- log_error_unit(unit_id, "Ignoring invalid environment '%s': %s", *p, message);
+ log_unit_error(unit_id, "Ignoring invalid environment '%s': %s", *p, message);
free(*p);
continue;
}
diff --git a/src/shared/ether-addr-util.h b/src/shared/ether-addr-util.h
new file mode 100644
index 0000000000..7033138788
--- /dev/null
+++ b/src/shared/ether-addr-util.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ 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 <net/ethernet.h>
+
+#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]
diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h
index f719580426..1d774f25dc 100644
--- a/src/shared/exit-status.h
+++ b/src/shared/exit-status.h
@@ -78,6 +78,7 @@ typedef enum ExitStatus {
EXIT_MAKE_STARTER,
EXIT_CHOWN,
EXIT_BUS_ENDPOINT,
+ EXIT_SMACK_PROCESS_LABEL,
} ExitStatus;
typedef enum ExitStatusLevel {
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index 38028b972e..ff6b1a7ed7 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -20,12 +20,12 @@
***/
#include <unistd.h>
-#include <sys/sendfile.h>
-#include "fileio.h"
+
#include "util.h"
#include "strv.h"
#include "utf8.h"
#include "ctype.h"
+#include "fileio.h"
int write_string_stream(FILE *f, const char *line) {
assert(f);
@@ -66,7 +66,7 @@ int write_string_file_no_create(const char *fn, const char *line) {
assert(line);
/* We manually build our own version of fopen(..., "we") that
- * without O_CREAT */
+ * works without O_CREAT */
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
@@ -94,20 +94,10 @@ int write_string_file_atomic(const char *fn, const char *line) {
fchmod_umask(fileno(f), 0644);
- errno = 0;
- fputs(line, f);
- if (!endswith(line, "\n"))
- fputc('\n', f);
-
- fflush(f);
-
- if (ferror(f))
- r = errno ? -errno : -EIO;
- else {
+ r = write_string_stream(f, line);
+ if (r >= 0) {
if (rename(p, fn) < 0)
r = -errno;
- else
- r = 0;
}
if (r < 0)
@@ -144,77 +134,6 @@ int read_one_line_file(const char *fn, char **line) {
return 0;
}
-ssize_t sendfile_full(int out_fd, const char *fn) {
- _cleanup_fclose_ FILE *f;
- struct stat st;
- int r;
- ssize_t s;
-
- size_t n, l;
- _cleanup_free_ char *buf = NULL;
-
- assert(out_fd > 0);
- assert(fn);
-
- f = fopen(fn, "re");
- if (!f)
- return -errno;
-
- r = fstat(fileno(f), &st);
- if (r < 0)
- return -errno;
-
- s = sendfile(out_fd, fileno(f), NULL, st.st_size);
- if (s < 0)
- if (errno == EINVAL || errno == ENOSYS) {
- /* continue below */
- } else
- return -errno;
- else
- return s;
-
- /* sendfile() failed, fall back to read/write */
-
- /* Safety check */
- if (st.st_size > 4*1024*1024)
- return -E2BIG;
-
- n = st.st_size > 0 ? st.st_size : LINE_MAX;
- l = 0;
-
- while (true) {
- char *t;
- size_t k;
-
- t = realloc(buf, n);
- if (!t)
- return -ENOMEM;
-
- buf = t;
- k = fread(buf + l, 1, n - l, f);
-
- if (k <= 0) {
- if (ferror(f))
- return -errno;
-
- break;
- }
-
- l += k;
- n *= 2;
-
- /* Safety check */
- if (n > 4*1024*1024)
- return -E2BIG;
- }
-
- r = write(out_fd, buf, l);
- if (r < 0)
- return -errno;
-
- return (ssize_t) l;
-}
-
int read_full_stream(FILE *f, char **contents, size_t *size) {
size_t n, l;
_cleanup_free_ char *buf = NULL;
diff --git a/src/shared/fileio.h b/src/shared/fileio.h
index c256915799..5ae51c1e28 100644
--- a/src/shared/fileio.h
+++ b/src/shared/fileio.h
@@ -33,7 +33,6 @@ int write_string_file_atomic(const char *fn, const char *line);
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);
-ssize_t sendfile_full(int out_fd, const char *fn);
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);
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 414470be1c..465e5f6cc8 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -52,12 +52,10 @@ int generator_write_fsck_deps(
r = fsck_exists(fstype);
if (r == -ENOENT) {
/* treat missing check as essentially OK */
- log_debug("Checking was requested for %s, but fsck.%s does not exist: %s", what, fstype, strerror(-r));
+ log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype);
return 0;
- } else if (r < 0) {
- log_warning("Checking was requested for %s, but fsck.%s cannot be used: %s", what, fstype, strerror(-r));
- return r;
- }
+ } else if (r < 0)
+ return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
}
if (streq(where, "/")) {
@@ -66,10 +64,8 @@ int generator_write_fsck_deps(
lnk = strappenda(dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
mkdir_parents(lnk, 0755);
- if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0) {
- log_error("Failed to create symlink %s: %m", lnk);
- return -errno;
- }
+ if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
} else {
_cleanup_free_ char *fsck = NULL;
diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c
index 6f5f8204dd..5b329e0851 100644
--- a/src/shared/hashmap.c
+++ b/src/shared/hashmap.c
@@ -4,6 +4,7 @@
This file is part of systemd.
Copyright 2010 Lennart Poettering
+ Copyright 2014 Michal Schmidt
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
@@ -26,49 +27,250 @@
#include "util.h"
#include "hashmap.h"
+#include "set.h"
#include "macro.h"
#include "siphash24.h"
+#include "strv.h"
+#include "list.h"
#include "mempool.h"
-#define INITIAL_N_BUCKETS 31
-
-struct hashmap_entry {
+/*
+ * Implementation of hashmaps.
+ * Addressing: open
+ * - uses less RAM compared to closed addressing (chaining), because
+ * our entries are small (especially in Sets, which tend to contain
+ * the majority of entries in systemd).
+ * Collision resolution: Robin Hood
+ * - tends to equalize displacement of entries from their optimal buckets.
+ * Probe sequence: linear
+ * - though theoretically worse than random probing/uniform hashing/double
+ * hashing, it is good for cache locality.
+ *
+ * References:
+ * Celis, P. 1986. Robin Hood Hashing.
+ * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada.
+ * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
+ * - The results are derived for random probing. Suggests deletion with
+ * tombstones and two mean-centered search methods. None of that works
+ * well for linear probing.
+ *
+ * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies.
+ * ACM Trans. Algorithms 1, 2 (October 2005), 177-213.
+ * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964
+ * http://www.math.uu.se/~svante/papers/sj157.pdf
+ * - Applies to Robin Hood with linear probing. Contains remarks on
+ * the unsuitability of mean-centered search with linear probing.
+ *
+ * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing.
+ * ACM Trans. Algorithms 1, 2 (October 2005), 214-242.
+ * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965
+ * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes
+ * in a successful search), and Janson writes about displacement. C = d + 1.
+ *
+ * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion.
+ * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
+ * - Explanation of backward shift deletion with pictures.
+ *
+ * Khuong, P. 2013. The Other Robin Hood Hashing.
+ * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/
+ * - Short summary of random vs. linear probing, and tombstones vs. backward shift.
+ */
+
+/*
+ * XXX Ideas for improvement:
+ * For unordered hashmaps, randomize iteration order, similarly to Perl:
+ * http://blog.booking.com/hardening-perls-hash-function.html
+ */
+
+/* INV_KEEP_FREE = 1 / (1 - max_load_factor)
+ * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */
+#define INV_KEEP_FREE 5U
+
+/* Fields common to entries of all hashmap/set types */
+struct hashmap_base_entry {
const void *key;
+};
+
+/* Entry types for specific hashmap/set types
+ * hashmap_base_entry must be at the beginning of each entry struct. */
+
+struct plain_hashmap_entry {
+ struct hashmap_base_entry b;
void *value;
- struct hashmap_entry *bucket_next, *bucket_previous;
- struct hashmap_entry *iterate_next, *iterate_previous;
};
-struct Hashmap {
- const struct hash_ops *hash_ops;
+struct ordered_hashmap_entry {
+ struct plain_hashmap_entry p;
+ unsigned iterate_next, iterate_previous;
+};
- struct hashmap_entry *iterate_list_head, *iterate_list_tail;
+struct set_entry {
+ struct hashmap_base_entry b;
+};
- struct hashmap_entry ** buckets;
- unsigned n_buckets, n_entries;
+/* In several functions it is advantageous to have the hash table extended
+ * virtually by a couple of additional buckets. We reserve special index values
+ * for these "swap" buckets. */
+#define _IDX_SWAP_BEGIN (UINT_MAX - 3)
+#define IDX_PUT (_IDX_SWAP_BEGIN + 0)
+#define IDX_TMP (_IDX_SWAP_BEGIN + 1)
+#define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2)
- uint8_t hash_key[HASH_KEY_SIZE];
- bool from_pool:1;
+#define IDX_FIRST (UINT_MAX - 1) /* special index for freshly initialized iterators */
+#define IDX_NIL UINT_MAX /* special index value meaning "none" or "end" */
+
+assert_cc(IDX_FIRST == _IDX_SWAP_END);
+assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST);
+
+/* Storage space for the "swap" buckets.
+ * All entry types can fit into a ordered_hashmap_entry. */
+struct swap_entries {
+ struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN];
};
-struct hashmap_tile {
- Hashmap h;
- struct hashmap_entry *initial_buckets[INITIAL_N_BUCKETS];
+/* Distance from Initial Bucket */
+typedef uint8_t dib_raw_t;
+#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */
+#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */
+#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */
+#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
+
+#define DIB_FREE UINT_MAX
+
+#ifdef ENABLE_HASHMAP_DEBUG
+struct hashmap_debug_info {
+ LIST_FIELDS(struct hashmap_debug_info, debug_list);
+ unsigned max_entries; /* high watermark of n_entries */
+
+ /* who allocated this hashmap */
+ int line;
+ const char *file;
+ const char *func;
+
+ /* fields to detect modification while iterating */
+ unsigned put_count; /* counts puts into the hashmap */
+ unsigned rem_count; /* counts removals from hashmap */
+ unsigned last_rem_idx; /* remembers last removal index */
};
-static DEFINE_MEMPOOL(hashmap_pool, struct hashmap_tile, 8);
-static DEFINE_MEMPOOL(hashmap_entry_pool, struct hashmap_entry, 64);
+/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
+static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
-#ifdef VALGRIND
+#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
-__attribute__((destructor)) static void cleanup_pools(void) {
- /* Be nice to valgrind */
+#else /* !ENABLE_HASHMAP_DEBUG */
+#define HASHMAP_DEBUG_FIELDS
+#endif /* ENABLE_HASHMAP_DEBUG */
- mempool_drop(&hashmap_entry_pool);
- mempool_drop(&hashmap_pool);
-}
+enum HashmapType {
+ HASHMAP_TYPE_PLAIN,
+ HASHMAP_TYPE_ORDERED,
+ HASHMAP_TYPE_SET,
+ _HASHMAP_TYPE_MAX
+};
-#endif
+struct _packed_ indirect_storage {
+ char *storage; /* where buckets and DIBs are stored */
+ uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */
+
+ unsigned n_entries; /* number of stored entries */
+ unsigned n_buckets; /* number of buckets */
+
+ unsigned idx_lowest_entry; /* Index below which all buckets are free.
+ Makes "while(hashmap_steal_first())" loops
+ O(n) instead of O(n^2) for unordered hashmaps. */
+ uint8_t _pad[3]; /* padding for the whole HashmapBase */
+ /* The bitfields in HashmapBase complete the alignment of the whole thing. */
+};
+
+struct direct_storage {
+ /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
+ * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
+ * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
+ char storage[sizeof(struct indirect_storage)];
+};
+
+#define DIRECT_BUCKETS(entry_t) \
+ (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t)))
+
+/* We should be able to store at least one entry directly. */
+assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1);
+
+/* We have 3 bits for n_direct_entries. */
+assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
+
+/* Hashmaps with directly stored entries all use this shared hash key.
+ * It's no big deal if the key is guessed, because there can be only
+ * a handful of directly stored entries in a hashmap. When a hashmap
+ * outgrows direct storage, it gets its own key for indirect storage. */
+static uint8_t shared_hash_key[HASH_KEY_SIZE];
+static bool shared_hash_key_initialized;
+
+/* Fields that all hashmap/set types must have */
+struct HashmapBase {
+ const struct hash_ops *hash_ops; /* hash and compare ops to use */
+
+ union _packed_ {
+ struct indirect_storage indirect; /* if has_indirect */
+ struct direct_storage direct; /* if !has_indirect */
+ };
+
+ enum HashmapType type:2; /* HASHMAP_TYPE_* */
+ bool has_indirect:1; /* whether indirect storage is used */
+ unsigned n_direct_entries:3; /* Number of entries in direct storage.
+ * Only valid if !has_indirect. */
+ bool from_pool:1; /* whether was allocated from mempool */
+ HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */
+};
+
+/* Specific hash types
+ * HashmapBase must be at the beginning of each hashmap struct. */
+
+struct Hashmap {
+ struct HashmapBase b;
+};
+
+struct OrderedHashmap {
+ struct HashmapBase b;
+ unsigned iterate_list_head, iterate_list_tail;
+};
+
+struct Set {
+ struct HashmapBase b;
+};
+
+DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8);
+DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8);
+/* No need for a separate Set pool */
+assert_cc(sizeof(Hashmap) == sizeof(Set));
+
+struct hashmap_type_info {
+ size_t head_size;
+ size_t entry_size;
+ struct mempool *mempool;
+ unsigned n_direct_buckets;
+};
+
+static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
+ [HASHMAP_TYPE_PLAIN] = {
+ .head_size = sizeof(Hashmap),
+ .entry_size = sizeof(struct plain_hashmap_entry),
+ .mempool = &hashmap_pool,
+ .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry),
+ },
+ [HASHMAP_TYPE_ORDERED] = {
+ .head_size = sizeof(OrderedHashmap),
+ .entry_size = sizeof(struct ordered_hashmap_entry),
+ .mempool = &ordered_hashmap_pool,
+ .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry),
+ },
+ [HASHMAP_TYPE_SET] = {
+ .head_size = sizeof(Set),
+ .entry_size = sizeof(struct set_entry),
+ .mempool = &hashmap_pool,
+ .n_direct_buckets = DIRECT_BUCKETS(struct set_entry),
+ },
+};
unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
uint64_t u;
@@ -138,9 +340,44 @@ const struct hash_ops devt_hash_ops = {
};
#endif
-static unsigned bucket_hash(Hashmap *h, const void *p) {
- return (unsigned) (h->hash_ops->hash(p, h->hash_key) % h->n_buckets);
+static unsigned n_buckets(HashmapBase *h) {
+ return h->has_indirect ? h->indirect.n_buckets
+ : hashmap_type_info[h->type].n_direct_buckets;
+}
+
+static unsigned n_entries(HashmapBase *h) {
+ return h->has_indirect ? h->indirect.n_entries
+ : h->n_direct_entries;
+}
+
+static void n_entries_inc(HashmapBase *h) {
+ if (h->has_indirect)
+ h->indirect.n_entries++;
+ else
+ h->n_direct_entries++;
+}
+
+static void n_entries_dec(HashmapBase *h) {
+ if (h->has_indirect)
+ h->indirect.n_entries--;
+ else
+ h->n_direct_entries--;
+}
+
+static char *storage_ptr(HashmapBase *h) {
+ return h->has_indirect ? h->indirect.storage
+ : h->direct.storage;
+}
+
+static uint8_t *hash_key(HashmapBase *h) {
+ return h->has_indirect ? h->indirect.hash_key
+ : shared_hash_key;
+}
+
+static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
+ return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h));
}
+#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
static uint8_t current[HASH_KEY_SIZE];
@@ -161,147 +398,484 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
memcpy(hash_key, current, sizeof(current));
}
-Hashmap *hashmap_new(const struct hash_ops *hash_ops) {
- bool b;
- struct hashmap_tile *ht;
- Hashmap *h;
+static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
+ return (struct hashmap_base_entry*)
+ (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
+}
+
+static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
+ return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
+}
+
+static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
+ return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
+}
- b = is_main_thread();
+static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
+ return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
+}
- if (b) {
- ht = mempool_alloc_tile(&hashmap_pool);
- if (!ht)
- return NULL;
+static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) {
+ return &swap->e[idx - _IDX_SWAP_BEGIN];
+}
- memzero(ht, sizeof(struct hashmap_tile));
- } else {
- ht = malloc0(sizeof(struct hashmap_tile));
+/* Returns a pointer to the bucket at index idx.
+ * Understands real indexes and swap indexes, hence "_virtual". */
+static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
+ unsigned idx) {
+ if (idx < _IDX_SWAP_BEGIN)
+ return bucket_at(h, idx);
+
+ if (idx < _IDX_SWAP_END)
+ return &bucket_at_swap(swap, idx)->p.b;
+
+ assert_not_reached("Invalid index");
+}
+
+static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
+ return (dib_raw_t*)
+ (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
+}
+
+static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
+ return idx >= from ? idx - from
+ : n_buckets(h) + idx - from;
+}
+
+static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) {
+ unsigned initial_bucket;
+
+ if (raw_dib == DIB_RAW_FREE)
+ return DIB_FREE;
+
+ if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
+ return raw_dib;
+
+ /*
+ * Having an overflow DIB value is very unlikely. The hash function
+ * would have to be bad. For example, in a table of size 2^24 filled
+ * to load factor 0.9 the maximum observed DIB is only about 60.
+ * In theory (assuming I used Maxima correctly), for an infinite size
+ * hash table with load factor 0.8 the probability of a given entry
+ * having DIB > 40 is 1.9e-8.
+ * This returns the correct DIB value by recomputing the hash value in
+ * the unlikely case. XXX Hitting this case could be a hint to rehash.
+ */
+ initial_bucket = bucket_hash(h, bucket_at(h, idx)->key);
+ return bucket_distance(h, idx, initial_bucket);
+}
+
+static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) {
+ dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
+}
+
+static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
+ dib_raw_t *dibs;
+
+ dibs = dib_raw_ptr(h);
+
+ for ( ; idx < n_buckets(h); idx++)
+ if (dibs[idx] != DIB_RAW_FREE)
+ return idx;
+
+ return IDX_NIL;
+}
+
+static void bucket_mark_free(HashmapBase *h, unsigned idx) {
+ memset(bucket_at(h, idx), 0, hashmap_type_info[h->type].entry_size);
+ bucket_set_dib(h, idx, DIB_FREE);
+}
+
+static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap,
+ unsigned from, unsigned to) {
+ struct hashmap_base_entry *e_from, *e_to;
+
+ assert(from != to);
- if (!ht)
- return NULL;
+ e_from = bucket_at_virtual(h, swap, from);
+ e_to = bucket_at_virtual(h, swap, to);
+
+ memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
+
+ if (h->type == HASHMAP_TYPE_ORDERED) {
+ OrderedHashmap *lh = (OrderedHashmap*) h;
+ struct ordered_hashmap_entry *le, *le_to;
+
+ le_to = (struct ordered_hashmap_entry*) e_to;
+
+ if (le_to->iterate_next != IDX_NIL) {
+ le = (struct ordered_hashmap_entry*)
+ bucket_at_virtual(h, swap, le_to->iterate_next);
+ le->iterate_previous = to;
+ }
+
+ if (le_to->iterate_previous != IDX_NIL) {
+ le = (struct ordered_hashmap_entry*)
+ bucket_at_virtual(h, swap, le_to->iterate_previous);
+ le->iterate_next = to;
+ }
+
+ if (lh->iterate_list_head == from)
+ lh->iterate_list_head = to;
+ if (lh->iterate_list_tail == from)
+ lh->iterate_list_tail = to;
}
+}
- h = &ht->h;
- h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops;
+static unsigned next_idx(HashmapBase *h, unsigned idx) {
+ return (idx + 1U) % n_buckets(h);
+}
- h->n_buckets = INITIAL_N_BUCKETS;
- h->n_entries = 0;
- h->iterate_list_head = h->iterate_list_tail = NULL;
+static unsigned prev_idx(HashmapBase *h, unsigned idx) {
+ return (n_buckets(h) + idx - 1U) % n_buckets(h);
+}
- h->buckets = ht->initial_buckets;
+static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
+ switch (h->type) {
- h->from_pool = b;
+ case HASHMAP_TYPE_PLAIN:
+ case HASHMAP_TYPE_ORDERED:
+ return ((struct plain_hashmap_entry*)e)->value;
- get_hash_key(h->hash_key, true);
+ case HASHMAP_TYPE_SET:
+ return (void*) e->key;
- return h;
+ default:
+ assert_not_reached("Unknown hashmap type");
+ }
}
-int hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops) {
- Hashmap *q;
+static void base_remove_entry(HashmapBase *h, unsigned idx) {
+ unsigned left, right, prev, dib;
+ dib_raw_t raw_dib, *dibs;
- assert(h);
+ dibs = dib_raw_ptr(h);
+ assert(dibs[idx] != DIB_RAW_FREE);
- if (*h)
- return 0;
+#ifdef ENABLE_HASHMAP_DEBUG
+ h->debug.rem_count++;
+ h->debug.last_rem_idx = idx;
+#endif
- q = hashmap_new(hash_ops);
- if (!q)
- return -ENOMEM;
+ left = idx;
+ /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
+ for (right = next_idx(h, left); ; right = next_idx(h, right)) {
+ raw_dib = dibs[right];
+ if (raw_dib == 0 || raw_dib == DIB_RAW_FREE)
+ break;
+
+ /* The buckets are not supposed to be all occupied and with DIB > 0.
+ * That would mean we could make everyone better off by shifting them
+ * backward. This scenario is impossible. */
+ assert(left != right);
+ }
- *h = q;
- return 0;
+ if (h->type == HASHMAP_TYPE_ORDERED) {
+ OrderedHashmap *lh = (OrderedHashmap*) h;
+ struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
+
+ if (le->iterate_next != IDX_NIL)
+ ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
+ else
+ lh->iterate_list_tail = le->iterate_previous;
+
+ if (le->iterate_previous != IDX_NIL)
+ ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
+ else
+ lh->iterate_list_head = le->iterate_next;
+ }
+
+ /* Now shift all buckets in the interval (left, right) one step backwards */
+ for (prev = left, left = next_idx(h, left); left != right;
+ prev = left, left = next_idx(h, left)) {
+ dib = bucket_calculate_dib(h, left, dibs[left]);
+ assert(dib != 0);
+ bucket_move_entry(h, NULL, left, prev);
+ bucket_set_dib(h, prev, dib - 1);
+ }
+
+ bucket_mark_free(h, prev);
+ n_entries_dec(h);
}
+#define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx)
+
+static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) {
+ struct ordered_hashmap_entry *e;
+ unsigned idx;
-static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
assert(h);
- assert(e);
-
- /* Insert into hash table */
- e->bucket_next = h->buckets[hash];
- e->bucket_previous = NULL;
- if (h->buckets[hash])
- h->buckets[hash]->bucket_previous = e;
- h->buckets[hash] = e;
-
- /* Insert into iteration list */
- e->iterate_previous = h->iterate_list_tail;
- e->iterate_next = NULL;
- if (h->iterate_list_tail) {
- assert(h->iterate_list_head);
- h->iterate_list_tail->iterate_next = e;
+ assert(i);
+
+ if (i->idx == IDX_NIL)
+ goto at_end;
+
+ if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
+ goto at_end;
+
+ if (i->idx == IDX_FIRST) {
+ idx = h->iterate_list_head;
+ e = ordered_bucket_at(h, idx);
} else {
- assert(!h->iterate_list_head);
- h->iterate_list_head = e;
+ idx = i->idx;
+ e = ordered_bucket_at(h, idx);
+ /*
+ * We allow removing the current entry while iterating, but removal may cause
+ * a backward shift. The next entry may thus move one bucket to the left.
+ * To detect when it happens, we remember the key pointer of the entry we were
+ * going to iterate next. If it does not match, there was a backward shift.
+ */
+ if (e->p.b.key != i->next_key) {
+ idx = prev_idx(HASHMAP_BASE(h), idx);
+ e = ordered_bucket_at(h, idx);
+ }
+ assert(e->p.b.key == i->next_key);
}
- h->iterate_list_tail = e;
- h->n_entries++;
- assert(h->n_entries >= 1);
+#ifdef ENABLE_HASHMAP_DEBUG
+ i->prev_idx = idx;
+#endif
+
+ if (e->iterate_next != IDX_NIL) {
+ struct ordered_hashmap_entry *n;
+ i->idx = e->iterate_next;
+ n = ordered_bucket_at(h, i->idx);
+ i->next_key = n->p.b.key;
+ } else
+ i->idx = IDX_NIL;
+
+ return idx;
+
+at_end:
+ i->idx = IDX_NIL;
+ return IDX_NIL;
}
-static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) {
+static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
+ unsigned idx;
+
assert(h);
- assert(e);
+ assert(i);
- /* Remove from iteration list */
- if (e->iterate_next)
- e->iterate_next->iterate_previous = e->iterate_previous;
- else
- h->iterate_list_tail = e->iterate_previous;
+ if (i->idx == IDX_NIL)
+ goto at_end;
- if (e->iterate_previous)
- e->iterate_previous->iterate_next = e->iterate_next;
- else
- h->iterate_list_head = e->iterate_next;
+ if (i->idx == IDX_FIRST) {
+ /* fast forward to the first occupied bucket */
+ if (h->has_indirect) {
+ i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
+ h->indirect.idx_lowest_entry = i->idx;
+ } else
+ i->idx = skip_free_buckets(h, 0);
+
+ if (i->idx == IDX_NIL)
+ goto at_end;
+ } else {
+ struct hashmap_base_entry *e;
+
+ assert(i->idx > 0);
- /* Remove from hash table bucket list */
- if (e->bucket_next)
- e->bucket_next->bucket_previous = e->bucket_previous;
+ e = bucket_at(h, i->idx);
+ /*
+ * We allow removing the current entry while iterating, but removal may cause
+ * a backward shift. The next entry may thus move one bucket to the left.
+ * To detect when it happens, we remember the key pointer of the entry we were
+ * going to iterate next. If it does not match, there was a backward shift.
+ */
+ if (e->key != i->next_key)
+ e = bucket_at(h, --i->idx);
- if (e->bucket_previous)
- e->bucket_previous->bucket_next = e->bucket_next;
+ assert(e->key == i->next_key);
+ }
+
+ idx = i->idx;
+#ifdef ENABLE_HASHMAP_DEBUG
+ i->prev_idx = idx;
+#endif
+
+ i->idx = skip_free_buckets(h, i->idx + 1);
+ if (i->idx != IDX_NIL)
+ i->next_key = bucket_at(h, i->idx)->key;
else
- h->buckets[hash] = e->bucket_next;
+ i->idx = IDX_NIL;
+
+ return idx;
- assert(h->n_entries >= 1);
- h->n_entries--;
+at_end:
+ i->idx = IDX_NIL;
+ return IDX_NIL;
}
-static void remove_entry(Hashmap *h, struct hashmap_entry *e) {
- unsigned hash;
+static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
+ if (!h) {
+ i->idx = IDX_NIL;
+ return IDX_NIL;
+ }
- assert(h);
- assert(e);
+#ifdef ENABLE_HASHMAP_DEBUG
+ if (i->idx == IDX_FIRST) {
+ i->put_count = h->debug.put_count;
+ i->rem_count = h->debug.rem_count;
+ } else {
+ /* While iterating, must not add any new entries */
+ assert(i->put_count == h->debug.put_count);
+ /* ... or remove entries other than the current one */
+ assert(i->rem_count == h->debug.rem_count ||
+ (i->rem_count == h->debug.rem_count - 1 &&
+ i->prev_idx == h->debug.last_rem_idx));
+ /* Reset our removals counter */
+ i->rem_count = h->debug.rem_count;
+ }
+#endif
- hash = bucket_hash(h, e->key);
- unlink_entry(h, e, hash);
+ return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i)
+ : hashmap_iterate_in_internal_order(h, i);
+}
- if (h->from_pool)
- mempool_free_tile(&hashmap_entry_pool, e);
- else
- free(e);
+void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key) {
+ struct hashmap_base_entry *e;
+ void *data;
+ unsigned idx;
+
+ idx = hashmap_iterate_entry(h, i);
+ if (idx == IDX_NIL) {
+ if (key)
+ *key = NULL;
+
+ return NULL;
+ }
+
+ e = bucket_at(h, idx);
+ data = entry_value(h, e);
+ if (key)
+ *key = e->key;
+
+ return data;
+}
+
+void *set_iterate(Set *s, Iterator *i) {
+ return internal_hashmap_iterate(HASHMAP_BASE(s), i, NULL);
}
-void hashmap_free(Hashmap*h) {
+#define HASHMAP_FOREACH_IDX(idx, h, i) \
+ for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
+ (idx != IDX_NIL); \
+ (idx) = hashmap_iterate_entry((h), &(i)))
- /* Free the hashmap, but nothing in it */
+static void reset_direct_storage(HashmapBase *h) {
+ const struct hashmap_type_info *hi = &hashmap_type_info[h->type];
+ void *p;
+
+ assert(!h->has_indirect);
+
+ p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets);
+ memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
+}
+
+static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+ HashmapBase *h;
+ const struct hashmap_type_info *hi = &hashmap_type_info[type];
+ bool use_pool;
+
+ use_pool = is_main_thread();
+
+ h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
if (!h)
- return;
+ return NULL;
+
+ h->type = type;
+ h->from_pool = use_pool;
+ h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops;
+
+ if (type == HASHMAP_TYPE_ORDERED) {
+ OrderedHashmap *lh = (OrderedHashmap*)h;
+ lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
+ }
+
+ reset_direct_storage(h);
+
+ if (!shared_hash_key_initialized) {
+ random_bytes(shared_hash_key, sizeof(shared_hash_key));
+ shared_hash_key_initialized= true;
+ }
+
+#ifdef ENABLE_HASHMAP_DEBUG
+ LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
+ h->debug.func = func;
+ h->debug.file = file;
+ h->debug.line = line;
+#endif
+
+ return h;
+}
+
+Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+}
+
+OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+}
+
+Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+}
+
+static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
+ enum HashmapType type HASHMAP_DEBUG_PARAMS) {
+ HashmapBase *q;
+
+ assert(h);
+
+ if (*h)
+ return 0;
+
+ q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
+ if (!q)
+ return -ENOMEM;
+
+ *h = q;
+ return 0;
+}
+
+int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
+}
+
+int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
+}
+
+int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
+ return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
+}
- hashmap_clear(h);
+static void hashmap_free_no_clear(HashmapBase *h) {
+ assert(!h->has_indirect);
+ assert(!h->n_direct_entries);
- if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))))
- free(h->buckets);
+#ifdef ENABLE_HASHMAP_DEBUG
+ LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
+#endif
if (h->from_pool)
- mempool_free_tile(&hashmap_pool, container_of(h, struct hashmap_tile, h));
+ mempool_free_tile(hashmap_type_info[h->type].mempool, h);
else
free(h);
}
-void hashmap_free_free(Hashmap *h) {
+void internal_hashmap_free(HashmapBase *h) {
+
+ /* Free the hashmap, but nothing in it */
+
+ if (!h)
+ return;
+
+ internal_hashmap_clear(h);
+ hashmap_free_no_clear(h);
+}
+
+void internal_hashmap_free_free(HashmapBase *h) {
/* Free the hashmap and all data objects in it, but not the
* keys */
@@ -309,8 +883,8 @@ void hashmap_free_free(Hashmap *h) {
if (!h)
return;
- hashmap_clear_free(h);
- hashmap_free(h);
+ internal_hashmap_clear_free(h);
+ hashmap_free_no_clear(h);
}
void hashmap_free_free_free(Hashmap *h) {
@@ -321,258 +895,499 @@ void hashmap_free_free_free(Hashmap *h) {
return;
hashmap_clear_free_free(h);
- hashmap_free(h);
+ hashmap_free_no_clear(HASHMAP_BASE(h));
}
-void hashmap_clear(Hashmap *h) {
+void internal_hashmap_clear(HashmapBase *h) {
if (!h)
return;
- while (h->iterate_list_head)
- remove_entry(h, h->iterate_list_head);
+ if (h->has_indirect) {
+ free(h->indirect.storage);
+ h->has_indirect = false;
+ }
+
+ h->n_direct_entries = 0;
+ reset_direct_storage(h);
+
+ if (h->type == HASHMAP_TYPE_ORDERED) {
+ OrderedHashmap *lh = (OrderedHashmap*) h;
+ lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
+ }
}
-void hashmap_clear_free(Hashmap *h) {
- void *p;
+void internal_hashmap_clear_free(HashmapBase *h) {
+ unsigned idx;
if (!h)
return;
- while ((p = hashmap_steal_first(h)))
- free(p);
+ for (idx = skip_free_buckets(h, 0); idx != IDX_NIL;
+ idx = skip_free_buckets(h, idx + 1))
+ free(entry_value(h, bucket_at(h, idx)));
+
+ internal_hashmap_clear(h);
}
void hashmap_clear_free_free(Hashmap *h) {
+ unsigned idx;
+
if (!h)
return;
- while (h->iterate_list_head) {
- void *a, *b;
-
- a = h->iterate_list_head->value;
- b = (void*) h->iterate_list_head->key;
- remove_entry(h, h->iterate_list_head);
- free(a);
- free(b);
+ for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL;
+ idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) {
+ struct plain_hashmap_entry *e = plain_bucket_at(h, idx);
+ free((void*)e->b.key);
+ free(e->value);
}
+
+ internal_hashmap_clear(HASHMAP_BASE(h));
}
-static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
- struct hashmap_entry *e;
- assert(h);
- assert(hash < h->n_buckets);
+static int resize_buckets(HashmapBase *h, unsigned entries_add);
+
+/*
+ * Finds an empty bucket to put an entry into, starting the scan at 'idx'.
+ * Performs Robin Hood swaps as it goes. The entry to put must be placed
+ * by the caller into swap slot IDX_PUT.
+ * If used for in-place resizing, may leave a displaced entry in swap slot
+ * IDX_PUT. Caller must rehash it next.
+ * Returns: true if it left a displaced entry to rehash next in IDX_PUT,
+ * false otherwise.
+ */
+static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
+ struct swap_entries *swap) {
+ dib_raw_t raw_dib, *dibs;
+ unsigned dib, distance;
+
+#ifdef ENABLE_HASHMAP_DEBUG
+ h->debug.put_count++;
+#endif
+
+ dibs = dib_raw_ptr(h);
+
+ for (distance = 0; ; distance++) {
+ raw_dib = dibs[idx];
+ if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) {
+ if (raw_dib == DIB_RAW_REHASH)
+ bucket_move_entry(h, swap, idx, IDX_TMP);
- for (e = h->buckets[hash]; e; e = e->bucket_next)
- if (h->hash_ops->compare(e->key, key) == 0)
- return e;
+ if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
+ h->indirect.idx_lowest_entry = idx;
- return NULL;
+ bucket_set_dib(h, idx, distance);
+ bucket_move_entry(h, swap, IDX_PUT, idx);
+ if (raw_dib == DIB_RAW_REHASH) {
+ bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
+ return true;
+ }
+
+ return false;
+ }
+
+ dib = bucket_calculate_dib(h, idx, raw_dib);
+
+ if (dib < distance) {
+ /* Found a wealthier entry. Go Robin Hood! */
+
+ bucket_set_dib(h, idx, distance);
+
+ /* swap the entries */
+ bucket_move_entry(h, swap, idx, IDX_TMP);
+ bucket_move_entry(h, swap, IDX_PUT, idx);
+ bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
+
+ distance = dib;
+ }
+
+ idx = next_idx(h, idx);
+ }
}
-static int resize_buckets(Hashmap *h, unsigned entries_add) {
- struct hashmap_entry **n, *i;
- unsigned m, new_n_entries, new_n_buckets;
- uint8_t nkey[HASH_KEY_SIZE];
+/*
+ * Puts an entry into a hashmap, boldly - no check whether key already exists.
+ * The caller must place the entry (only its key and value, not link indexes)
+ * in swap slot IDX_PUT.
+ * Caller must ensure: the key does not exist yet in the hashmap.
+ * that resize is not needed if !may_resize.
+ * Returns: 1 if entry was put successfully.
+ * -ENOMEM if may_resize==true and resize failed with -ENOMEM.
+ * Cannot return -ENOMEM if !may_resize.
+ */
+static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
+ struct swap_entries *swap, bool may_resize) {
+ struct ordered_hashmap_entry *new_entry;
+ int r;
+
+ assert(idx < n_buckets(h));
+
+ new_entry = bucket_at_swap(swap, IDX_PUT);
+
+ if (may_resize) {
+ r = resize_buckets(h, 1);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ idx = bucket_hash(h, new_entry->p.b.key);
+ }
+ assert(n_entries(h) < n_buckets(h));
+
+ if (h->type == HASHMAP_TYPE_ORDERED) {
+ OrderedHashmap *lh = (OrderedHashmap*) h;
+
+ new_entry->iterate_next = IDX_NIL;
+ new_entry->iterate_previous = lh->iterate_list_tail;
+
+ if (lh->iterate_list_tail != IDX_NIL) {
+ struct ordered_hashmap_entry *old_tail;
+
+ old_tail = ordered_bucket_at(lh, lh->iterate_list_tail);
+ assert(old_tail->iterate_next == IDX_NIL);
+ old_tail->iterate_next = IDX_PUT;
+ }
+
+ lh->iterate_list_tail = IDX_PUT;
+ if (lh->iterate_list_head == IDX_NIL)
+ lh->iterate_list_head = IDX_PUT;
+ }
+
+ assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
+
+ n_entries_inc(h);
+#ifdef ENABLE_HASHMAP_DEBUG
+ h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
+#endif
+
+ return 1;
+}
+#define hashmap_put_boldly(h, idx, swap, may_resize) \
+ hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize)
+
+/*
+ * Returns 0 if resize is not needed.
+ * 1 if succesfully resized.
+ * -ENOMEM on allocation failure.
+ */
+static int resize_buckets(HashmapBase *h, unsigned entries_add) {
+ struct swap_entries swap;
+ char *new_storage;
+ dib_raw_t *old_dibs, *new_dibs;
+ const struct hashmap_type_info *hi;
+ unsigned idx, optimal_idx;
+ unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
+ uint8_t new_shift;
+ bool rehash_next;
assert(h);
- new_n_entries = h->n_entries + entries_add;
+ hi = &hashmap_type_info[h->type];
+ new_n_entries = n_entries(h) + entries_add;
/* overflow? */
- if (_unlikely_(new_n_entries < entries_add || new_n_entries > UINT_MAX / 4))
+ if (_unlikely_(new_n_entries < entries_add))
return -ENOMEM;
- new_n_buckets = new_n_entries * 4 / 3;
-
- if (_likely_(new_n_buckets <= h->n_buckets))
+ /* For direct storage we allow 100% load, because it's tiny. */
+ if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets)
return 0;
- /* Increase by four at least */
- m = MAX((h->n_entries+1)*4-1, new_n_buckets);
-
- /* If we hit OOM we simply risk packed hashmaps... */
- n = new0(struct hashmap_entry*, m);
- if (!n)
+ /*
+ * Load factor = n/m = 1 - (1/INV_KEEP_FREE).
+ * From it follows: m = n + n/(INV_KEEP_FREE - 1)
+ */
+ new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1);
+ /* overflow? */
+ if (_unlikely_(new_n_buckets < new_n_entries))
return -ENOMEM;
- /* Let's use a different randomized hash key for the
- * extension, so that people cannot guess what we are using
- * here forever */
- get_hash_key(nkey, false);
+ if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t))))
+ return -ENOMEM;
- for (i = h->iterate_list_head; i; i = i->iterate_next) {
- unsigned long old_bucket, new_bucket;
+ old_n_buckets = n_buckets(h);
- old_bucket = h->hash_ops->hash(i->key, h->hash_key) % h->n_buckets;
+ if (_likely_(new_n_buckets <= old_n_buckets))
+ return 0;
- /* First, drop from old bucket table */
- if (i->bucket_next)
- i->bucket_next->bucket_previous = i->bucket_previous;
+ new_shift = log2u_round_up(MAX(
+ new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)),
+ 2 * sizeof(struct direct_storage)));
- if (i->bucket_previous)
- i->bucket_previous->bucket_next = i->bucket_next;
- else
- h->buckets[old_bucket] = i->bucket_next;
+ /* Realloc storage (buckets and DIB array). */
+ new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL,
+ 1U << new_shift);
+ if (!new_storage)
+ return -ENOMEM;
- /* Then, add to new backet table */
- new_bucket = h->hash_ops->hash(i->key, nkey) % m;
+ /* Must upgrade direct to indirect storage. */
+ if (!h->has_indirect) {
+ memcpy(new_storage, h->direct.storage,
+ old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
+ h->indirect.n_entries = h->n_direct_entries;
+ h->indirect.idx_lowest_entry = 0;
+ h->n_direct_entries = 0;
+ }
- i->bucket_next = n[new_bucket];
- i->bucket_previous = NULL;
- if (n[new_bucket])
- n[new_bucket]->bucket_previous = i;
- n[new_bucket] = i;
+ /* Get a new hash key. If we've just upgraded to indirect storage,
+ * allow reusing a previously generated key. It's still a different key
+ * from the shared one that we used for direct storage. */
+ get_hash_key(h->indirect.hash_key, !h->has_indirect);
+
+ h->has_indirect = true;
+ h->indirect.storage = new_storage;
+ h->indirect.n_buckets = (1U << new_shift) /
+ (hi->entry_size + sizeof(dib_raw_t));
+
+ old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets);
+ new_dibs = dib_raw_ptr(h);
+
+ /*
+ * Move the DIB array to the new place, replacing valid DIB values with
+ * DIB_RAW_REHASH to indicate all of the used buckets need rehashing.
+ * Note: Overlap is not possible, because we have at least doubled the
+ * number of buckets and dib_raw_t is smaller than any entry type.
+ */
+ for (idx = 0; idx < old_n_buckets; idx++) {
+ assert(old_dibs[idx] != DIB_RAW_REHASH);
+ new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
+ : DIB_RAW_REHASH;
}
- if (h->buckets != (struct hashmap_entry**) ((uint8_t*) h + ALIGN(sizeof(Hashmap))))
- free(h->buckets);
+ /* Zero the area of newly added entries (including the old DIB area) */
+ memset(bucket_at(h, old_n_buckets), 0,
+ (n_buckets(h) - old_n_buckets) * hi->entry_size);
- h->buckets = n;
- h->n_buckets = m;
+ /* The upper half of the new DIB array needs initialization */
+ memset(&new_dibs[old_n_buckets], DIB_RAW_INIT,
+ (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
- memcpy(h->hash_key, nkey, HASH_KEY_SIZE);
+ /* Rehash entries that need it */
+ n_rehashed = 0;
+ for (idx = 0; idx < old_n_buckets; idx++) {
+ if (new_dibs[idx] != DIB_RAW_REHASH)
+ continue;
- return 1;
-}
+ optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
-static int __hashmap_put(Hashmap *h, const void *key, void *value, unsigned hash) {
- /* For when we know no such entry exists yet */
+ /*
+ * Not much to do if by luck the entry hashes to its current
+ * location. Just set its DIB.
+ */
+ if (optimal_idx == idx) {
+ new_dibs[idx] = 0;
+ n_rehashed++;
+ continue;
+ }
+
+ new_dibs[idx] = DIB_RAW_FREE;
+ bucket_move_entry(h, &swap, idx, IDX_PUT);
+ /* bucket_move_entry does not clear the source */
+ memset(bucket_at(h, idx), 0, hi->entry_size);
+
+ do {
+ /*
+ * Find the new bucket for the current entry. This may make
+ * another entry homeless and load it into IDX_PUT.
+ */
+ rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap);
+ n_rehashed++;
+
+ /* Did the current entry displace another one? */
+ if (rehash_next)
+ optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key);
+ } while (rehash_next);
+ }
- struct hashmap_entry *e;
+ assert(n_rehashed == n_entries(h));
- if (resize_buckets(h, 1) > 0)
- hash = bucket_hash(h, key);
+ return 1;
+}
- if (h->from_pool)
- e = mempool_alloc_tile(&hashmap_entry_pool);
- else
- e = new(struct hashmap_entry, 1);
+/*
+ * Finds an entry with a matching key
+ * Returns: index of the found entry, or IDX_NIL if not found.
+ */
+static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) {
+ struct hashmap_base_entry *e;
+ unsigned dib, distance;
+ dib_raw_t *dibs = dib_raw_ptr(h);
- if (!e)
- return -ENOMEM;
+ assert(idx < n_buckets(h));
- e->key = key;
- e->value = value;
+ for (distance = 0; ; distance++) {
+ if (dibs[idx] == DIB_RAW_FREE)
+ return IDX_NIL;
- link_entry(h, e, hash);
+ dib = bucket_calculate_dib(h, idx, dibs[idx]);
- return 1;
+ if (dib < distance)
+ return IDX_NIL;
+ if (dib == distance) {
+ e = bucket_at(h, idx);
+ if (h->hash_ops->compare(e->key, key) == 0)
+ return idx;
+ }
+
+ idx = next_idx(h, idx);
+ }
}
+#define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key)
int hashmap_put(Hashmap *h, const void *key, void *value) {
- struct hashmap_entry *e;
- unsigned hash;
+ struct swap_entries swap;
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
assert(h);
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (e) {
+ idx = bucket_scan(h, hash, key);
+ if (idx != IDX_NIL) {
+ e = plain_bucket_at(h, idx);
if (e->value == value)
return 0;
return -EEXIST;
}
- return __hashmap_put(h, key, value, hash);
+ e = &bucket_at_swap(&swap, IDX_PUT)->p;
+ e->b.key = key;
+ e->value = value;
+ return hashmap_put_boldly(h, hash, &swap, true);
+}
+
+int set_put(Set *s, const void *key) {
+ struct swap_entries swap;
+ struct hashmap_base_entry *e;
+ unsigned hash, idx;
+
+ assert(s);
+
+ hash = bucket_hash(s, key);
+ idx = bucket_scan(s, hash, key);
+ if (idx != IDX_NIL)
+ return 0;
+
+ e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
+ e->key = key;
+ return hashmap_put_boldly(s, hash, &swap, true);
}
int hashmap_replace(Hashmap *h, const void *key, void *value) {
- struct hashmap_entry *e;
- unsigned hash;
+ struct swap_entries swap;
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
assert(h);
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (e) {
- e->key = key;
+ idx = bucket_scan(h, hash, key);
+ if (idx != IDX_NIL) {
+ e = plain_bucket_at(h, idx);
+#ifdef ENABLE_HASHMAP_DEBUG
+ /* Although the key is equal, the key pointer may have changed,
+ * and this would break our assumption for iterating. So count
+ * this operation as incompatible with iteration. */
+ if (e->b.key != key) {
+ h->b.debug.put_count++;
+ h->b.debug.rem_count++;
+ h->b.debug.last_rem_idx = idx;
+ }
+#endif
+ e->b.key = key;
e->value = value;
return 0;
}
- return __hashmap_put(h, key, value, hash);
+ e = &bucket_at_swap(&swap, IDX_PUT)->p;
+ e->b.key = key;
+ e->value = value;
+ return hashmap_put_boldly(h, hash, &swap, true);
}
int hashmap_update(Hashmap *h, const void *key, void *value) {
- struct hashmap_entry *e;
- unsigned hash;
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
assert(h);
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return -ENOENT;
+ e = plain_bucket_at(h, idx);
e->value = value;
return 0;
}
-void* hashmap_get(Hashmap *h, const void *key) {
- unsigned hash;
- struct hashmap_entry *e;
+void *internal_hashmap_get(HashmapBase *h, const void *key) {
+ struct hashmap_base_entry *e;
+ unsigned hash, idx;
if (!h)
return NULL;
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return NULL;
- return e->value;
+ e = bucket_at(h, idx);
+ return entry_value(h, e);
}
-void* hashmap_get2(Hashmap *h, const void *key, void **key2) {
- unsigned hash;
- struct hashmap_entry *e;
+void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
if (!h)
return NULL;
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return NULL;
+ e = plain_bucket_at(h, idx);
if (key2)
- *key2 = (void*) e->key;
+ *key2 = (void*) e->b.key;
return e->value;
}
-bool hashmap_contains(Hashmap *h, const void *key) {
+bool internal_hashmap_contains(HashmapBase *h, const void *key) {
unsigned hash;
if (!h)
return false;
hash = bucket_hash(h, key);
- return !!hash_scan(h, hash, key);
+ return bucket_scan(h, hash, key) != IDX_NIL;
}
-void* hashmap_remove(Hashmap *h, const void *key) {
- struct hashmap_entry *e;
- unsigned hash;
+void *internal_hashmap_remove(HashmapBase *h, const void *key) {
+ struct hashmap_base_entry *e;
+ unsigned hash, idx;
void *data;
if (!h)
return NULL;
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return NULL;
- data = e->value;
- remove_entry(h, e);
+ e = bucket_at(h, idx);
+ data = entry_value(h, e);
+ remove_entry(h, idx);
return data;
}
-void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
- struct hashmap_entry *e;
- unsigned hash;
+void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
void *data;
if (!h) {
@@ -582,228 +1397,249 @@ void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
}
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e) {
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL) {
if (rkey)
*rkey = NULL;
return NULL;
}
+ e = plain_bucket_at(h, idx);
data = e->value;
if (rkey)
- *rkey = (void*) e->key;
+ *rkey = (void*) e->b.key;
- remove_entry(h, e);
+ remove_entry(h, idx);
return data;
}
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
- struct hashmap_entry *e;
- unsigned old_hash, new_hash;
+ struct swap_entries swap;
+ struct plain_hashmap_entry *e;
+ unsigned old_hash, new_hash, idx;
if (!h)
return -ENOENT;
old_hash = bucket_hash(h, old_key);
- e = hash_scan(h, old_hash, old_key);
- if (!e)
+ idx = bucket_scan(h, old_hash, old_key);
+ if (idx == IDX_NIL)
return -ENOENT;
new_hash = bucket_hash(h, new_key);
- if (hash_scan(h, new_hash, new_key))
+ if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
return -EEXIST;
- unlink_entry(h, e, old_hash);
+ remove_entry(h, idx);
- e->key = new_key;
+ e = &bucket_at_swap(&swap, IDX_PUT)->p;
+ e->b.key = new_key;
e->value = value;
+ assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
+
+ return 0;
+}
- link_entry(h, e, new_hash);
+int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
+ struct swap_entries swap;
+ struct hashmap_base_entry *e;
+ unsigned old_hash, new_hash, idx;
+
+ if (!s)
+ return -ENOENT;
+
+ old_hash = bucket_hash(s, old_key);
+ idx = bucket_scan(s, old_hash, old_key);
+ if (idx == IDX_NIL)
+ return -ENOENT;
+
+ new_hash = bucket_hash(s, new_key);
+ if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
+ return -EEXIST;
+
+ remove_entry(s, idx);
+
+ e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
+ e->key = new_key;
+ assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
return 0;
}
int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
- struct hashmap_entry *e, *k;
- unsigned old_hash, new_hash;
+ struct swap_entries swap;
+ struct plain_hashmap_entry *e;
+ unsigned old_hash, new_hash, idx_old, idx_new;
if (!h)
return -ENOENT;
old_hash = bucket_hash(h, old_key);
- e = hash_scan(h, old_hash, old_key);
- if (!e)
+ idx_old = bucket_scan(h, old_hash, old_key);
+ if (idx_old == IDX_NIL)
return -ENOENT;
- new_hash = bucket_hash(h, new_key);
- k = hash_scan(h, new_hash, new_key);
- if (k)
- if (e != k)
- remove_entry(h, k);
-
- unlink_entry(h, e, old_hash);
+ old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
- e->key = new_key;
+ new_hash = bucket_hash(h, new_key);
+ idx_new = bucket_scan(h, new_hash, new_key);
+ if (idx_new != IDX_NIL)
+ if (idx_old != idx_new) {
+ remove_entry(h, idx_new);
+ /* Compensate for a possible backward shift. */
+ if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key)
+ idx_old = prev_idx(HASHMAP_BASE(h), idx_old);
+ assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key);
+ }
+
+ remove_entry(h, idx_old);
+
+ e = &bucket_at_swap(&swap, IDX_PUT)->p;
+ e->b.key = new_key;
e->value = value;
-
- link_entry(h, e, new_hash);
+ assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
return 0;
}
-void* hashmap_remove_value(Hashmap *h, const void *key, void *value) {
- struct hashmap_entry *e;
- unsigned hash;
+void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
+ struct plain_hashmap_entry *e;
+ unsigned hash, idx;
if (!h)
return NULL;
hash = bucket_hash(h, key);
-
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return NULL;
+ e = plain_bucket_at(h, idx);
if (e->value != value)
return NULL;
- remove_entry(h, e);
+ remove_entry(h, idx);
return value;
}
-void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
- struct hashmap_entry *e;
-
- assert(i);
-
- if (!h)
- goto at_end;
-
- if (*i == ITERATOR_LAST)
- goto at_end;
-
- if (*i == ITERATOR_FIRST && !h->iterate_list_head)
- goto at_end;
+static unsigned find_first_entry(HashmapBase *h) {
+ Iterator i = ITERATOR_FIRST;
- e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i;
+ if (!h || !n_entries(h))
+ return IDX_NIL;
- if (e->iterate_next)
- *i = (Iterator) e->iterate_next;
- else
- *i = ITERATOR_LAST;
-
- if (key)
- *key = e->key;
-
- return e->value;
-
-at_end:
- *i = ITERATOR_LAST;
-
- if (key)
- *key = NULL;
-
- return NULL;
+ return hashmap_iterate_entry(h, &i);
}
-void* hashmap_first(Hashmap *h) {
-
- if (!h)
- return NULL;
+void *internal_hashmap_first(HashmapBase *h) {
+ unsigned idx;
- if (!h->iterate_list_head)
+ idx = find_first_entry(h);
+ if (idx == IDX_NIL)
return NULL;
- return h->iterate_list_head->value;
+ return entry_value(h, bucket_at(h, idx));
}
-void* hashmap_first_key(Hashmap *h) {
-
- if (!h)
- return NULL;
+void *internal_hashmap_first_key(HashmapBase *h) {
+ struct hashmap_base_entry *e;
+ unsigned idx;
- if (!h->iterate_list_head)
+ idx = find_first_entry(h);
+ if (idx == IDX_NIL)
return NULL;
- return (void*) h->iterate_list_head->key;
+ e = bucket_at(h, idx);
+ return (void*) e->key;
}
-void* hashmap_steal_first(Hashmap *h) {
+void *internal_hashmap_steal_first(HashmapBase *h) {
+ struct hashmap_base_entry *e;
void *data;
+ unsigned idx;
- if (!h)
- return NULL;
-
- if (!h->iterate_list_head)
+ idx = find_first_entry(h);
+ if (idx == IDX_NIL)
return NULL;
- data = h->iterate_list_head->value;
- remove_entry(h, h->iterate_list_head);
+ e = bucket_at(h, idx);
+ data = entry_value(h, e);
+ remove_entry(h, idx);
return data;
}
-void* hashmap_steal_first_key(Hashmap *h) {
+void *internal_hashmap_steal_first_key(HashmapBase *h) {
+ struct hashmap_base_entry *e;
void *key;
+ unsigned idx;
- if (!h)
- return NULL;
-
- if (!h->iterate_list_head)
+ idx = find_first_entry(h);
+ if (idx == IDX_NIL)
return NULL;
- key = (void*) h->iterate_list_head->key;
- remove_entry(h, h->iterate_list_head);
+ e = bucket_at(h, idx);
+ key = (void*) e->key;
+ remove_entry(h, idx);
return key;
}
-unsigned hashmap_size(Hashmap *h) {
+unsigned internal_hashmap_size(HashmapBase *h) {
if (!h)
return 0;
- return h->n_entries;
+ return n_entries(h);
}
-unsigned hashmap_buckets(Hashmap *h) {
+unsigned internal_hashmap_buckets(HashmapBase *h) {
if (!h)
return 0;
- return h->n_buckets;
+ return n_buckets(h);
}
-bool hashmap_isempty(Hashmap *h) {
+int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
+ Iterator i;
+ unsigned idx;
- if (!h)
- return true;
+ assert(h);
- return h->n_entries == 0;
-}
+ HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
+ struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
+ int r;
-int hashmap_merge(Hashmap *h, Hashmap *other) {
- struct hashmap_entry *e;
+ r = hashmap_put(h, pe->b.key, pe->value);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ }
- assert(h);
+ return 0;
+}
- if (!other)
- return 0;
+int set_merge(Set *s, Set *other) {
+ Iterator i;
+ unsigned idx;
+
+ assert(s);
- for (e = other->iterate_list_head; e; e = e->iterate_next) {
+ HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
+ struct set_entry *se = set_bucket_at(other, idx);
int r;
- r = hashmap_put(h, e->key, e->value);
- if (r < 0 && r != -EEXIST)
+ r = set_put(s, se->b.key);
+ if (r < 0)
return r;
}
return 0;
}
-int hashmap_reserve(Hashmap *h, unsigned entries_add) {
+int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
int r;
assert(h);
@@ -815,96 +1651,144 @@ int hashmap_reserve(Hashmap *h, unsigned entries_add) {
return 0;
}
-int hashmap_move(Hashmap *h, Hashmap *other) {
- struct hashmap_entry *e, *n;
+/*
+ * The same as hashmap_merge(), but every new item from other is moved to h.
+ * Keys already in h are skipped and stay in other.
+ * Returns: 0 on success.
+ * -ENOMEM on alloc failure, in which case no move has been done.
+ */
+int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
+ struct swap_entries swap;
+ struct hashmap_base_entry *e, *n;
+ Iterator i;
+ unsigned idx;
+ int r;
assert(h);
- /* The same as hashmap_merge(), but every new item from other
- * is moved to h. */
-
if (!other)
return 0;
- for (e = other->iterate_list_head; e; e = n) {
- unsigned h_hash, other_hash;
+ assert(other->type == h->type);
+
+ /*
+ * This reserves buckets for the worst case, where none of other's
+ * entries are yet present in h. This is preferable to risking
+ * an allocation failure in the middle of the moving and having to
+ * rollback or return a partial result.
+ */
+ r = resize_buckets(h, n_entries(other));
+ if (r < 0)
+ return r;
- n = e->iterate_next;
+ HASHMAP_FOREACH_IDX(idx, other, i) {
+ unsigned h_hash;
+ e = bucket_at(other, idx);
h_hash = bucket_hash(h, e->key);
- if (hash_scan(h, h_hash, e->key))
+ if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
continue;
- other_hash = bucket_hash(other, e->key);
- unlink_entry(other, e, other_hash);
- link_entry(h, e, h_hash);
+ n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
+ n->key = e->key;
+ if (h->type != HASHMAP_TYPE_SET)
+ ((struct plain_hashmap_entry*) n)->value =
+ ((struct plain_hashmap_entry*) e)->value;
+ assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
+
+ remove_entry(other, idx);
}
return 0;
}
-int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
- unsigned h_hash, other_hash;
- struct hashmap_entry *e;
+int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
+ struct swap_entries swap;
+ unsigned h_hash, other_hash, idx;
+ struct hashmap_base_entry *e, *n;
+ int r;
assert(h);
h_hash = bucket_hash(h, key);
- if (hash_scan(h, h_hash, key))
+ if (bucket_scan(h, h_hash, key) != IDX_NIL)
return -EEXIST;
if (!other)
return -ENOENT;
+ assert(other->type == h->type);
+
other_hash = bucket_hash(other, key);
- e = hash_scan(other, other_hash, key);
- if (!e)
+ idx = bucket_scan(other, other_hash, key);
+ if (idx == IDX_NIL)
return -ENOENT;
- unlink_entry(other, e, other_hash);
- link_entry(h, e, h_hash);
+ e = bucket_at(other, idx);
+
+ n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
+ n->key = e->key;
+ if (h->type != HASHMAP_TYPE_SET)
+ ((struct plain_hashmap_entry*) n)->value =
+ ((struct plain_hashmap_entry*) e)->value;
+ r = hashmap_put_boldly(h, h_hash, &swap, true);
+ if (r < 0)
+ return r;
+ remove_entry(other, idx);
return 0;
}
-Hashmap *hashmap_copy(Hashmap *h) {
- Hashmap *copy;
+HashmapBase *internal_hashmap_copy(HashmapBase *h) {
+ HashmapBase *copy;
+ int r;
assert(h);
- copy = hashmap_new(h->hash_ops);
+ copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS);
if (!copy)
return NULL;
- if (hashmap_merge(copy, h) < 0) {
- hashmap_free(copy);
+ switch (h->type) {
+ case HASHMAP_TYPE_PLAIN:
+ case HASHMAP_TYPE_ORDERED:
+ r = hashmap_merge((Hashmap*)copy, (Hashmap*)h);
+ break;
+ case HASHMAP_TYPE_SET:
+ r = set_merge((Set*)copy, (Set*)h);
+ break;
+ default:
+ assert_not_reached("Unknown hashmap type");
+ }
+
+ if (r < 0) {
+ internal_hashmap_free(copy);
return NULL;
}
return copy;
}
-char **hashmap_get_strv(Hashmap *h) {
+char **internal_hashmap_get_strv(HashmapBase *h) {
char **sv;
- Iterator it;
- char *item;
- int n;
+ Iterator i;
+ unsigned idx, n;
- sv = new(char*, h->n_entries+1);
+ sv = new(char*, n_entries(h)+1);
if (!sv)
return NULL;
n = 0;
- HASHMAP_FOREACH(item, h, it)
- sv[n++] = item;
+ HASHMAP_FOREACH_IDX(idx, h, i)
+ sv[n++] = entry_value(h, bucket_at(h, idx));
sv[n] = NULL;
return sv;
}
-void *hashmap_next(Hashmap *h, const void *key) {
- unsigned hash;
- struct hashmap_entry *e;
+void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
+ struct ordered_hashmap_entry *e;
+ unsigned hash, idx;
assert(key);
@@ -912,13 +1796,55 @@ void *hashmap_next(Hashmap *h, const void *key) {
return NULL;
hash = bucket_hash(h, key);
- e = hash_scan(h, hash, key);
- if (!e)
+ idx = bucket_scan(h, hash, key);
+ if (idx == IDX_NIL)
return NULL;
- e = e->iterate_next;
- if (!e)
+ e = ordered_bucket_at(h, idx);
+ if (e->iterate_next == IDX_NIL)
return NULL;
+ return ordered_bucket_at(h, e->iterate_next)->p.value;
+}
- return e->value;
+int set_consume(Set *s, void *value) {
+ int r;
+
+ r = set_put(s, value);
+ if (r <= 0)
+ free(value);
+
+ return r;
+}
+
+int set_put_strdup(Set *s, const char *p) {
+ char *c;
+ int r;
+
+ assert(s);
+ assert(p);
+
+ c = strdup(p);
+ if (!c)
+ return -ENOMEM;
+
+ r = set_consume(s, c);
+ if (r == -EEXIST)
+ return 0;
+
+ return r;
+}
+
+int set_put_strdupv(Set *s, char **l) {
+ int n = 0, r;
+ char **i;
+
+ STRV_FOREACH(i, l) {
+ r = set_put_strdup(s, *i);
+ if (r < 0)
+ return r;
+
+ n += r;
+ }
+
+ return n;
}
diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h
index 65fb3c0ee9..9c6e0cab18 100644
--- a/src/shared/hashmap.h
+++ b/src/shared/hashmap.h
@@ -6,6 +6,7 @@
This file is part of systemd.
Copyright 2010 Lennart Poettering
+ Copyright 2014 Michal Schmidt
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
@@ -26,20 +27,45 @@
#include "macro.h"
#include "util.h"
-/* Pretty straightforward hash table implementation. As a minor
- * optimization a NULL hashmap object will be treated as empty hashmap
- * for all read operations. That way it is not necessary to
- * instantiate an object for each Hashmap use. */
+/*
+ * A hash table implementation. As a minor optimization a NULL hashmap object
+ * will be treated as empty hashmap for all read operations. That way it is not
+ * necessary to instantiate an object for each Hashmap use.
+ *
+ * If ENABLE_HASHMAP_DEBUG is defined (by configuring with --enable-hashmap-debug),
+ * the implemention will:
+ * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
+ * - perform extra checks for invalid use of iterators
+ */
#define HASH_KEY_SIZE 16
-typedef struct Hashmap Hashmap;
-typedef struct OrderedHashmap OrderedHashmap;
-typedef struct _IteratorStruct _IteratorStruct;
-typedef _IteratorStruct* Iterator;
+/* The base type for all hashmap and set types. Many functions in the
+ * implementation take (HashmapBase*) parameters and are run-time polymorphic,
+ * though the API is not meant to be polymorphic (do not call functions
+ * prefixed with two underscores directly). */
+typedef struct HashmapBase HashmapBase;
+
+/* Specific hashmap/set types */
+typedef struct Hashmap Hashmap; /* Maps keys to values */
+typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
+typedef struct Set Set; /* Stores just keys */
+
+/* Ideally the Iterator would be an opaque struct, but it is instantiated
+ * by hashmap users, so the definition has to be here. Do not use its fields
+ * directly. */
+typedef struct {
+ unsigned idx; /* index of an entry to be iterated next */
+ const void *next_key; /* expected value of that entry's key pointer */
+#ifdef ENABLE_HASHMAP_DEBUG
+ unsigned put_count; /* hashmap's put_count recorded at start of iteration */
+ unsigned rem_count; /* hashmap's rem_count in previous iteration */
+ unsigned prev_idx; /* idx in previous iteration */
+#endif
+} Iterator;
-#define ITERATOR_FIRST ((Iterator) 0)
-#define ITERATOR_LAST ((Iterator) -1)
+#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
+#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
typedef int (*compare_func_t)(const void *a, const void *b);
@@ -82,153 +108,287 @@ extern const struct hash_ops devt_hash_ops = {
#define devt_hash_ops uint64_hash_ops
#endif
-Hashmap *hashmap_new(const struct hash_ops *hash_ops);
-static inline OrderedHashmap *ordered_hashmap_new(const struct hash_ops *hash_ops) {
- return (OrderedHashmap*) hashmap_new(hash_ops);
+/* Macros for type checking */
+#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
+ (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
+ __builtin_types_compatible_p(typeof(h), Hashmap*) || \
+ __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
+ __builtin_types_compatible_p(typeof(h), Set*))
+
+#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
+ (__builtin_types_compatible_p(typeof(h), Hashmap*) || \
+ __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
+
+#define HASHMAP_BASE(h) \
+ __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
+ (HashmapBase*)(h), \
+ (void)0)
+
+#define PLAIN_HASHMAP(h) \
+ __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
+ (Hashmap*)(h), \
+ (void)0)
+
+#ifdef ENABLE_HASHMAP_DEBUG
+# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
+# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
+# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
+#else
+# define HASHMAP_DEBUG_PARAMS
+# define HASHMAP_DEBUG_SRC_ARGS
+# define HASHMAP_DEBUG_PASS_ARGS
+#endif
+
+Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
+
+void internal_hashmap_free(HashmapBase *h);
+static inline void hashmap_free(Hashmap *h) {
+ internal_hashmap_free(HASHMAP_BASE(h));
}
-void hashmap_free(Hashmap *h);
static inline void ordered_hashmap_free(OrderedHashmap *h) {
- hashmap_free((Hashmap*) h);
+ internal_hashmap_free(HASHMAP_BASE(h));
+}
+
+void internal_hashmap_free_free(HashmapBase *h);
+static inline void hashmap_free_free(Hashmap *h) {
+ internal_hashmap_free_free(HASHMAP_BASE(h));
}
-void hashmap_free_free(Hashmap *h);
static inline void ordered_hashmap_free_free(OrderedHashmap *h) {
- hashmap_free_free((Hashmap*) h);
+ internal_hashmap_free_free(HASHMAP_BASE(h));
}
+
void hashmap_free_free_free(Hashmap *h);
static inline void ordered_hashmap_free_free_free(OrderedHashmap *h) {
- hashmap_free_free_free((Hashmap*) h);
+ hashmap_free_free_free(PLAIN_HASHMAP(h));
}
-Hashmap *hashmap_copy(Hashmap *h);
-static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
- return (OrderedHashmap*) hashmap_copy((Hashmap*) h);
+
+HashmapBase *internal_hashmap_copy(HashmapBase *h);
+static inline Hashmap *hashmap_copy(Hashmap *h) {
+ return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
}
-int hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops);
-static inline int ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops) {
- return hashmap_ensure_allocated((Hashmap**) h, hash_ops);
+static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
+ return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
}
+int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+
int hashmap_put(Hashmap *h, const void *key, void *value);
static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) {
- return hashmap_put((Hashmap*) h, key, value);
+ return hashmap_put(PLAIN_HASHMAP(h), key, value);
}
+
int hashmap_update(Hashmap *h, const void *key, void *value);
static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
- return hashmap_update((Hashmap*) h, key, value);
+ return hashmap_update(PLAIN_HASHMAP(h), key, value);
}
+
int hashmap_replace(Hashmap *h, const void *key, void *value);
static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) {
- return hashmap_replace((Hashmap*) h, key, value);
+ return hashmap_replace(PLAIN_HASHMAP(h), key, value);
+}
+
+void *internal_hashmap_get(HashmapBase *h, const void *key);
+static inline void *hashmap_get(Hashmap *h, const void *key) {
+ return internal_hashmap_get(HASHMAP_BASE(h), key);
}
-void *hashmap_get(Hashmap *h, const void *key);
static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
- return hashmap_get((Hashmap*) h, key);
+ return internal_hashmap_get(HASHMAP_BASE(h), key);
}
+
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) {
- return hashmap_get2((Hashmap*) h, key, rkey);
+ return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
+}
+
+bool internal_hashmap_contains(HashmapBase *h, const void *key);
+static inline bool hashmap_contains(Hashmap *h, const void *key) {
+ return internal_hashmap_contains(HASHMAP_BASE(h), key);
}
-bool hashmap_contains(Hashmap *h, const void *key);
static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
- return hashmap_contains((Hashmap*) h, key);
+ return internal_hashmap_contains(HASHMAP_BASE(h), key);
+}
+
+void *internal_hashmap_remove(HashmapBase *h, const void *key);
+static inline void *hashmap_remove(Hashmap *h, const void *key) {
+ return internal_hashmap_remove(HASHMAP_BASE(h), key);
}
-void *hashmap_remove(Hashmap *h, const void *key);
static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
- return hashmap_remove((Hashmap*) h, key);
+ return internal_hashmap_remove(HASHMAP_BASE(h), key);
}
+
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) {
- return hashmap_remove2((Hashmap*) h, key, rkey);
+ return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
}
+
void *hashmap_remove_value(Hashmap *h, const void *key, void *value);
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
- return hashmap_remove_value((Hashmap*) h, key, value);
+ return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
}
+
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
- return hashmap_remove_and_put((Hashmap*) h, old_key, new_key, value);
+ return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value);
}
+
int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);
static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
- return hashmap_remove_and_replace((Hashmap*) h, old_key, new_key, value);
+ return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value);
}
-int hashmap_merge(Hashmap *h, Hashmap *other);
-static inline int ordered_hashmap_merge(OrderedHashmap *h, OrderedHashmap *other) {
- return hashmap_merge((Hashmap*) h, (Hashmap*) other);
+/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
+ * should just work, allow this by having looser type-checking here. */
+int internal_hashmap_merge(Hashmap *h, Hashmap *other);
+#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
+#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
+
+int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
+static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
+ return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
}
-int hashmap_reserve(Hashmap *h, unsigned entries_add);
static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
- return hashmap_reserve((Hashmap*) h, entries_add);
+ return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+}
+
+int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
+/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
+static inline int hashmap_move(Hashmap *h, Hashmap *other) {
+ return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
}
-int hashmap_move(Hashmap *h, Hashmap *other);
static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
- return hashmap_move((Hashmap*) h, (Hashmap*) other);
+ return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
+}
+
+int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
+static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
+ return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
-int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key);
static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
- return hashmap_move_one((Hashmap*) h, (Hashmap*) other, key);
+ return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
}
-unsigned hashmap_size(Hashmap *h) _pure_;
+unsigned internal_hashmap_size(HashmapBase *h) _pure_;
+static inline unsigned hashmap_size(Hashmap *h) {
+ return internal_hashmap_size(HASHMAP_BASE(h));
+}
static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
- return hashmap_size((Hashmap*) h);
+ return internal_hashmap_size(HASHMAP_BASE(h));
+}
+
+static inline bool hashmap_isempty(Hashmap *h) {
+ return hashmap_size(h) == 0;
}
-bool hashmap_isempty(Hashmap *h) _pure_;
static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
- return hashmap_isempty((Hashmap*) h);
+ return ordered_hashmap_size(h) == 0;
+}
+
+unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
+static inline unsigned hashmap_buckets(Hashmap *h) {
+ return internal_hashmap_buckets(HASHMAP_BASE(h));
}
-unsigned hashmap_buckets(Hashmap *h) _pure_;
static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
- return hashmap_buckets((Hashmap*) h);
+ return internal_hashmap_buckets(HASHMAP_BASE(h));
}
-void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key);
+void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key);
+static inline void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
+ return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
+}
static inline void *ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, const void **key) {
- return hashmap_iterate((Hashmap*) h, i, key);
+ return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
}
-void hashmap_clear(Hashmap *h);
+void internal_hashmap_clear(HashmapBase *h);
+static inline void hashmap_clear(Hashmap *h) {
+ internal_hashmap_clear(HASHMAP_BASE(h));
+}
static inline void ordered_hashmap_clear(OrderedHashmap *h) {
- hashmap_clear((Hashmap*) h);
+ internal_hashmap_clear(HASHMAP_BASE(h));
+}
+
+void internal_hashmap_clear_free(HashmapBase *h);
+static inline void hashmap_clear_free(Hashmap *h) {
+ internal_hashmap_clear_free(HASHMAP_BASE(h));
}
-void hashmap_clear_free(Hashmap *h);
static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
- hashmap_clear_free((Hashmap*) h);
+ internal_hashmap_clear_free(HASHMAP_BASE(h));
}
+
void hashmap_clear_free_free(Hashmap *h);
static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
- hashmap_clear_free_free((Hashmap*) h);
+ hashmap_clear_free_free(PLAIN_HASHMAP(h));
}
-void *hashmap_steal_first(Hashmap *h);
+/*
+ * Note about all *_first*() functions
+ *
+ * For plain Hashmaps and Sets the order of entries is undefined.
+ * The functions find whatever entry is first in the implementation
+ * internal order.
+ *
+ * Only for OrderedHashmaps the order is well defined and finding
+ * the first entry is O(1).
+ */
+
+void *internal_hashmap_steal_first(HashmapBase *h);
+static inline void *hashmap_steal_first(Hashmap *h) {
+ return internal_hashmap_steal_first(HASHMAP_BASE(h));
+}
static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
- return hashmap_steal_first((Hashmap*) h);
+ return internal_hashmap_steal_first(HASHMAP_BASE(h));
+}
+
+void *internal_hashmap_steal_first_key(HashmapBase *h);
+static inline void *hashmap_steal_first_key(Hashmap *h) {
+ return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
}
-void *hashmap_steal_first_key(Hashmap *h);
static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
- return hashmap_steal_first_key((Hashmap*) h);
+ return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
}
-void *hashmap_first(Hashmap *h) _pure_;
-static inline void *ordered_hashmap_first(OrderedHashmap *h) {
- return hashmap_first((Hashmap*) h);
+
+void *internal_hashmap_first_key(HashmapBase *h) _pure_;
+static inline void *hashmap_first_key(Hashmap *h) {
+ return internal_hashmap_first_key(HASHMAP_BASE(h));
}
-void *hashmap_first_key(Hashmap *h) _pure_;
static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
- return hashmap_first_key((Hashmap*) h);
+ return internal_hashmap_first_key(HASHMAP_BASE(h));
}
-void *hashmap_next(Hashmap *h, const void *key);
-static inline void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
- return hashmap_next((Hashmap*) h, key);
+void *internal_hashmap_first(HashmapBase *h) _pure_;
+static inline void *hashmap_first(Hashmap *h) {
+ return internal_hashmap_first(HASHMAP_BASE(h));
}
+static inline void *ordered_hashmap_first(OrderedHashmap *h) {
+ return internal_hashmap_first(HASHMAP_BASE(h));
+}
+
+/* no hashmap_next */
+void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
-char **hashmap_get_strv(Hashmap *h);
+char **internal_hashmap_get_strv(HashmapBase *h);
+static inline char **hashmap_get_strv(Hashmap *h) {
+ return internal_hashmap_get_strv(HASHMAP_BASE(h));
+}
static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
- return hashmap_get_strv((Hashmap*) h);
+ return internal_hashmap_get_strv(HASHMAP_BASE(h));
}
+/*
+ * Hashmaps are iterated in unpredictable order.
+ * OrderedHashmaps are an exception to this. They are iterated in the order
+ * the entries were inserted.
+ * It is safe to remove the current entry.
+ */
#define HASHMAP_FOREACH(e, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL))
+ for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); \
+ (e); \
+ (e) = hashmap_iterate((h), &(i), NULL))
#define ORDERED_HASHMAP_FOREACH(e, h, i) \
for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), NULL); \
@@ -236,7 +396,9 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
(e) = ordered_hashmap_iterate((h), &(i), NULL))
#define HASHMAP_FOREACH_KEY(e, k, h, i) \
- for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
+ for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); \
+ (e); \
+ (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k)); \
@@ -249,6 +411,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
+
#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
diff --git a/src/shared/in-addr-util.c b/src/shared/in-addr-util.c
index 5fbee6caf2..9dc9ec82b4 100644
--- a/src/shared/in-addr-util.c
+++ b/src/shared/in-addr-util.c
@@ -250,21 +250,20 @@ unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
}
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) {
- uint32_t address;
+ uint8_t msb_octet = *(uint8_t*) addr;
+
+ /* addr may not be aligned, so make sure we only access it byte-wise */
assert(addr);
- assert(addr->s_addr != INADDR_ANY);
assert(prefixlen);
- address = be32toh(addr->s_addr);
-
- if ((address >> 31) == 0x0)
+ if (msb_octet < 128)
/* class A, leading bits: 0 */
*prefixlen = 8;
- else if ((address >> 30) == 0x2)
+ else if (msb_octet < 192)
/* class B, leading bits 10 */
*prefixlen = 16;
- else if ((address >> 29) == 0x6)
+ else if (msb_octet < 224)
/* class C, leading bits 110 */
*prefixlen = 24;
else
diff --git a/src/shared/install.c b/src/shared/install.c
index 035b44cc52..efbe61e874 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -538,7 +538,6 @@ static int find_symlinks_in_scope(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
-
/* First look in runtime config path */
r = get_config_path(scope, true, root_dir, &path);
if (r < 0)
@@ -662,7 +661,7 @@ int unit_file_unmask(
goto finish;
STRV_FOREACH(i, files) {
- char *path;
+ _cleanup_free_ char *path = NULL;
if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
if (r == 0)
@@ -678,21 +677,16 @@ int unit_file_unmask(
q = null_or_empty_path(path);
if (q > 0) {
- if (unlink(path) >= 0) {
- mark_symlink_for_removal(&remove_symlinks_to, path);
+ if (unlink(path) < 0)
+ q = -errno;
+ else {
+ q = mark_symlink_for_removal(&remove_symlinks_to, path);
add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
-
- free(path);
- continue;
}
-
- q = -errno;
}
if (q != -ENOENT && r == 0)
r = q;
-
- free(path);
}
@@ -840,6 +834,7 @@ static void install_info_free(InstallInfo *i) {
strv_free(i->aliases);
strv_free(i->wanted_by);
strv_free(i->required_by);
+ strv_free(i->also);
free(i->default_instance);
free(i);
}
@@ -948,6 +943,7 @@ static int config_parse_also(
size_t l;
const char *word, *state;
InstallContext *c = data;
+ InstallInfo *i = userdata;
assert(filename);
assert(lvalue);
@@ -964,6 +960,10 @@ static int config_parse_also(
r = install_info_add(c, n, NULL);
if (r < 0)
return r;
+
+ r = strv_extend(&i->also, n);
+ if (r < 0)
+ return r;
}
if (!isempty(state))
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
@@ -1043,7 +1043,8 @@ static int unit_file_load(
const char *path,
const char *root_dir,
bool allow_symlink,
- bool load) {
+ bool load,
+ bool *also) {
const ConfigTableItem items[] = {
{ "Install", "Alias", config_parse_strv, 0, &info->aliases },
@@ -1087,6 +1088,9 @@ static int unit_file_load(
if (r < 0)
return r;
+ if (also)
+ *also = !strv_isempty(info->also);
+
return
(int) strv_length(info->aliases) +
(int) strv_length(info->wanted_by) +
@@ -1099,7 +1103,8 @@ static int unit_file_search(
LookupPaths *paths,
const char *root_dir,
bool allow_symlink,
- bool load) {
+ bool load,
+ bool *also) {
char **p;
int r;
@@ -1109,7 +1114,7 @@ static int unit_file_search(
assert(paths);
if (info->path)
- return unit_file_load(c, info, info->path, root_dir, allow_symlink, load);
+ return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also);
assert(info->name);
@@ -1120,7 +1125,7 @@ static int unit_file_search(
if (!path)
return -ENOMEM;
- r = unit_file_load(c, info, path, root_dir, allow_symlink, load);
+ r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
if (r >= 0) {
info->path = path;
path = NULL;
@@ -1149,7 +1154,7 @@ static int unit_file_search(
if (!path)
return -ENOMEM;
- r = unit_file_load(c, info, path, root_dir, allow_symlink, load);
+ r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also);
if (r >= 0) {
info->path = path;
path = NULL;
@@ -1167,7 +1172,8 @@ static int unit_file_can_install(
LookupPaths *paths,
const char *root_dir,
const char *name,
- bool allow_symlink) {
+ bool allow_symlink,
+ bool *also) {
_cleanup_(install_context_done) InstallContext c = {};
InstallInfo *i;
@@ -1182,7 +1188,7 @@ static int unit_file_can_install(
assert_se(i = ordered_hashmap_first(c.will_install));
- r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true);
+ r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also);
if (r >= 0)
r =
@@ -1415,7 +1421,7 @@ static int install_context_apply(
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);
+ q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
if (q < 0) {
if (r >= 0)
r = q;
@@ -1462,7 +1468,7 @@ static int install_context_mark_for_removal(
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);
+ q = unit_file_search(c, i, paths, root_dir, false, true, NULL);
if (q == -ENOENT) {
/* do nothing */
} else if (q < 0) {
@@ -1541,10 +1547,8 @@ int unit_file_add_dependency(
UnitFileState state;
state = unit_file_get_state(scope, root_dir, *i);
- if (state < 0) {
- log_error("Failed to get unit file state for %s: %s", *i, strerror(-state));
- return state;
- }
+ if (state < 0)
+ return log_error_errno(state, "Failed to get unit file state for %s: %m", *i);
if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
log_error("Failed to enable unit: Unit %s is masked", *i);
@@ -1569,7 +1573,7 @@ int unit_file_add_dependency(
while ((info = ordered_hashmap_first(c.will_install))) {
assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0);
- r = unit_file_search(&c, info, &paths, root_dir, false, false);
+ r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL);
if (r < 0)
return r;
@@ -1620,12 +1624,10 @@ int unit_file_enable(
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 < 0) {
- log_error("Failed to get unit file state for %s: %s", *i, strerror(-state));
- return state;
- }
-
if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) {
log_error("Failed to enable unit: Unit %s is masked", *i);
return -ENOTSUP;
@@ -1740,7 +1742,7 @@ int unit_file_set_default(
assert_se(i = ordered_hashmap_first(c.will_install));
- r = unit_file_search(&c, i, &paths, root_dir, false, true);
+ r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL);
if (r < 0)
return r;
@@ -1827,6 +1829,7 @@ UnitFileState unit_file_get_state(
STRV_FOREACH(i, paths.unit_path) {
struct stat st;
char *partial;
+ bool also = false;
free(path);
path = NULL;
@@ -1871,13 +1874,16 @@ UnitFileState unit_file_get_state(
else if (r > 0)
return state;
- r = unit_file_can_install(&paths, root_dir, partial, true);
+ 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)
+ else if (r == 0) {
+ if (also)
+ return UNIT_FILE_INDIRECT;
return UNIT_FILE_STATIC;
+ }
}
return r < 0 ? r : state;
@@ -2244,7 +2250,7 @@ int unit_file_get_list(
if (!path)
return -ENOMEM;
- r = unit_file_can_install(&paths, root_dir, path, true);
+ r = unit_file_can_install(&paths, root_dir, path, true, NULL);
if (r == -EINVAL || /* Invalid setting? */
r == -EBADMSG || /* Invalid format? */
r == -ENOENT /* Included file not found? */)
@@ -2276,6 +2282,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
[UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
[UNIT_FILE_STATIC] = "static",
[UNIT_FILE_DISABLED] = "disabled",
+ [UNIT_FILE_INDIRECT] = "indirect",
[UNIT_FILE_INVALID] = "invalid",
};
diff --git a/src/shared/install.h b/src/shared/install.h
index c0b4df69d5..357be0f92d 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -41,6 +41,7 @@ typedef enum UnitFileState {
UNIT_FILE_MASKED_RUNTIME,
UNIT_FILE_STATIC,
UNIT_FILE_DISABLED,
+ UNIT_FILE_INDIRECT,
UNIT_FILE_INVALID,
_UNIT_FILE_STATE_MAX,
_UNIT_FILE_STATE_INVALID = -1
@@ -80,6 +81,7 @@ typedef struct {
char **aliases;
char **wanted_by;
char **required_by;
+ char **also;
char *default_instance;
} InstallInfo;
diff --git a/src/shared/locale-util.h b/src/shared/locale-util.h
index d7a3e4fae6..e48aa3d9af 100644
--- a/src/shared/locale-util.h
+++ b/src/shared/locale-util.h
@@ -21,6 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
+
+#include "macro.h"
+
typedef enum LocaleVariable {
/* We don't list LC_ALL here on purpose. People should be
* using LANG instead. */
diff --git a/src/shared/log.c b/src/shared/log.c
index 26c604afd8..af1a932c86 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -106,8 +106,8 @@ void log_close_syslog(void) {
}
static int create_log_socket(int type) {
- int fd;
struct timeval tv;
+ int fd;
fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
if (fd < 0)
@@ -122,18 +122,20 @@ static int create_log_socket(int type) {
timeval_store(&tv, 10 * USEC_PER_MSEC);
else
timeval_store(&tv, 10 * USEC_PER_SEC);
- setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
return fd;
}
static int log_open_syslog(void) {
- int r;
- union sockaddr_union sa = {
+
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/dev/log",
};
+ int r;
+
if (syslog_fd >= 0)
return 0;
@@ -176,10 +178,12 @@ void log_close_journal(void) {
}
static int log_open_journal(void) {
- union sockaddr_union sa = {
+
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/socket",
};
+
int r;
if (journal_fd >= 0)
@@ -302,10 +306,11 @@ void log_set_facility(int facility) {
static int write_to_console(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
- const char *object_name,
+ const char *object_field,
const char *object,
const char *buffer) {
@@ -356,15 +361,16 @@ static int write_to_console(
}
static int write_to_syslog(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- const char *buffer) {
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *buffer) {
- char header_priority[16], header_time[64], header_pid[16];
+ char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_time[64], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
struct iovec iovec[5] = {};
struct msghdr msghdr = {
.msg_iov = iovec,
@@ -418,15 +424,16 @@ static int write_to_syslog(
}
static int write_to_kmsg(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- const char *buffer) {
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *buffer) {
- char header_priority[16], header_pid[16];
+ char header_priority[1 + DECIMAL_STR_MAX(int) + 2], header_pid[1 + DECIMAL_STR_MAX(pid_t) + 4];
struct iovec iovec[5] = {};
if (kmsg_fd < 0)
@@ -450,45 +457,55 @@ static int write_to_kmsg(
return 1;
}
-static int log_do_header(char *header, size_t size,
- int level,
- const char *file, int line, const char *func,
- const char *object_name, const char *object) {
+static int log_do_header(
+ char *header,
+ size_t size,
+ int level,
+ int error,
+ const char *file, int line, const char *func,
+ const char *object_field, const char *object) {
+
snprintf(header, size,
"PRIORITY=%i\n"
"SYSLOG_FACILITY=%i\n"
- "%s%.*s%s"
+ "%s%s%s"
+ "%s%.*i%s"
+ "%s%s%s"
"%s%.*i%s"
- "%s%.*s%s"
- "%s%.*s%s"
+ "%s%s%s"
"SYSLOG_IDENTIFIER=%s\n",
LOG_PRI(level),
LOG_FAC(level),
- file ? "CODE_FILE=" : "",
- file ? LINE_MAX : 0, file, /* %.0s means no output */
- file ? "\n" : "",
+ isempty(file) ? "" : "CODE_FILE=",
+ isempty(file) ? "" : file,
+ isempty(file) ? "" : "\n",
line ? "CODE_LINE=" : "",
line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
line ? "\n" : "",
- func ? "CODE_FUNCTION=" : "",
- func ? LINE_MAX : 0, func,
- func ? "\n" : "",
- object ? object_name : "",
- object ? LINE_MAX : 0, object, /* %.0s means no output */
- object ? "\n" : "",
+ isempty(func) ? "" : "CODE_FUNCTION=",
+ isempty(func) ? "" : func,
+ isempty(func) ? "" : "\n",
+ error ? "ERRNO=" : "",
+ error ? 1 : 0, error,
+ error ? "\n" : "",
+ isempty(object) ? "" : object_field,
+ isempty(object) ? "" : object,
+ isempty(object) ? "" : "\n",
program_invocation_short_name);
header[size - 1] = '\0';
+
return 0;
}
static int write_to_journal(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- const char *buffer) {
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *buffer) {
char header[LINE_MAX];
struct iovec iovec[4] = {};
@@ -497,8 +514,7 @@ static int write_to_journal(
if (journal_fd < 0)
return 0;
- log_do_header(header, sizeof(header), level,
- file, line, func, object_name, object);
+ log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object);
IOVEC_SET_STRING(iovec[0], header);
IOVEC_SET_STRING(iovec[1], "MESSAGE=");
@@ -515,23 +531,27 @@ static int write_to_journal(
}
static int log_dispatch(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- char *buffer) {
+ int level,
+ int error,
+ const char *file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ char *buffer) {
- int r = 0;
+ assert(buffer);
if (log_target == LOG_TARGET_NULL)
- return 0;
+ return -error;
/* Patch in LOG_DAEMON facility if necessary */
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
+ if (error < 0)
+ error = -error;
+
do {
char *e;
int k = 0;
@@ -548,27 +568,23 @@ static int log_dispatch(
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_JOURNAL) {
- k = write_to_journal(level, file, line, func,
- object_name, object, buffer);
+ k = write_to_journal(level, error, file, line, func, object_field, object, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_journal();
log_open_kmsg();
- } else if (k > 0)
- r++;
+ }
}
if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
log_target == LOG_TARGET_SYSLOG) {
- k = write_to_syslog(level, file, line, func,
- object_name, object, buffer);
+ k = write_to_syslog(level, error, file, line, func, object_field, object, buffer);
if (k < 0) {
if (k != -EAGAIN)
log_close_syslog();
log_open_kmsg();
- } else if (k > 0)
- r++;
+ }
}
if (k <= 0 &&
@@ -578,31 +594,26 @@ static int log_dispatch(
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_KMSG)) {
- k = write_to_kmsg(level, file, line, func,
- object_name, object, buffer);
+ k = write_to_kmsg(level, error, file, line, func, object_field, object, buffer);
if (k < 0) {
log_close_kmsg();
log_open_console();
- } else if (k > 0)
- r++;
+ }
}
- if (k <= 0) {
- k = write_to_console(level, file, line, func,
- object_name, object, buffer);
- if (k < 0)
- return k;
- }
+ if (k <= 0)
+ (void) write_to_console(level, error, file, line, func, object_field, object, buffer);
buffer = e;
} while (buffer);
- return r;
+ return -error;
}
int log_dump_internal(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
char *buffer) {
@@ -611,93 +622,119 @@ int log_dump_internal(
/* This modifies the buffer... */
+ if (error < 0)
+ error = -error;
+
if (_likely_(LOG_PRI(level) > log_max_level))
- return 0;
+ return -error;
- return log_dispatch(level, file, line, func, NULL, NULL, buffer);
+ return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
}
-int log_metav(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *format,
- va_list ap) {
+int log_internalv(
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *format,
+ va_list ap) {
PROTECT_ERRNO;
char buffer[LINE_MAX];
+ if (error < 0)
+ error = -error;
+
if (_likely_(LOG_PRI(level) > log_max_level))
- return 0;
+ return -error;
+
+ /* Make sure that %m maps to the specified error */
+ if (error != 0)
+ errno = error;
vsnprintf(buffer, sizeof(buffer), format, ap);
char_array_0(buffer);
- return log_dispatch(level, file, line, func, NULL, NULL, buffer);
+ return log_dispatch(level, error, file, line, func, NULL, NULL, buffer);
}
-int log_meta(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *format, ...) {
+int log_internal(
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *format, ...) {
- int r;
va_list ap;
+ int r;
va_start(ap, format);
- r = log_metav(level, file, line, func, format, ap);
+ r = log_internalv(level, error, file, line, func, format, ap);
va_end(ap);
return r;
}
-int log_metav_object(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- const char *format,
- va_list ap) {
+int log_object_internalv(
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *format,
+ va_list ap) {
PROTECT_ERRNO;
char buffer[LINE_MAX];
+ if (error < 0)
+ error = -error;
+
if (_likely_(LOG_PRI(level) > log_max_level))
- return 0;
+ return -error;
+
+ /* Make sure that %m maps to the specified error */
+ if (error != 0)
+ errno = error;
vsnprintf(buffer, sizeof(buffer), format, ap);
char_array_0(buffer);
- return log_dispatch(level, file, line, func,
- object_name, object, buffer);
+ return log_dispatch(level, error, file, line, func, object_field, object, buffer);
}
-int log_meta_object(
- int level,
- const char*file,
- int line,
- const char *func,
- const char *object_name,
- const char *object,
- const char *format, ...) {
+int log_object_internal(
+ int level,
+ int error,
+ const char*file,
+ int line,
+ const char *func,
+ const char *object_field,
+ const char *object,
+ const char *format, ...) {
- int r;
va_list ap;
+ int r;
va_start(ap, format);
- r = log_metav_object(level, file, line, func,
- object_name, object, format, ap);
+ r = log_object_internalv(level, error, file, line, func, object_field, object, format, ap);
va_end(ap);
return r;
}
-static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
+static void log_assert(
+ int level,
+ const char *text,
+ const char *file,
+ int line,
+ const char *func,
+ const char *format) {
+
static char buffer[LINE_MAX];
if (_likely_(LOG_PRI(level) > log_max_level))
@@ -710,7 +747,7 @@ static void log_assert(int level, const char *text, const char *file, int line,
char_array_0(buffer);
log_abort_msg = buffer;
- log_dispatch(level, file, line, func, NULL, NULL, buffer);
+ log_dispatch(level, 0, file, line, func, NULL, NULL, buffer);
}
noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
@@ -729,26 +766,31 @@ void log_assert_failed_return(const char *text, const char *file, int line, cons
}
int log_oom_internal(const char *file, int line, const char *func) {
- log_meta(LOG_ERR, file, line, func, "Out of memory.");
+ log_internal(LOG_ERR, ENOMEM, file, line, func, "Out of memory.");
return -ENOMEM;
}
int log_struct_internal(
int level,
+ int error,
const char *file,
int line,
const char *func,
const char *format, ...) {
+ char buf[LINE_MAX];
+ bool found = false;
PROTECT_ERRNO;
va_list ap;
- int r;
+
+ if (error < 0)
+ error = -error;
if (_likely_(LOG_PRI(level) > log_max_level))
- return 0;
+ return -error;
if (log_target == LOG_TARGET_NULL)
- return 0;
+ return -error;
if ((level & LOG_FACMASK) == 0)
level = log_facility | LOG_PRI(level);
@@ -757,7 +799,6 @@ int log_struct_internal(
log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
log_target == LOG_TARGET_JOURNAL) &&
journal_fd >= 0) {
-
char header[LINE_MAX];
struct iovec iovec[17] = {};
unsigned n = 0, i;
@@ -765,25 +806,28 @@ int log_struct_internal(
.msg_iov = iovec,
};
static const char nl = '\n';
+ bool fallback = false;
/* If the journal is available do structured logging */
- log_do_header(header, sizeof(header), level,
- file, line, func, NULL, NULL);
+ log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL);
IOVEC_SET_STRING(iovec[n++], header);
va_start(ap, format);
while (format && n + 1 < ELEMENTSOF(iovec)) {
- char *buf;
va_list aq;
+ char *m;
/* We need to copy the va_list structure,
* since vasprintf() leaves it afterwards at
* an undefined location */
+ if (error != 0)
+ errno = error;
+
va_copy(aq, ap);
- if (vasprintf(&buf, format, aq) < 0) {
+ if (vasprintf(&m, format, aq) < 0) {
va_end(aq);
- r = -ENOMEM;
+ fallback = true;
goto finish;
}
va_end(aq);
@@ -792,7 +836,7 @@ int log_struct_internal(
* the next format string */
VA_FORMAT_ADVANCE(format, ap);
- IOVEC_SET_STRING(iovec[n++], buf);
+ IOVEC_SET_STRING(iovec[n++], m);
iovec[n].iov_base = (char*) &nl;
iovec[n].iov_len = 1;
@@ -803,50 +847,46 @@ int log_struct_internal(
mh.msg_iovlen = n;
- if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
- r = -errno;
- else
- r = 1;
+ (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
finish:
va_end(ap);
for (i = 1; i < n; i += 2)
free(iovec[i].iov_base);
- } else {
- char buf[LINE_MAX];
- bool found = false;
-
- /* Fallback if journal logging is not available */
+ if (!fallback)
+ return -error;
+ }
- va_start(ap, format);
- while (format) {
- va_list aq;
+ /* Fallback if journal logging is not available or didn't work. */
- va_copy(aq, ap);
- vsnprintf(buf, sizeof(buf), format, aq);
- va_end(aq);
- char_array_0(buf);
+ va_start(ap, format);
+ while (format) {
+ va_list aq;
- if (startswith(buf, "MESSAGE=")) {
- found = true;
- break;
- }
+ if (error != 0)
+ errno = error;
- VA_FORMAT_ADVANCE(format, ap);
+ va_copy(aq, ap);
+ vsnprintf(buf, sizeof(buf), format, aq);
+ va_end(aq);
+ char_array_0(buf);
- format = va_arg(ap, char *);
+ if (startswith(buf, "MESSAGE=")) {
+ found = true;
+ break;
}
- va_end(ap);
- if (found)
- r = log_dispatch(level, file, line, func,
- NULL, NULL, buf + 8);
- else
- r = -EINVAL;
+ VA_FORMAT_ADVANCE(format, ap);
+
+ format = va_arg(ap, char *);
}
+ va_end(ap);
- return r;
+ if (!found)
+ return -error;
+
+ return log_dispatch(level, error, file, line, func, NULL, NULL, buf + 8);
}
int log_set_target_from_string(const char *e) {
@@ -910,7 +950,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
void log_parse_environment(void) {
const char *e;
- parse_proc_cmdline(parse_proc_cmdline_item);
+ (void) parse_proc_cmdline(parse_proc_cmdline_item);
e = secure_getenv("SYSTEMD_LOG_TARGET");
if (e && log_set_target_from_string(e) < 0)
diff --git a/src/shared/log.h b/src/shared/log.h
index a3e23a855c..2b6971f248 100644
--- a/src/shared/log.h
+++ b/src/shared/log.h
@@ -25,6 +25,8 @@
#include <stdarg.h>
#include <syslog.h>
#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <errno.h>
#include "macro.h"
@@ -73,46 +75,51 @@ void log_close_console(void);
void log_parse_environment(void);
-int log_meta(
+int log_internal(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
- const char *format, ...) _printf_(5,6);
+ const char *format, ...) _printf_(6,7);
-int log_metav(
+int log_internalv(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
const char *format,
- va_list ap) _printf_(5,0);
+ va_list ap) _printf_(6,0);
-int log_meta_object(
+int log_object_internal(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
- const char *object_name,
+ const char *object_field,
const char *object,
- const char *format, ...) _printf_(7,8);
+ const char *format, ...) _printf_(8,9);
-int log_metav_object(
+int log_object_internalv(
int level,
+ int error,
const char*file,
int line,
const char *func,
- const char *object_name,
+ const char *object_field,
const char *object,
const char *format,
- va_list ap) _printf_(7,0);
+ va_list ap) _printf_(8,0);
int log_struct_internal(
int level,
+ int error,
const char *file,
int line,
const char *func,
- const char *format, ...) _printf_(5,0) _sentinel_;
+ const char *format, ...) _printf_(6,0) _sentinel_;
int log_oom_internal(
const char *file,
@@ -122,11 +129,13 @@ int log_oom_internal(
/* This modifies the buffer passed! */
int log_dump_internal(
int level,
- const char*file,
+ int error,
+ const char *file,
int line,
const char *func,
char *buffer);
+/* Logging for various assertions */
noreturn void log_assert_failed(
const char *text,
const char *file,
@@ -145,17 +154,32 @@ void log_assert_failed_return(
int line,
const char *func);
-#define log_full(level, ...) \
-do { \
- if (log_get_max_level() >= (level)) \
- log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__); \
-} while (0)
-
-#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
-#define log_info(...) log_full(LOG_INFO, __VA_ARGS__)
-#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
-#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
-#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
+/* Logging with level */
+#define log_full_errno(level, error, ...) \
+ ({ \
+ int _l = (level), _e = (error); \
+ (log_get_max_level() >= _l) \
+ ? log_internal(_l, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
+ : -abs(_e); \
+ })
+
+#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__)
+
+/* Normal logging */
+#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__)
+#define log_info(...) log_full(LOG_INFO, __VA_ARGS__)
+#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__)
+#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__)
+#define log_error(...) log_full(LOG_ERR, __VA_ARGS__)
+#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__)
+
+/* Logging triggered by an errno-like error */
+#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__)
+#define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__)
+#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__)
+#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__)
+#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__)
+#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__)
#ifdef LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
@@ -163,19 +187,24 @@ do { \
# define log_trace(...) do {} while(0)
#endif
-#define log_struct(level, ...) log_struct_internal(level, __FILE__, __LINE__, __func__, __VA_ARGS__)
-
-#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__)
+/* Structured logging */
+#define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__)
+#define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__)
/* This modifies the buffer passed! */
-#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer)
+#define log_dump(level, buffer) log_dump_internal(level, 0, __FILE__, __LINE__, __func__, buffer)
+
+#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__)
bool log_on_console(void) _pure_;
const char *log_target_to_string(LogTarget target) _const_;
LogTarget log_target_from_string(const char *s) _pure_;
-#define MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
+/* Helpers to prepare various fields for structured logging */
+#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
+#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
+#define LOG_ERRNO(error) "ERRNO=%i", abs(error)
void log_received_signal(int level, const struct signalfd_siginfo *si);
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 04e1165191..98972eda3b 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -295,10 +295,8 @@ static int output_short(
if (r < 0)
r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
fprintf(f, "[%5llu.%06llu]",
(unsigned long long) (t / USEC_PER_SEC),
@@ -322,10 +320,8 @@ static int output_short(
if (r < 0)
r = sd_journal_get_realtime_usec(j, &x);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
t = (time_t) (x / USEC_PER_SEC);
@@ -365,7 +361,7 @@ static int output_short(
fprintf(f, " %.*s", (int) comm_len, comm);
n += comm_len + 1;
} else
- fputc(' ', f);
+ fputs(" unknown", f);
if (pid && shall_print(pid, pid_len, flags)) {
fprintf(f, "[%.*s]", (int) pid_len, pid);
@@ -422,12 +418,11 @@ static int output_verbose(
r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
if (r < 0)
- log_debug("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r));
+ log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
else {
r = safe_atou64(value, &realtime);
if (r < 0)
- log_debug("Failed to parse realtime timestamp: %s",
- strerror(-r));
+ log_debug_errno(r, "Failed to parse realtime timestamp: %m");
}
}
@@ -441,10 +436,8 @@ static int output_verbose(
}
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
fprintf(f, "%s [%s]\n",
flags & OUTPUT_UTC ?
@@ -516,22 +509,16 @@ static int output_export(
sd_journal_set_data_threshold(j, 0);
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
fprintf(f,
"__CURSOR=%s\n"
@@ -656,22 +643,16 @@ static int output_json(
sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
r = sd_journal_get_realtime_usec(j, &realtime);
- if (r < 0) {
- log_error("Failed to get realtime timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get realtime timestamp: %m");
r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
- if (r < 0) {
- log_error("Failed to get monotonic timestamp: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get monotonic timestamp: %m");
r = sd_journal_get_cursor(j, &cursor);
- if (r < 0) {
- log_error("Failed to get cursor: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get cursor: %m");
if (mode == OUTPUT_JSON_PRETTY)
fprintf(f,
@@ -877,8 +858,7 @@ static int output_cat(
if (r == -ENOENT)
return 0;
- log_error("Failed to get data: %s", strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to get data: %m");
}
assert(l >= 8);
@@ -1225,24 +1205,18 @@ int add_match_this_boot(sd_journal *j, const char *machine) {
if (machine) {
r = get_boot_id_for_machine(machine, &boot_id);
- if (r < 0) {
- log_error("Failed to get boot id of container %s: %s", machine, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
} else {
r = sd_id128_get_boot(&boot_id);
- if (r < 0) {
- log_error("Failed to get boot id: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot id: %m");
}
sd_id128_to_string(boot_id, match + 9);
r = sd_journal_add_match(j, match, strlen(match));
- if (r < 0) {
- log_error("Failed to add match: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
r = sd_journal_add_conjunction(j);
if (r < 0)
diff --git a/src/shared/macro.h b/src/shared/macro.h
index 9ee332c8df..548294e47b 100644
--- a/src/shared/macro.h
+++ b/src/shared/macro.h
@@ -95,15 +95,15 @@
#error "Wut? Pointers are neither 4 nor 8 bytes long?"
#endif
-#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p))
-#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p))
-#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p))
+#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p)))
+#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p)))
+#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p)))
static inline size_t ALIGN_TO(size_t l, size_t ali) {
return ((l + ali - 1) & ~(ali - 1));
}
-#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali))
+#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali)))
/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */
static inline unsigned long ALIGN_POWER2(unsigned long u) {
@@ -384,6 +384,21 @@ 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
@@ -408,4 +423,8 @@ do { \
#endif
#endif
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+#define MODE_INVALID ((mode_t) -1)
+
#include "log.h"
diff --git a/src/shared/memfd.c b/src/shared/memfd-util.c
index 162c12f7a7..6624c5e7db 100644
--- a/src/shared/memfd.c
+++ b/src/shared/memfd-util.c
@@ -31,7 +31,7 @@
#include "util.h"
#include "bus-label.h"
-#include "memfd.h"
+#include "memfd-util.h"
#include "utf8.h"
#include "missing.h"
@@ -65,7 +65,7 @@ int memfd_new(const char *name) {
}
}
- fd = memfd_create(name, MFD_ALLOW_SEALING);
+ fd = memfd_create(name, MFD_ALLOW_SEALING | MFD_CLOEXEC);
if (fd < 0)
return -errno;
@@ -101,7 +101,7 @@ int memfd_set_sealed(int fd) {
assert(fd >= 0);
- r = fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
+ r = fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
if (r < 0)
return -errno;
@@ -117,8 +117,7 @@ int memfd_get_sealed(int fd) {
if (r < 0)
return -errno;
- return (r & (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)) ==
- (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE);
+ return r == (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
}
int memfd_get_size(int fd, uint64_t *sz) {
@@ -172,50 +171,3 @@ int memfd_new_and_map(const char *name, size_t sz, void **p) {
return r;
}
-
-int memfd_get_name(int fd, char **name) {
- char path[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)], buf[FILENAME_MAX+1], *e;
- const char *delim, *end;
- _cleanup_free_ char *n = NULL;
- ssize_t k;
-
- assert(fd >= 0);
- assert(name);
-
- sprintf(path, "/proc/self/fd/%i", fd);
-
- k = readlink(path, buf, sizeof(buf));
- if (k < 0)
- return -errno;
-
- if ((size_t) k >= sizeof(buf))
- return -E2BIG;
-
- buf[k] = 0;
-
- delim = strstr(buf, ":[");
- if (!delim)
- return -EIO;
-
- delim = strchr(delim + 2, ':');
- if (!delim)
- return -EIO;
-
- delim++;
-
- end = strchr(delim, ']');
- if (!end)
- return -EIO;
-
- n = strndup(delim, end - delim);
- if (!n)
- return -ENOMEM;
-
- e = utf8_escape_invalid(n);
- if (!e)
- return -ENOMEM;
-
- *name = e;
-
- return 0;
-}
diff --git a/src/shared/memfd.h b/src/shared/memfd-util.h
index 8f02b0ff55..cf588fe02f 100644
--- a/src/shared/memfd.h
+++ b/src/shared/memfd-util.h
@@ -38,5 +38,3 @@ int memfd_get_sealed(int fd);
int memfd_get_size(int fd, uint64_t *sz);
int memfd_set_size(int fd, uint64_t sz);
-
-int memfd_get_name(int fd, char **name);
diff --git a/src/shared/mempool.c b/src/shared/mempool.c
index b39a37f2db..d5d98d8829 100644
--- a/src/shared/mempool.c
+++ b/src/shared/mempool.c
@@ -74,6 +74,15 @@ void* mempool_alloc_tile(struct mempool *mp) {
return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size;
}
+void* mempool_alloc0_tile(struct mempool *mp) {
+ void *p;
+
+ p = mempool_alloc_tile(mp);
+ if (p)
+ memzero(p, mp->tile_size);
+ return p;
+}
+
void mempool_free_tile(struct mempool *mp, void *p) {
* (void**) p = mp->freelist;
mp->freelist = p;
diff --git a/src/shared/mempool.h b/src/shared/mempool.h
index 8b0bf381bf..42f473bee1 100644
--- a/src/shared/mempool.h
+++ b/src/shared/mempool.h
@@ -34,6 +34,7 @@ struct mempool {
};
void* mempool_alloc_tile(struct mempool *mp);
+void* mempool_alloc0_tile(struct mempool *mp);
void mempool_free_tile(struct mempool *mp, void *p);
#define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \
diff --git a/src/shared/missing.h b/src/shared/missing.h
index bb4f8f23a8..478988c8a4 100644
--- a/src/shared/missing.h
+++ b/src/shared/missing.h
@@ -33,6 +33,8 @@
#include <linux/input.h>
#include <linux/if_link.h>
#include <linux/loop.h>
+#include <linux/audit.h>
+#include <linux/capability.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
@@ -74,7 +76,11 @@
#endif
#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002ULL
+#define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
#endif
#ifndef IP_FREEBIND
@@ -115,22 +121,26 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
}
#endif
-#ifdef __x86_64__
-# ifndef __NR_memfd_create
+#ifndef __NR_memfd_create
+# if defined __x86_64__
# define __NR_memfd_create 319
-# endif
-#elif defined __arm__
-# ifndef __NR_memfd_create
+# elif defined __arm__
# define __NR_memfd_create 385
-# endif
-#elif defined _MIPS_SIM
-# ifndef __NR_memfd_create
-# warning "__NR_memfd_create not yet defined for MIPS"
-# define __NR_memfd_create 0xffffffff
-# endif
-#else
-# ifndef __NR_memfd_create
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_memfd_create 4354
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_memfd_create 6318
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_memfd_create 5314
+# endif
+# elif defined __i386__
# define __NR_memfd_create 356
+# else
+# warning "__NR_memfd_create unknown for your architecture"
+# define __NR_memfd_create 0xffffffff
# endif
#endif
@@ -140,6 +150,39 @@ static inline int memfd_create(const char *name, unsigned int flags) {
}
#endif
+#ifndef __NR_getrandom
+# if defined __x86_64__
+# define __NR_getrandom 318
+# elif defined(__i386__)
+# define __NR_getrandom 355
+# elif defined(__arm__) || defined(__aarch64__)
+# define __NR_getrandom 384
+# elif defined(__ia64__)
+# define __NR_getrandom 1339
+# elif defined(__m68k__)
+# define __NR_getrandom 352
+# elif defined(__s390x__)
+# define __NR_getrandom 349
+# else
+# warning "__NR_getrandom unknown for your architecture"
+# define __NR_getrandom 0xffffffff
+# endif
+#endif
+
+#if !HAVE_DECL_GETRANDOM
+static inline int getrandom(void *buffer, size_t count, unsigned flags) {
+ return syscall(__NR_getrandom, buffer, count, flags);
+}
+#endif
+
+#ifndef GRND_NONBLOCK
+#define GRND_NONBLOCK 0x0001
+#endif
+
+#ifndef GRND_RANDOM
+#define GRND_RANDOM 0x0002
+#endif
+
#ifndef BTRFS_IOCTL_MAGIC
#define BTRFS_IOCTL_MAGIC 0x94
#endif
@@ -411,7 +454,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BOND_AD_INFO 23
#define __IFLA_BOND_MAX 24
-#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
+#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
#endif
#if !HAVE_DECL_IFLA_VLAN_PROTOCOL
@@ -480,6 +523,22 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_BRPORT_UNICAST_FLOOD
+#define IFLA_BRPORT_UNSPEC 0
+#define IFLA_BRPORT_STATE 1
+#define IFLA_BRPORT_PRIORITY 2
+#define IFLA_BRPORT_COST 3
+#define IFLA_BRPORT_MODE 4
+#define IFLA_BRPORT_GUARD 5
+#define IFLA_BRPORT_PROTECT 6
+#define IFLA_BRPORT_FAST_LEAVE 7
+#define IFLA_BRPORT_LEARNING 8
+#define IFLA_BRPORT_UNICAST_FLOOD 9
+#define __IFLA_BRPORT_MAX 10
+
+#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
+#endif
+
#ifndef IPV6_UNICAST_IF
#define IPV6_UNICAST_IF 76
#endif
@@ -508,6 +567,10 @@ static inline int setns(int fd, int nstype) {
# define NET_ADDR_RANDOM 1
#endif
+#ifndef NET_NAME_UNKNOWN
+# define NET_NAME_UNKNOWN 0
+#endif
+
#ifndef NET_NAME_ENUM
# define NET_NAME_ENUM 1
#endif
@@ -536,3 +599,35 @@ static inline int setns(int fd, int nstype) {
#ifndef LOOPBACK_IFINDEX
#define LOOPBACK_IFINDEX 1
#endif
+
+#ifndef MAX_AUDIT_MESSAGE_LENGTH
+#define MAX_AUDIT_MESSAGE_LENGTH 8970
+#endif
+
+#ifndef AUDIT_NLGRP_MAX
+#define AUDIT_NLGRP_READLOG 1
+#endif
+
+#ifndef CAP_MAC_OVERRIDE
+#define CAP_MAC_OVERRIDE 32
+#endif
+
+#ifndef CAP_MAC_ADMIN
+#define CAP_MAC_ADMIN 33
+#endif
+
+#ifndef CAP_SYSLOG
+#define CAP_SYSLOG 34
+#endif
+
+#ifndef CAP_WAKE_ALARM
+#define CAP_WAKE_ALARM 35
+#endif
+
+#ifndef CAP_BLOCK_SUSPEND
+#define CAP_BLOCK_SUSPEND 36
+#endif
+
+#ifndef CAP_AUDIT_READ
+#define CAP_AUDIT_READ 37
+#endif
diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c
index ef3f494cc8..beefd1052a 100644
--- a/src/shared/mkdir.c
+++ b/src/shared/mkdir.c
@@ -44,8 +44,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd
if ((st.st_mode & 0007) > (mode & 0007) ||
(st.st_mode & 0070) > (mode & 0070) ||
(st.st_mode & 0700) > (mode & 0700) ||
- (uid != (uid_t) -1 && st.st_uid != uid) ||
- (gid != (gid_t) -1 && st.st_gid != gid) ||
+ (uid != UID_INVALID && st.st_uid != uid) ||
+ (gid != GID_INVALID && st.st_gid != gid) ||
!S_ISDIR(st.st_mode)) {
errno = EEXIST;
return -errno;
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 54790947ba..a9f2b7e4f4 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -40,7 +40,7 @@ noreturn static void pager_fallback(void) {
} while (n > 0);
if (n < 0) {
- log_error("Internal pager failed: %m");
+ log_error_errno(errno, "Internal pager failed: %m");
_exit(EXIT_FAILURE);
}
@@ -67,17 +67,15 @@ int pager_open(bool jump_to_end) {
* pager so that we get the value from the actual tty */
columns();
- if (pipe(fd) < 0) {
- log_error("Failed to create pager pipe: %m");
- return -errno;
- }
+ if (pipe(fd) < 0)
+ return log_error_errno(errno, "Failed to create pager pipe: %m");
parent_pid = getpid();
pager_pid = fork();
if (pager_pid < 0) {
r = -errno;
- log_error("Failed to fork pager: %m");
+ log_error_errno(errno, "Failed to fork pager: %m");
safe_close_pair(fd);
return r;
}
@@ -126,10 +124,8 @@ int pager_open(bool jump_to_end) {
}
/* Return in the parent */
- if (dup2(fd[1], STDOUT_FILENO) < 0) {
- log_error("Failed to duplicate pager pipe: %m");
- return -errno;
- }
+ if (dup2(fd[1], STDOUT_FILENO) < 0)
+ return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
safe_close_pair(fd);
return 1;
@@ -143,7 +139,7 @@ void pager_close(void) {
/* Inform pager that we are done */
fclose(stdout);
kill(pager_pid, SIGCONT);
- wait_for_terminate(pager_pid, NULL);
+ (void) wait_for_terminate(pager_pid, NULL);
pager_pid = 0;
}
@@ -176,23 +172,21 @@ int show_man_page(const char *desc, bool null_stdio) {
args[1] = desc;
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork: %m");
- return -errno;
- }
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
if (pid == 0) {
/* Child */
if (null_stdio) {
r = make_null_stdio();
if (r < 0) {
- log_error("Failed to kill stdio: %s", strerror(-r));
+ log_error_errno(r, "Failed to kill stdio: %m");
_exit(EXIT_FAILURE);
}
}
execvp(args[0], (char**) args);
- log_error("Failed to execute man: %m");
+ log_error_errno(errno, "Failed to execute man: %m");
_exit(EXIT_FAILURE);
}
diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index 67566bc76b..be03695cf8 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -563,11 +563,11 @@ int path_is_os_tree(const char *path) {
return r >= 0;
}
-int find_binary(const char *name, char **filename) {
+int find_binary(const char *name, bool local, char **filename) {
assert(name);
if (is_path(name)) {
- if (access(name, X_OK) < 0)
+ if (local && access(name, X_OK) < 0)
return -errno;
if (filename) {
@@ -657,7 +657,7 @@ int fsck_exists(const char *fstype) {
checker = strappenda("fsck.", fstype);
- r = find_binary(checker, &p);
+ r = find_binary(checker, true, &p);
if (r < 0)
return r;
diff --git a/src/shared/path-util.h b/src/shared/path-util.h
index 8d171a57ec..bd0d32473f 100644
--- a/src/shared/path-util.h
+++ b/src/shared/path-util.h
@@ -55,7 +55,7 @@ int path_is_mount_point(const char *path, bool allow_symlink);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
-int find_binary(const char *name, char **filename);
+int find_binary(const char *name, bool local, char **filename);
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index d44d70bf9f..085d374ed8 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -28,13 +28,44 @@
#include "util.h"
#include "ptyfwd.h"
-#define ESCAPE_USEC USEC_PER_SEC
+struct PTYForward {
+ sd_event *event;
-static bool look_for_escape(usec_t *timestamp, unsigned *counter, const char *buffer, size_t n) {
+ int master;
+
+ sd_event_source *stdin_event_source;
+ sd_event_source *stdout_event_source;
+ sd_event_source *master_event_source;
+
+ sd_event_source *sigwinch_event_source;
+
+ struct termios saved_stdin_attr;
+ struct termios saved_stdout_attr;
+
+ bool saved_stdin:1;
+ bool saved_stdout:1;
+
+ bool stdin_readable:1;
+ bool stdin_hangup:1;
+ bool stdout_writable:1;
+ bool stdout_hangup:1;
+ bool master_readable:1;
+ bool master_writable:1;
+ bool master_hangup:1;
+
+ char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
+ size_t in_buffer_full, out_buffer_full;
+
+ usec_t escape_timestamp;
+ unsigned escape_counter;
+};
+
+#define ESCAPE_USEC (1*USEC_PER_SEC)
+
+static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
const char *p;
- assert(timestamp);
- assert(counter);
+ assert(f);
assert(buffer);
assert(n > 0);
@@ -44,343 +75,316 @@ static bool look_for_escape(usec_t *timestamp, unsigned *counter, const char *bu
if (*p == 0x1D) {
usec_t nw = now(CLOCK_MONOTONIC);
- if (*counter == 0 || nw > *timestamp + USEC_PER_SEC) {
- *timestamp = nw;
- *counter = 1;
+ if (f->escape_counter == 0 || nw > f->escape_timestamp + ESCAPE_USEC) {
+ f->escape_timestamp = nw;
+ f->escape_counter = 1;
} else {
- (*counter)++;
+ (f->escape_counter)++;
- if (*counter >= 3)
+ if (f->escape_counter >= 3)
return true;
}
} else {
- *timestamp = 0;
- *counter = 0;
+ f->escape_timestamp = 0;
+ f->escape_counter = 0;
}
}
return false;
}
-static int process_pty_loop(int master, sigset_t *mask, pid_t kill_pid, int signo) {
- char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
- size_t in_buffer_full = 0, out_buffer_full = 0;
- struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
- bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
- bool stdin_hangup = false, stdout_hangup = false, master_hangup = false;
- bool tried_orderly_shutdown = false, process_signalfd = false, quit = false;
- usec_t escape_timestamp = 0;
- unsigned escape_counter = 0;
- _cleanup_close_ int ep = -1, signal_fd = -1;
-
- assert(master >= 0);
- assert(mask);
- assert(kill_pid == 0 || kill_pid > 1);
- assert(signo >= 0 && signo < _NSIG);
-
- fd_nonblock(STDIN_FILENO, true);
- fd_nonblock(STDOUT_FILENO, true);
- fd_nonblock(master, true);
-
- signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (signal_fd < 0) {
- log_error("signalfd(): %m");
- return -errno;
- }
-
- ep = epoll_create1(EPOLL_CLOEXEC);
- if (ep < 0) {
- log_error("Failed to create epoll: %m");
- return -errno;
- }
+static int shovel(PTYForward *f) {
+ ssize_t k;
- /* We read from STDIN only if this is actually a TTY,
- * otherwise we assume non-interactivity. */
- if (isatty(STDIN_FILENO)) {
- zero(stdin_ev);
- stdin_ev.events = EPOLLIN|EPOLLET;
- stdin_ev.data.fd = STDIN_FILENO;
+ assert(f);
- if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
- log_error("Failed to register STDIN in epoll: %m");
- return -errno;
- }
- }
+ while ((f->stdin_readable && f->in_buffer_full <= 0) ||
+ (f->master_writable && f->in_buffer_full > 0) ||
+ (f->master_readable && f->out_buffer_full <= 0) ||
+ (f->stdout_writable && f->out_buffer_full > 0)) {
- zero(stdout_ev);
- stdout_ev.events = EPOLLOUT|EPOLLET;
- stdout_ev.data.fd = STDOUT_FILENO;
+ if (f->stdin_readable && f->in_buffer_full < LINE_MAX) {
- zero(master_ev);
- master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
- master_ev.data.fd = master;
+ k = read(STDIN_FILENO, f->in_buffer + f->in_buffer_full, LINE_MAX - f->in_buffer_full);
+ if (k < 0) {
- zero(signal_ev);
- signal_ev.events = EPOLLIN;
- signal_ev.data.fd = signal_fd;
+ if (errno == EAGAIN)
+ f->stdin_readable = false;
+ else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
+ f->stdin_readable = false;
+ f->stdin_hangup = true;
- if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) {
- if (errno != EPERM) {
- log_error("Failed to register stdout in epoll: %m");
- return -errno;
+ f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
+ } else {
+ log_error_errno(errno, "read(): %m");
+ return sd_event_exit(f->event, EXIT_FAILURE);
+ }
+ } else if (k == 0) {
+ /* EOF on stdin */
+ f->stdin_readable = false;
+ f->stdin_hangup = true;
+
+ f->stdin_event_source = sd_event_source_unref(f->stdin_event_source);
+ } else {
+ /* Check if ^] has been
+ * pressed three times within
+ * one second. If we get this
+ * we quite immediately. */
+ if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k))
+ return sd_event_exit(f->event, EXIT_FAILURE);
+
+ f->in_buffer_full += (size_t) k;
+ }
}
- /* stdout without epoll support. Likely redirected to regular file. */
- stdout_writable = true;
- }
-
- if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
- epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
- log_error("Failed to register fds in epoll: %m");
- return -errno;
- }
-
- for (;;) {
- struct epoll_event ev[16];
- ssize_t k;
- int i, nfds;
+ if (f->master_writable && f->in_buffer_full > 0) {
- nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), quit ? 0 : -1);
- if (nfds < 0) {
+ k = write(f->master, f->in_buffer, f->in_buffer_full);
+ if (k < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
+ if (errno == EAGAIN || errno == EIO)
+ f->master_writable = false;
+ else if (errno == EPIPE || errno == ECONNRESET) {
+ f->master_writable = f->master_readable = false;
+ f->master_hangup = true;
- log_error("epoll_wait(): %m");
- return -errno;
+ f->master_event_source = sd_event_source_unref(f->master_event_source);
+ } else {
+ log_error_errno(errno, "write(): %m");
+ return sd_event_exit(f->event, EXIT_FAILURE);
+ }
+ } else {
+ assert(f->in_buffer_full >= (size_t) k);
+ memmove(f->in_buffer, f->in_buffer + k, f->in_buffer_full - k);
+ f->in_buffer_full -= k;
+ }
}
- if (nfds == 0)
- return 0;
-
- for (i = 0; i < nfds; i++) {
- if (ev[i].data.fd == STDIN_FILENO) {
-
- if (ev[i].events & (EPOLLIN|EPOLLHUP))
- stdin_readable = true;
-
- } else if (ev[i].data.fd == STDOUT_FILENO) {
-
- if (ev[i].events & (EPOLLOUT|EPOLLHUP))
- stdout_writable = true;
+ if (f->master_readable && f->out_buffer_full < LINE_MAX) {
- } else if (ev[i].data.fd == master) {
+ k = read(f->master, f->out_buffer + f->out_buffer_full, LINE_MAX - f->out_buffer_full);
+ if (k < 0) {
- if (ev[i].events & (EPOLLIN|EPOLLHUP))
- master_readable = true;
+ /* Note that EIO on the master device
+ * might be cause by vhangup() or
+ * temporary closing of everything on
+ * the other side, we treat it like
+ * EAGAIN here and try again. */
- if (ev[i].events & (EPOLLOUT|EPOLLHUP))
- master_writable = true;
+ if (errno == EAGAIN || errno == EIO)
+ f->master_readable = false;
+ else if (errno == EPIPE || errno == ECONNRESET) {
+ f->master_readable = f->master_writable = false;
+ f->master_hangup = true;
- } else if (ev[i].data.fd == signal_fd)
- process_signalfd = true;
- }
-
- while ((stdin_readable && in_buffer_full <= 0) ||
- (master_writable && in_buffer_full > 0) ||
- (master_readable && out_buffer_full <= 0) ||
- (stdout_writable && out_buffer_full > 0)) {
-
- if (stdin_readable && in_buffer_full < LINE_MAX) {
-
- k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full);
- if (k < 0) {
-
- if (errno == EAGAIN)
- stdin_readable = false;
- else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
- stdin_readable = false;
- stdin_hangup = true;
- epoll_ctl(ep, EPOLL_CTL_DEL, STDIN_FILENO, NULL);
- } else {
- log_error("read(): %m");
- return -errno;
- }
+ f->master_event_source = sd_event_source_unref(f->master_event_source);
} else {
- /* Check if ^] has been
- * pressed three times within
- * one second. If we get this
- * we quite immediately. */
- if (look_for_escape(&escape_timestamp, &escape_counter, in_buffer + in_buffer_full, k))
- return !quit;
-
- in_buffer_full += (size_t) k;
+ log_error_errno(errno, "read(): %m");
+ return sd_event_exit(f->event, EXIT_FAILURE);
}
- }
-
- if (master_writable && in_buffer_full > 0) {
+ } else
+ f->out_buffer_full += (size_t) k;
+ }
- k = write(master, in_buffer, in_buffer_full);
- if (k < 0) {
+ if (f->stdout_writable && f->out_buffer_full > 0) {
- if (errno == EAGAIN || errno == EIO)
- master_writable = false;
- else if (errno == EPIPE || errno == ECONNRESET) {
- master_writable = master_readable = false;
- master_hangup = true;
- epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL);
- } else {
- log_error("write(): %m");
- return -errno;
- }
+ k = write(STDOUT_FILENO, f->out_buffer, f->out_buffer_full);
+ if (k < 0) {
+ if (errno == EAGAIN)
+ f->stdout_writable = false;
+ else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
+ f->stdout_writable = false;
+ f->stdout_hangup = true;
+ f->stdout_event_source = sd_event_source_unref(f->stdout_event_source);
} else {
- assert(in_buffer_full >= (size_t) k);
- memmove(in_buffer, in_buffer + k, in_buffer_full - k);
- in_buffer_full -= k;
+ log_error_errno(errno, "write(): %m");
+ return sd_event_exit(f->event, EXIT_FAILURE);
}
- }
- if (master_readable && out_buffer_full < LINE_MAX) {
-
- k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full);
- if (k < 0) {
-
- /* Note that EIO on the master
- * device might be cause by
- * vhangup() or temporary
- * closing of everything on
- * the other side, we treat it
- * like EAGAIN here and try
- * again. */
-
- if (errno == EAGAIN || errno == EIO)
- master_readable = false;
- else if (errno == EPIPE || errno == ECONNRESET) {
- master_readable = master_writable = false;
- master_hangup = true;
- epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL);
- } else {
- log_error("read(): %m");
- return -errno;
- }
- } else
- out_buffer_full += (size_t) k;
+ } else {
+ assert(f->out_buffer_full >= (size_t) k);
+ memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k);
+ f->out_buffer_full -= k;
}
+ }
+ }
+
+ if (f->stdin_hangup || f->stdout_hangup || f->master_hangup) {
+ /* Exit the loop if any side hung up and if there's
+ * nothing more to write or nothing we could write. */
- if (stdout_writable && out_buffer_full > 0) {
+ if ((f->out_buffer_full <= 0 || f->stdout_hangup) &&
+ (f->in_buffer_full <= 0 || f->master_hangup))
+ return sd_event_exit(f->event, EXIT_SUCCESS);
+ }
- k = write(STDOUT_FILENO, out_buffer, out_buffer_full);
- if (k < 0) {
+ return 0;
+}
- if (errno == EAGAIN)
- stdout_writable = false;
- else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
- stdout_writable = false;
- stdout_hangup = true;
- epoll_ctl(ep, EPOLL_CTL_DEL, STDOUT_FILENO, NULL);
- } else {
- log_error("write(): %m");
- return -errno;
- }
+static int on_master_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
+ PTYForward *f = userdata;
- } else {
- assert(out_buffer_full >= (size_t) k);
- memmove(out_buffer, out_buffer + k, out_buffer_full - k);
- out_buffer_full -= k;
- }
- }
+ assert(f);
+ assert(e);
+ assert(e == f->master_event_source);
+ assert(fd >= 0);
+ assert(fd == f->master);
- }
+ if (revents & (EPOLLIN|EPOLLHUP))
+ f->master_readable = true;
- if (process_signalfd) {
- struct signalfd_siginfo sfsi;
- ssize_t n;
+ if (revents & (EPOLLOUT|EPOLLHUP))
+ f->master_writable = true;
- n = read(signal_fd, &sfsi, sizeof(sfsi));
- if (n != sizeof(sfsi)) {
+ return shovel(f);
+}
- if (n >= 0) {
- log_error("Failed to read from signalfd: invalid block size");
- return -EIO;
- }
+static int on_stdin_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
+ PTYForward *f = userdata;
- if (errno != EINTR && errno != EAGAIN) {
- log_error("Failed to read from signalfd: %m");
- return -errno;
- }
- } else {
+ assert(f);
+ assert(e);
+ assert(e == f->stdin_event_source);
+ assert(fd >= 0);
+ assert(fd == STDIN_FILENO);
- if (sfsi.ssi_signo == SIGWINCH) {
- struct winsize ws;
+ if (revents & (EPOLLIN|EPOLLHUP))
+ f->stdin_readable = true;
- /* The window size changed, let's forward that. */
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
- ioctl(master, TIOCSWINSZ, &ws);
+ return shovel(f);
+}
- } else if (sfsi.ssi_signo == SIGTERM && kill_pid > 0 && signo > 0 && !tried_orderly_shutdown) {
+static int on_stdout_event(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
+ PTYForward *f = userdata;
- if (kill(kill_pid, signo) < 0)
- quit = true;
- else {
- log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
+ assert(f);
+ assert(e);
+ assert(e == f->stdout_event_source);
+ assert(fd >= 0);
+ assert(fd == STDOUT_FILENO);
- /* This only works for systemd... */
- tried_orderly_shutdown = true;
- }
+ if (revents & (EPOLLOUT|EPOLLHUP))
+ f->stdout_writable = true;
- } else
- /* Signals that where
- * delivered via signalfd that
- * we didn't know are a reason
- * for us to quit */
- quit = true;
- }
- }
+ return shovel(f);
+}
- if (stdin_hangup || stdout_hangup || master_hangup) {
- /* Exit the loop if any side hung up and if
- * there's nothing more to write or nothing we
- * could write. */
+static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *si, void *userdata) {
+ PTYForward *f = userdata;
+ struct winsize ws;
- if ((out_buffer_full <= 0 || stdout_hangup) &&
- (in_buffer_full <= 0 || master_hangup))
- return !quit;
- }
- }
+ assert(f);
+ assert(e);
+ assert(e == f->sigwinch_event_source);
+
+ /* The window size changed, let's forward that. */
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
+ (void)ioctl(f->master, TIOCSWINSZ, &ws);
+
+ return 0;
}
-int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo) {
- struct termios saved_stdin_attr, raw_stdin_attr;
- struct termios saved_stdout_attr, raw_stdout_attr;
- bool saved_stdin = false;
- bool saved_stdout = false;
+int pty_forward_new(sd_event *event, int master, PTYForward **ret) {
+ _cleanup_(pty_forward_freep) PTYForward *f = NULL;
struct winsize ws;
int r;
+ f = new0(PTYForward, 1);
+ if (!f)
+ return -ENOMEM;
+
+ if (event)
+ f->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&f->event);
+ if (r < 0)
+ return r;
+ }
+
+ r = fd_nonblock(STDIN_FILENO, true);
+ if (r < 0)
+ return r;
+
+ r = fd_nonblock(STDOUT_FILENO, true);
+ if (r < 0)
+ return r;
+
+ r = fd_nonblock(master, true);
+ if (r < 0)
+ return r;
+
+ f->master = master;
+
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
- ioctl(master, TIOCSWINSZ, &ws);
+ (void)ioctl(master, TIOCSWINSZ, &ws);
- if (tcgetattr(STDIN_FILENO, &saved_stdin_attr) >= 0) {
- saved_stdin = true;
+ if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
+ struct termios raw_stdin_attr;
- raw_stdin_attr = saved_stdin_attr;
+ f->saved_stdin = true;
+
+ raw_stdin_attr = f->saved_stdin_attr;
cfmakeraw(&raw_stdin_attr);
- raw_stdin_attr.c_oflag = saved_stdin_attr.c_oflag;
+ raw_stdin_attr.c_oflag = f->saved_stdin_attr.c_oflag;
tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
}
- if (tcgetattr(STDOUT_FILENO, &saved_stdout_attr) >= 0) {
- saved_stdout = true;
- raw_stdout_attr = saved_stdout_attr;
+ if (tcgetattr(STDOUT_FILENO, &f->saved_stdout_attr) >= 0) {
+ struct termios raw_stdout_attr;
+
+ f->saved_stdout = true;
+
+ raw_stdout_attr = f->saved_stdout_attr;
cfmakeraw(&raw_stdout_attr);
- raw_stdout_attr.c_iflag = saved_stdout_attr.c_iflag;
- raw_stdout_attr.c_lflag = saved_stdout_attr.c_lflag;
+ raw_stdout_attr.c_iflag = f->saved_stdout_attr.c_iflag;
+ raw_stdout_attr.c_lflag = f->saved_stdout_attr.c_lflag;
tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
}
- r = process_pty_loop(master, mask, kill_pid, signo);
+ r = sd_event_add_io(f->event, &f->master_event_source, master, EPOLLIN|EPOLLOUT|EPOLLET, on_master_event, f);
+ if (r < 0)
+ return r;
- if (saved_stdout)
- tcsetattr(STDOUT_FILENO, TCSANOW, &saved_stdout_attr);
- if (saved_stdin)
- tcsetattr(STDIN_FILENO, TCSANOW, &saved_stdin_attr);
+ r = sd_event_add_io(f->event, &f->stdin_event_source, STDIN_FILENO, EPOLLIN|EPOLLET, on_stdin_event, f);
+ if (r < 0 && r != -EPERM)
+ return r;
+
+ r = sd_event_add_io(f->event, &f->stdout_event_source, STDOUT_FILENO, EPOLLOUT|EPOLLET, on_stdout_event, f);
+ if (r == -EPERM)
+ /* stdout without epoll support. Likely redirected to regular file. */
+ f->stdout_writable = true;
+ else if (r < 0)
+ return r;
+
+ r = sd_event_add_signal(f->event, &f->sigwinch_event_source, SIGWINCH, on_sigwinch_event, f);
+
+ *ret = f;
+ f = NULL;
+
+ return 0;
+}
+
+PTYForward *pty_forward_free(PTYForward *f) {
+
+ if (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_unref(f->event);
+
+ if (f->saved_stdout)
+ tcsetattr(STDOUT_FILENO, TCSANOW, &f->saved_stdout_attr);
+ if (f->saved_stdin)
+ tcsetattr(STDIN_FILENO, TCSANOW, &f->saved_stdin_attr);
+
+ free(f);
+ }
/* STDIN/STDOUT should not be nonblocking normally, so let's
* unconditionally reset it */
fd_nonblock(STDIN_FILENO, false);
fd_nonblock(STDOUT_FILENO, false);
- return r;
-
+ return NULL;
}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index 8b657023a9..5a612fd597 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -24,4 +24,11 @@
#include <sys/types.h>
#include <signal.h>
-int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo);
+#include "sd-event.h"
+
+typedef struct PTYForward PTYForward;
+
+int pty_forward_new(sd_event *event, int master, PTYForward **f);
+PTYForward *pty_forward_free(PTYForward *f);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c
index 1eddd17d27..a2233e0cfb 100644
--- a/src/shared/selinux-util.c
+++ b/src/shared/selinux-util.c
@@ -233,7 +233,7 @@ int mac_selinux_get_our_label(char **label) {
return r;
}
-int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, char **label) {
+int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label) {
int r = -EOPNOTSUPP;
#ifdef HAVE_SELINUX
@@ -257,11 +257,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, char **label
if (r < 0)
return -errno;
- r = getexeccon(&fcon);
- if (r < 0)
- return -errno;
-
- if (!fcon) {
+ if (!exec_label) {
/* If there is no context set for next exec let's use context
of target executable */
r = getfilecon(exe, &fcon);
@@ -332,9 +328,13 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
}
- if (r < 0 && errno != ENOENT)
+ /* No context specified by the policy? Proceed without setting it. */
+ if (r < 0 && errno == ENOENT)
+ return 0;
+
+ if (r < 0)
r = -errno;
- else if (r == 0) {
+ else {
r = setfscreatecon(filecon);
if (r < 0) {
log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h
index 7ff8c607b4..a694441000 100644
--- a/src/shared/selinux-util.h
+++ b/src/shared/selinux-util.h
@@ -36,7 +36,7 @@ int mac_selinux_apply(const char *path, const char *label);
int mac_selinux_get_create_label_from_exe(const char *exe, char **label);
int mac_selinux_get_our_label(char **label);
-int mac_selinux_get_child_mls_label(int socket_fd, const char *exec, char **label);
+int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label);
void mac_selinux_free(char *label);
int mac_selinux_create_file_prepare(const char *path, mode_t mode);
diff --git a/src/shared/set.c b/src/shared/set.c
deleted file mode 100644
index 84ab82a701..0000000000
--- a/src/shared/set.c
+++ /dev/null
@@ -1,166 +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 <stdlib.h>
-
-#include "set.h"
-#include "hashmap.h"
-#include "strv.h"
-
-#define MAKE_SET(h) ((Set*) (h))
-#define MAKE_HASHMAP(s) ((Hashmap*) (s))
-
-/* For now this is not much more than a wrapper around a hashmap */
-
-Set *set_new(const struct hash_ops *hash_ops) {
- return MAKE_SET(hashmap_new(hash_ops));
-}
-
-void set_free(Set* s) {
- hashmap_free(MAKE_HASHMAP(s));
-}
-
-void set_free_free(Set *s) {
- hashmap_free_free(MAKE_HASHMAP(s));
-}
-
-int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) {
- return hashmap_ensure_allocated((Hashmap**) s, hash_ops);
-}
-
-int set_put(Set *s, void *value) {
- return hashmap_put(MAKE_HASHMAP(s), value, value);
-}
-
-int set_consume(Set *s, void *value) {
- int r;
-
- r = set_put(s, value);
- if (r < 0)
- free(value);
-
- return r;
-}
-
-int set_put_strdup(Set *s, const char *p) {
- char *c;
- int r;
-
- assert(s);
- assert(p);
-
- c = strdup(p);
- if (!c)
- return -ENOMEM;
-
- r = set_consume(s, c);
- if (r == -EEXIST)
- return 0;
-
- return r;
-}
-
-int set_put_strdupv(Set *s, char **l) {
- int n = 0, r;
- char **i;
-
- STRV_FOREACH(i, l) {
- r = set_put_strdup(s, *i);
- if (r < 0)
- return r;
-
- n += r;
- }
-
- return n;
-}
-
-int set_replace(Set *s, void *value) {
- return hashmap_replace(MAKE_HASHMAP(s), value, value);
-}
-
-void *set_get(Set *s, void *value) {
- return hashmap_get(MAKE_HASHMAP(s), value);
-}
-
-bool set_contains(Set *s, void *value) {
- return hashmap_contains(MAKE_HASHMAP(s), value);
-}
-
-void *set_remove(Set *s, void *value) {
- return hashmap_remove(MAKE_HASHMAP(s), value);
-}
-
-int set_remove_and_put(Set *s, void *old_value, void *new_value) {
- return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value);
-}
-
-unsigned set_size(Set *s) {
- return hashmap_size(MAKE_HASHMAP(s));
-}
-
-bool set_isempty(Set *s) {
- return hashmap_isempty(MAKE_HASHMAP(s));
-}
-
-void *set_iterate(Set *s, Iterator *i) {
- return hashmap_iterate(MAKE_HASHMAP(s), i, NULL);
-}
-
-void *set_steal_first(Set *s) {
- return hashmap_steal_first(MAKE_HASHMAP(s));
-}
-
-void* set_first(Set *s) {
- return hashmap_first(MAKE_HASHMAP(s));
-}
-
-int set_merge(Set *s, Set *other) {
- return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-int set_reserve(Set *s, unsigned entries_add) {
- return hashmap_reserve(MAKE_HASHMAP(s), entries_add);
-}
-
-int set_move(Set *s, Set *other) {
- return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other));
-}
-
-int set_move_one(Set *s, Set *other, void *value) {
- return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value);
-}
-
-Set* set_copy(Set *s) {
- return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s)));
-}
-
-void set_clear(Set *s) {
- hashmap_clear(MAKE_HASHMAP(s));
-}
-
-void set_clear_free(Set *s) {
- hashmap_clear_free(MAKE_HASHMAP(s));
-}
-
-char **set_get_strv(Set *s) {
- return hashmap_get_strv(MAKE_HASHMAP(s));
-}
diff --git a/src/shared/set.h b/src/shared/set.h
index d2622d17ea..4605ecd2c1 100644
--- a/src/shared/set.h
+++ b/src/shared/set.h
@@ -21,56 +21,114 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-/* Pretty straightforward set implementation. Internally based on the
- * hashmap. That means that as a minor optimization a NULL set
- * object will be treated as empty set for all read
- * operations. That way it is not necessary to instantiate an object
- * for each set use. */
-
#include "hashmap.h"
#include "util.h"
-typedef struct Set Set;
+Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
-Set *set_new(const struct hash_ops *hash_ops);
-void set_free(Set* s);
-void set_free_free(Set *s);
-Set* set_copy(Set *s);
-int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops);
+static inline void set_free(Set *s) {
+ internal_hashmap_free(HASHMAP_BASE(s));
+}
-int set_put(Set *s, void *value);
-int set_consume(Set *s, void *value);
-int set_put_strdup(Set *s, const char *p);
-int set_put_strdupv(Set *s, char **l);
-int set_replace(Set *s, void *value);
-void *set_get(Set *s, void *value);
-bool set_contains(Set *s, void *value);
-void *set_remove(Set *s, void *value);
-int set_remove_and_put(Set *s, void *old_value, void *new_value);
+static inline void set_free_free(Set *s) {
+ internal_hashmap_free_free(HASHMAP_BASE(s));
+}
+
+/* no set_free_free_free */
+
+static inline Set *set_copy(Set *s) {
+ return (Set*) internal_hashmap_copy(HASHMAP_BASE(s));
+}
+
+int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
+#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
+int set_put(Set *s, const void *key);
+/* no set_update */
+/* no set_replace */
+static inline void *set_get(Set *s, void *key) {
+ return internal_hashmap_get(HASHMAP_BASE(s), key);
+}
+/* no set_get2 */
+
+static inline bool set_contains(Set *s, const void *key) {
+ return internal_hashmap_contains(HASHMAP_BASE(s), key);
+}
+
+static inline void *set_remove(Set *s, void *key) {
+ return internal_hashmap_remove(HASHMAP_BASE(s), key);
+}
+
+/* no set_remove2 */
+/* no set_remove_value */
+int set_remove_and_put(Set *s, const void *old_key, const void *new_key);
+/* no set_remove_and_replace */
int set_merge(Set *s, Set *other);
-int set_reserve(Set *s, unsigned entries_add);
-int set_move(Set *s, Set *other);
-int set_move_one(Set *s, Set *other, void *value);
-unsigned set_size(Set *s);
-bool set_isempty(Set *s);
+static inline int set_reserve(Set *h, unsigned entries_add) {
+ return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
+}
+
+static inline int set_move(Set *s, Set *other) {
+ return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other));
+}
+
+static inline int set_move_one(Set *s, Set *other, const void *key) {
+ return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key);
+}
+
+static inline unsigned set_size(Set *s) {
+ return internal_hashmap_size(HASHMAP_BASE(s));
+}
+
+static inline bool set_isempty(Set *s) {
+ return set_size(s) == 0;
+}
+
+static inline unsigned set_buckets(Set *s) {
+ return internal_hashmap_buckets(HASHMAP_BASE(s));
+}
void *set_iterate(Set *s, Iterator *i);
-void set_clear(Set *s);
-void set_clear_free(Set *s);
+static inline void set_clear(Set *s) {
+ internal_hashmap_clear(HASHMAP_BASE(s));
+}
+
+static inline void set_clear_free(Set *s) {
+ internal_hashmap_clear_free(HASHMAP_BASE(s));
+}
+
+/* no set_clear_free_free */
+
+static inline void *set_steal_first(Set *s) {
+ return internal_hashmap_steal_first(HASHMAP_BASE(s));
+}
+
+/* no set_steal_first_key */
+/* no set_first_key */
-void *set_steal_first(Set *s);
-void* set_first(Set *s);
+static inline void *set_first(Set *s) {
+ return internal_hashmap_first(HASHMAP_BASE(s));
+}
-char **set_get_strv(Set *s);
+/* no set_next */
+
+static inline char **set_get_strv(Set *s) {
+ return internal_hashmap_get_strv(HASHMAP_BASE(s));
+}
+
+int set_consume(Set *s, void *value);
+int set_put_strdup(Set *s, const char *p);
+int set_put_strdupv(Set *s, char **l);
#define SET_FOREACH(e, s, i) \
for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i)))
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
+
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index d8de644a92..ae14c6bd4d 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -48,9 +48,10 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
{}
};
- config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", NULL,
- "Sleep\0",
- config_item_table_lookup, items, false, false, true, NULL);
+ config_parse_many(PKGSYSCONFDIR "/sleep.conf",
+ CONF_DIRS_NULSTR("systemd/sleep.conf"),
+ "Sleep\0", config_item_table_lookup, items,
+ false, NULL);
if (streq(verb, "suspend")) {
/* empty by default */
@@ -227,14 +228,14 @@ static bool enough_memory_for_hibernation(void) {
r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
if (r < 0) {
- log_error("Failed to retrieve Active(anon) from /proc/meminfo: %s", strerror(-r));
+ log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
return false;
}
r = safe_atollu(active, &act);
if (r < 0) {
- log_error("Failed to parse Active(anon) from /proc/meminfo: %s: %s",
- active, strerror(-r));
+ log_error_errno(r, "Failed to parse Active(anon) from /proc/meminfo: %s: %m",
+ active);
return false;
}
diff --git a/src/shared/smack-util.c b/src/shared/smack-util.c
index a8dccd1554..64e213489e 100644
--- a/src/shared/smack-util.c
+++ b/src/shared/smack-util.c
@@ -25,6 +25,7 @@
#include "util.h"
#include "path-util.h"
+#include "fileio.h"
#include "smack-util.h"
#define SMACK_FLOOR_LABEL "_"
@@ -123,14 +124,38 @@ int mac_smack_apply_ip_in_fd(int fd, const char *label) {
return r;
}
-int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
+int mac_smack_apply_pid(pid_t pid, const char *label) {
+
+#ifdef HAVE_SMACK
+ const char *p;
+#endif
int r = 0;
+ assert(label);
+
+#ifdef HAVE_SMACK
+ if (!mac_smack_use())
+ return 0;
+
+ p = procfs_file_alloca(pid, "attr/current");
+ r = write_string_file(p, label);
+ if (r < 0)
+ return r;
+#endif
+
+ return r;
+}
+
+int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
+
#ifdef HAVE_SMACK
struct stat st;
+#endif
+ int r = 0;
assert(path);
+#ifdef HAVE_SMACK
if (!mac_smack_use())
return 0;
@@ -174,8 +199,7 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
if (ignore_erofs && errno == EROFS)
return 0;
- log_debug("Unable to fix SMACK label of %s: %m", path);
- r = -errno;
+ r = log_debug_errno(errno, "Unable to fix SMACK label of %s: %m", path);
}
#endif
diff --git a/src/shared/smack-util.h b/src/shared/smack-util.h
index 68778da38b..50f55b1f4b 100644
--- a/src/shared/smack-util.h
+++ b/src/shared/smack-util.h
@@ -31,5 +31,6 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs);
int mac_smack_apply(const char *path, const char *label);
int mac_smack_apply_fd(int fd, const char *label);
+int mac_smack_apply_pid(pid_t pid, const char *label);
int mac_smack_apply_ip_in_fd(int fd, const char *label);
int mac_smack_apply_ip_out_fd(int fd, const char *label);
diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c
index 47d9488d56..b1ef19f265 100644
--- a/src/shared/socket-label.c
+++ b/src/shared/socket-label.c
@@ -93,13 +93,13 @@ int socket_address_listen(
if (free_bind) {
one = 1;
if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
- log_warning("IP_FREEBIND failed: %m");
+ log_warning_errno(errno, "IP_FREEBIND failed: %m");
}
if (transparent) {
one = 1;
if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0)
- log_warning("IP_TRANSPARENT failed: %m");
+ log_warning_errno(errno, "IP_TRANSPARENT failed: %m");
}
}
@@ -161,13 +161,11 @@ int make_socket_fd(int log_level, const char* address, int flags) {
_cleanup_free_ char *p = NULL;
r = socket_address_print(&a, &p);
- if (r < 0) {
- log_error("socket_address_print(): %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "socket_address_print(): %m");
if (fd < 0)
- log_error("Failed to listen on %s: %s", p, strerror(-fd));
+ log_error_errno(fd, "Failed to listen on %s: %m", p);
else
log_full(log_level, "Listening on %s", p);
}
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 911dbfe55a..c6f64876be 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -636,12 +636,10 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret)
int saved_errno = errno;
r = sockaddr_pretty(&sa->sa, salen, true, &ret);
- if (r < 0) {
- log_error("sockadd_pretty() failed: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "sockadd_pretty() failed: %m");
- log_debug("getnameinfo(%s) failed: %s", ret, strerror(saved_errno));
+ log_debug_errno(saved_errno, "getnameinfo(%s) failed: %m", ret);
} else {
ret = strdup(host);
if (!ret)
@@ -659,10 +657,8 @@ int getnameinfo_pretty(int fd, char **ret) {
assert(fd >= 0);
assert(ret);
- if (getsockname(fd, &sa.sa, &salen) < 0) {
- log_error("getsockname(%d) failed: %m", fd);
- return -errno;
- }
+ if (getsockname(fd, &sa.sa, &salen) < 0)
+ return log_error_errno(errno, "getsockname(%d) failed: %m", fd);
return socknameinfo_pretty(&sa, salen, ret);
}
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index c1a9c58681..ee267833e6 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -49,7 +49,7 @@ int ask_password_agent_open(void) {
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
if (r < 0)
- log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
+ log_error_errno(r, "Failed to fork TTY ask password agent: %m");
return r;
}
@@ -62,6 +62,6 @@ void ask_password_agent_close(void) {
/* Inform agent that we are done */
kill(agent_pid, SIGTERM);
kill(agent_pid, SIGCONT);
- wait_for_terminate(agent_pid, NULL);
+ (void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index 29b01db19a..e7419b5ee4 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -64,7 +64,7 @@ int polkit_agent_open(void) {
safe_close(pipe_fd[1]);
if (r < 0)
- log_error("Failed to fork TTY ask password agent: %s", strerror(-r));
+ log_error_errno(r, "Failed to fork TTY ask password agent: %m");
else
/* Wait until the agent closes the fd */
fd_wait_for_event(pipe_fd[0], POLLHUP, USEC_INFINITY);
@@ -82,7 +82,7 @@ void polkit_agent_close(void) {
/* Inform agent that we are done */
kill(agent_pid, SIGTERM);
kill(agent_pid, SIGCONT);
- wait_for_terminate(agent_pid, NULL);
+ (void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/strv.c b/src/shared/strv.c
index 00857e40a7..fdb658c0a3 100644
--- a/src/shared/strv.c
+++ b/src/shared/strv.c
@@ -248,40 +248,6 @@ char **strv_split(const char *s, const char *separator) {
return r;
}
-int strv_split_quoted(char ***t, const char *s) {
- const char *word, *state;
- size_t l;
- unsigned n, i;
- char **r;
-
- assert(s);
-
- n = 0;
- FOREACH_WORD_QUOTED(word, l, s, state)
- n++;
- if (!isempty(state))
- /* bad syntax */
- return -EINVAL;
-
- r = new(char*, n+1);
- if (!r)
- return -ENOMEM;
-
- i = 0;
- FOREACH_WORD_QUOTED(word, l, s, state) {
- r[i] = cunescape_length(word, l);
- if (!r[i]) {
- strv_free(r);
- return -ENOMEM;
- }
- i++;
- }
-
- r[i] = NULL;
- *t = r;
- return 0;
-}
-
char **strv_split_newlines(const char *s) {
char **l;
unsigned n;
@@ -307,6 +273,41 @@ char **strv_split_newlines(const char *s) {
return l;
}
+int strv_split_quoted(char ***t, const char *s, bool relax) {
+ size_t n = 0, allocated = 0;
+ _cleanup_strv_free_ char **l = NULL;
+ int r;
+
+ assert(t);
+ assert(s);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = unquote_first_word(&s, &word, relax);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (!GREEDY_REALLOC(l, allocated, n + 2))
+ return -ENOMEM;
+
+ l[n++] = word;
+ word = NULL;
+
+ l[n] = NULL;
+ }
+
+ if (!l)
+ l = new0(char*, 1);
+
+ *t = l;
+ l = NULL;
+
+ return 0;
+}
+
char *strv_join(char **l, const char *separator) {
char *r, *e;
char **s;
@@ -387,7 +388,7 @@ int strv_push(char ***l, char *value) {
n = strv_length(*l);
- /* increase and check for overflow */
+ /* Increase and check for overflow */
m = n + 2;
if (m < n)
return -ENOMEM;
@@ -403,6 +404,34 @@ int strv_push(char ***l, char *value) {
return 0;
}
+int strv_push_pair(char ***l, char *a, char *b) {
+ char **c;
+ unsigned n, m;
+
+ if (!a && !b)
+ return 0;
+
+ n = strv_length(*l);
+
+ /* increase and check for overflow */
+ m = n + !!a + !!b + 1;
+ if (m < n)
+ return -ENOMEM;
+
+ c = realloc_multiply(*l, sizeof(char*), m);
+ if (!c)
+ return -ENOMEM;
+
+ if (a)
+ c[n++] = a;
+ if (b)
+ c[n++] = b;
+ c[n] = NULL;
+
+ *l = c;
+ return 0;
+}
+
int strv_push_prepend(char ***l, char *value) {
char **c;
unsigned n, m, i;
@@ -443,6 +472,18 @@ int strv_consume(char ***l, char *value) {
return r;
}
+int strv_consume_pair(char ***l, char *a, char *b) {
+ int r;
+
+ r = strv_push_pair(l, a, b);
+ if (r < 0) {
+ free(a);
+ free(b);
+ }
+
+ return r;
+}
+
int strv_consume_prepend(char ***l, char *value) {
int r;
@@ -586,6 +627,17 @@ char **strv_sort(char **l) {
return l;
}
+bool strv_equal(char **a, char **b) {
+ if (!a || !b)
+ return a == b;
+
+ for ( ; *a || *b; ++a, ++b)
+ if (!streq_ptr(*a, *b))
+ return false;
+
+ return true;
+}
+
void strv_print(char **l) {
char **s;
diff --git a/src/shared/strv.h b/src/shared/strv.h
index 9c9633c515..2c0280b713 100644
--- a/src/shared/strv.h
+++ b/src/shared/strv.h
@@ -42,13 +42,17 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
int strv_push(char ***l, char *value);
+int strv_push_pair(char ***l, char *a, char *b);
int strv_push_prepend(char ***l, char *value);
int strv_consume(char ***l, char *value);
+int strv_consume_pair(char ***l, char *a, char *b);
int strv_consume_prepend(char ***l, char *value);
char **strv_remove(char **l, const char *s);
char **strv_uniq(char **l);
+bool strv_equal(char **a, char **b);
+
#define strv_contains(l, s) (!!strv_find((l), (s)))
char **strv_new(const char *x, ...) _sentinel_;
@@ -63,9 +67,10 @@ static inline bool strv_isempty(char * const *l) {
}
char **strv_split(const char *s, const char *separator);
-int strv_split_quoted(char ***t, const char *s);
char **strv_split_newlines(const char *s);
+int strv_split_quoted(char ***t, const char *s, bool relax);
+
char *strv_join(char **l, const char *separator);
char *strv_join_quoted(char **l);
diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c
index bac0e5c349..ca3875628a 100644
--- a/src/shared/switch-root.c
+++ b/src/shared/switch-root.c
@@ -47,7 +47,6 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
struct stat new_root_stat;
bool old_root_remove;
const char *i, *temporary_old_root;
- int r;
if (path_equal(new_root, "/"))
return 0;
@@ -57,10 +56,8 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
old_root_remove = in_initrd();
- if (stat(new_root, &new_root_stat) < 0) {
- log_error("Failed to stat directory %s: %m", new_root);
- return -errno;
- }
+ if (stat(new_root, &new_root_stat) < 0)
+ return log_error_errno(errno, "Failed to stat directory %s: %m", new_root);
/* Work-around for kernel design: the kernel refuses switching
* root if any file systems are mounted MS_SHARED. Hence
@@ -68,7 +65,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
*
* https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
- log_warning("Failed to make \"/\" private mount: %m");
+ log_warning_errno(errno, "Failed to make \"/\" private mount: %m");
NULSTR_FOREACH(i, move_mounts) {
char new_mount[PATH_MAX];
@@ -86,38 +83,37 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
* stat failed. Unmount the old mount
* point. */
if (umount2(i, MNT_DETACH) < 0)
- log_warning("Failed to unmount %s: %m", i);
+ log_warning_errno(errno, "Failed to unmount %s: %m", i);
continue;
}
if (mount(i, new_mount, NULL, mountflags, NULL) < 0) {
if (mountflags & MS_MOVE) {
- log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount);
+ log_error_errno(errno, "Failed to move mount %s to %s, forcing unmount: %m", i, new_mount);
if (umount2(i, MNT_FORCE) < 0)
- log_warning("Failed to unmount %s: %m", i);
+ log_warning_errno(errno, "Failed to unmount %s: %m", i);
}
if (mountflags & MS_BIND)
- log_error("Failed to bind mount %s to %s: %m", i, new_mount);
+ log_error_errno(errno, "Failed to bind mount %s to %s: %m", i, new_mount);
}
}
- r = base_filesystem_create(new_root);
- if (r < 0) {
- log_error("Failed to create the base filesystem: %s", strerror(-r));
- return r;
- }
+ /* Do not fail, if base_filesystem_create() fails. Not all
+ * switch roots are like base_filesystem_create() wants them
+ * to look like. They might even boot, if they are RO and
+ * don't have the FS layout. Just ignore the error and
+ * switch_root() nevertheless. */
+ (void) base_filesystem_create(new_root);
- if (chdir(new_root) < 0) {
- log_error("Failed to change directory to %s: %m", new_root);
- return -errno;
- }
+ if (chdir(new_root) < 0)
+ return log_error_errno(errno, "Failed to change directory to %s: %m", new_root);
if (old_root_remove) {
old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
if (old_root_fd < 0)
- log_warning("Failed to open root directory: %m");
+ log_warning_errno(errno, "Failed to open root directory: %m");
}
/* We first try a pivot_root() so that we can umount the old
@@ -128,30 +124,24 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot,
/* Immediately get rid of the old root, if detach_oldroot is set.
* Since we are running off it we need to do this lazily. */
if (detach_oldroot && umount2(oldroot, MNT_DETACH) < 0)
- log_error("Failed to lazily umount old root dir %s, %s: %m",
+ log_error_errno(errno, "Failed to lazily umount old root dir %s, %s: %m",
oldroot,
errno == ENOENT ? "ignoring" : "leaving it around");
- } else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) {
- log_error("Failed to mount moving %s to /: %m", new_root);
- return -errno;
- }
+ } else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount moving %s to /: %m", new_root);
- if (chroot(".") < 0) {
- log_error("Failed to change root: %m");
- return -errno;
- }
+ if (chroot(".") < 0)
+ return log_error_errno(errno, "Failed to change root: %m");
- if (chdir("/") < 0) {
- log_error("Failed to change directory: %m");
- return -errno;
- }
+ if (chdir("/") < 0)
+ return log_error_errno(errno, "Failed to change directory: %m");
if (old_root_fd >= 0) {
struct stat rb;
if (fstat(old_root_fd, &rb) < 0)
- log_warning("Failed to stat old root directory, leaving: %m");
+ log_warning_errno(errno, "Failed to stat old root directory, leaving: %m");
else {
rm_rf_children(old_root_fd, false, false, &rb);
old_root_fd = -1;
diff --git a/src/shared/time-dst.c b/src/shared/time-dst.c
index 6195b11017..926d22b94b 100644
--- a/src/shared/time-dst.c
+++ b/src/shared/time-dst.c
@@ -244,6 +244,8 @@ read_again:
if (fread(zone_names, 1, chars, f) != chars)
return -EINVAL;
+ zone_names[chars] = '\0';
+
for (i = 0; i < num_isstd; ++i) {
int c = getc(f);
if (c == EOF)
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index 5f09ce181f..5e0e1a96ef 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -27,6 +27,7 @@
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_hwdb*, udev_hwdb_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
@@ -35,6 +36,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
#define _cleanup_udev_unref_ _cleanup_(udev_unrefp)
#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp)
#define _cleanup_udev_enumerate_unref_ _cleanup_(udev_enumerate_unrefp)
+#define _cleanup_udev_hwdb_unref_ _cleanup_(udev_hwdb_unrefp)
#define _cleanup_udev_event_unref_ _cleanup_(udev_event_unrefp)
#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp)
#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp)
diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c
index 74c3be4a13..4794ff45bb 100644
--- a/src/shared/uid-range.c
+++ b/src/shared/uid-range.c
@@ -161,7 +161,7 @@ int uid_range_add_str(UidRange **p, unsigned *n, const char *s) {
}
int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
- uid_t closest = (uid_t) -1, candidate;
+ uid_t closest = UID_INVALID, candidate;
unsigned i;
assert(p);
@@ -184,7 +184,7 @@ int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
closest = end;
}
- if (closest == (uid_t) -1)
+ if (closest == UID_INVALID)
return -EBUSY;
*uid = closest;
diff --git a/src/shared/unaligned.h b/src/shared/unaligned.h
new file mode 100644
index 0000000000..d6181dd9a9
--- /dev/null
+++ b/src/shared/unaligned.h
@@ -0,0 +1,66 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ 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 <stdint.h>
+
+static inline uint16_t unaligned_read_be16(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint16_t) u[0]) << 8) |
+ ((uint16_t) u[1]);
+}
+
+static inline uint32_t unaligned_read_be32(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint32_t) unaligned_read_be16(u)) << 16) |
+ ((uint32_t) unaligned_read_be16(u + 2));
+}
+
+static inline uint64_t unaligned_read_be64(const void *_u) {
+ const uint8_t *u = _u;
+
+ return (((uint64_t) unaligned_read_be32(u)) << 32) |
+ ((uint64_t) unaligned_read_be32(u + 4));
+}
+
+static inline void unaligned_write_be16(void *_u, uint16_t a) {
+ uint8_t *u = _u;
+
+ u[0] = (uint8_t) (a >> 8);
+ u[1] = (uint8_t) a;
+}
+
+static inline void unaligned_write_be32(void *_u, uint32_t a) {
+ uint8_t *u = _u;
+
+ unaligned_write_be16(u, (uint16_t) (a >> 16));
+ unaligned_write_be16(u + 2, (uint16_t) a);
+}
+
+static inline void unaligned_write_be64(void *_u, uint64_t a) {
+ uint8_t *u = _u;
+
+ unaligned_write_be32(u, (uint32_t) (a >> 32));
+ unaligned_write_be32(u + 4, (uint32_t) a);
+}
diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c
index 2ef85450e7..21b66913c9 100644
--- a/src/shared/unit-name.c
+++ b/src/shared/unit-name.c
@@ -243,6 +243,30 @@ static char *do_escape(const char *f, char *t) {
return t;
}
+static char *do_escape_mangle(const char *f, enum unit_name_mangle allow_globs, char *t) {
+ const char *valid_chars;
+
+ assert(f);
+ assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB));
+ assert(t);
+
+ /* We'll only escape the obvious characters here, to play
+ * safe. */
+
+ valid_chars = allow_globs == MANGLE_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
+
+ for (; *f; f++) {
+ if (*f == '/')
+ *(t++) = '-';
+ else if (!strchr(valid_chars, *f))
+ t = do_escape_char(*f, t);
+ else
+ *(t++) = *f;
+ }
+
+ return t;
+}
+
char *unit_name_escape(const char *f) {
char *r, *t;
@@ -478,15 +502,18 @@ int unit_name_from_dbus_path(const char *path, char **name) {
}
/**
- * Try to turn a string that might not be a unit name into a
- * sensible unit name.
+ * Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
+ * /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.
*/
-char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) {
- const char *valid_chars, *f;
+char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix) {
char *r, *t;
assert(name);
- assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB));
+ assert(suffix);
+ assert(suffix[0] == '.');
if (is_device_path(name))
return unit_name_from_path(name, ".device");
@@ -494,59 +521,13 @@ char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) {
if (path_is_absolute(name))
return unit_name_from_path(name, ".mount");
- /* We'll only escape the obvious characters here, to play
- * safe. */
-
- valid_chars = allow_globs == MANGLE_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
-
- r = new(char, strlen(name) * 4 + strlen(".service") + 1);
- if (!r)
- return NULL;
-
- for (f = name, t = r; *f; f++) {
- if (*f == '/')
- *(t++) = '-';
- else if (!strchr(valid_chars, *f))
- t = do_escape_char(*f, t);
- else
- *(t++) = *f;
- }
-
- if (unit_name_to_type(name) < 0)
- strcpy(t, ".service");
- else
- *t = 0;
-
- return r;
-}
-
-/**
- * Similar to unit_name_mangle(), but is called when we know
- * that this is about a specific unit type.
- */
-char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix) {
- char *r, *t;
- const char *f;
-
- assert(name);
- assert(IN_SET(allow_globs, MANGLE_GLOB, MANGLE_NOGLOB));
- assert(suffix);
- assert(suffix[0] == '.');
-
r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
if (!r)
return NULL;
- for (f = name, t = r; *f; f++) {
- if (*f == '/')
- *(t++) = '-';
- else if (!strchr(VALID_CHARS, *f))
- t = do_escape_char(*f, t);
- else
- *(t++) = *f;
- }
+ t = do_escape_mangle(name, allow_globs, r);
- if (!endswith(name, suffix))
+ if (unit_name_to_type(name) < 0)
strcpy(t, suffix);
else
*t = 0;
diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h
index daeb56a860..6f139cc4c4 100644
--- a/src/shared/unit-name.h
+++ b/src/shared/unit-name.h
@@ -156,8 +156,10 @@ enum unit_name_mangle {
MANGLE_GLOB,
};
-char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs);
char *unit_name_mangle_with_suffix(const char *name, enum unit_name_mangle allow_globs, const char *suffix);
+static inline char *unit_name_mangle(const char *name, enum unit_name_mangle allow_globs) {
+ return unit_name_mangle_with_suffix(name, allow_globs, ".service");
+}
int build_subslice(const char *slice, const char*name, char **subslice);
diff --git a/src/shared/utf8.c b/src/shared/utf8.c
index 9353559b76..4469a73751 100644
--- a/src/shared/utf8.c
+++ b/src/shared/utf8.c
@@ -142,18 +142,20 @@ int utf8_encoded_to_unichar(const char *str) {
}
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
- const uint8_t *p;
+ const char *p;
assert(str);
- for (p = (const uint8_t*) str; length;) {
+ for (p = str; length;) {
int encoded_len, val;
- encoded_len = utf8_encoded_valid_unichar((const char *) p);
- val = utf8_encoded_to_unichar((const char*) p);
-
+ encoded_len = utf8_encoded_valid_unichar(p);
if (encoded_len < 0 ||
- val < 0 ||
+ (size_t) encoded_len > length)
+ return false;
+
+ val = utf8_encoded_to_unichar(p);
+ if (val < 0 ||
is_unicode_control(val) ||
(!newline && val == '\n'))
return false;
@@ -200,7 +202,46 @@ char *utf8_escape_invalid(const char *str) {
s = mempcpy(s, str, len);
str += len;
} else {
- s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER));
+ s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
+ str += 1;
+ }
+ }
+
+ *s = '\0';
+
+ return p;
+}
+
+char *utf8_escape_non_printable(const char *str) {
+ char *p, *s;
+
+ assert(str);
+
+ p = s = malloc(strlen(str) * 4 + 1);
+ if (!p)
+ return NULL;
+
+ while (*str) {
+ int len;
+
+ len = utf8_encoded_valid_unichar(str);
+ if (len > 0) {
+ if (utf8_is_printable(str, len)) {
+ s = mempcpy(s, str, len);
+ str += len;
+ } else {
+ while (len > 0) {
+ *(s++) = '\\';
+ *(s++) = 'x';
+ *(s++) = hexchar((int) *str >> 4);
+ *(s++) = hexchar((int) *str);
+
+ str += 1;
+ len --;
+ }
+ }
+ } else {
+ s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER);
str += 1;
}
}
diff --git a/src/shared/utf8.h b/src/shared/utf8.h
index c087995930..59abee50ac 100644
--- a/src/shared/utf8.h
+++ b/src/shared/utf8.h
@@ -29,12 +29,12 @@
const char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
-char *utf8_escape_invalid(const char *s);
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
-_pure_ static inline bool utf8_is_printable(const char* str, size_t length) {
- return utf8_is_printable_newline(str, length, true);
-}
+#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
+
+char *utf8_escape_invalid(const char *s);
+char *utf8_escape_non_printable(const char *str);
char *utf16_to_utf8(const void *s, size_t length);
diff --git a/src/shared/util.c b/src/shared/util.c
index 4143f6d643..26a4f72b43 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -174,6 +174,69 @@ char* first_word(const char *s, const char *word) {
return (char*) p;
}
+static 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;
+}
+
int close_nointr(int fd) {
assert(fd >= 0);
@@ -291,7 +354,7 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if ((unsigned long) uid != ul)
return -ERANGE;
- /* Some libc APIs use (uid_t) -1 as special placeholder */
+ /* Some libc APIs use UID_INVALID as special placeholder */
if (uid == (uid_t) 0xFFFFFFFF)
return -ENXIO;
@@ -363,6 +426,46 @@ int safe_atou8(const char *s, uint8_t *ret) {
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;
@@ -515,56 +618,6 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
return 0;
}
-int get_starttime_of_pid(pid_t pid, unsigned long long *st) {
- int r;
- _cleanup_free_ char *line = NULL;
- const char *p;
-
- assert(pid >= 0);
- assert(st);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- /* Let's skip the pid and comm fields. The latter is enclosed
- * in () but does not escape any () in its value, so let's
- * skip over it manually */
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%*d " /* ppid */
- "%*d " /* pgrp */
- "%*d " /* session */
- "%*d " /* tty_nr */
- "%*d " /* tpgid */
- "%*u " /* flags */
- "%*u " /* minflt */
- "%*u " /* cminflt */
- "%*u " /* majflt */
- "%*u " /* cmajflt */
- "%*u " /* utime */
- "%*u " /* stime */
- "%*d " /* cutime */
- "%*d " /* cstime */
- "%*d " /* priority */
- "%*d " /* nice */
- "%*d " /* num_threads */
- "%*d " /* itrealvalue */
- "%llu " /* starttime */,
- st) != 1)
- return -EIO;
-
- return 0;
-}
-
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
@@ -695,7 +748,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
}
/* Kernel threads have no argv[] */
- if (r == NULL || r[0] == 0) {
+ if (isempty(r)) {
_cleanup_free_ char *t = NULL;
int h;
@@ -757,19 +810,30 @@ int get_process_capeff(pid_t pid, char **capeff) {
return get_status_field(p, "\nCapEff:", capeff);
}
+static int get_process_link_contents(const char *proc_file, char **name) {
+ int r;
+
+ assert(proc_file);
+ assert(name);
+
+ r = readlink_malloc(proc_file, name);
+ if (r < 0)
+ return r == -ENOENT ? -ESRCH : r;
+
+ return 0;
+}
+
int get_process_exe(pid_t pid, char **name) {
const char *p;
char *d;
int r;
assert(pid >= 0);
- assert(name);
p = procfs_file_alloca(pid, "exe");
-
- r = readlink_malloc(p, name);
+ r = get_process_link_contents(p, name);
if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
+ return r;
d = endswith(*name, " (deleted)");
if (d)
@@ -821,6 +885,59 @@ int get_process_gid(pid_t pid, gid_t *gid) {
return get_process_id(pid, "Gid:", gid);
}
+int get_process_cwd(pid_t pid, char **cwd) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cwd");
+
+ return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "root");
+
+ return get_process_link_contents(p, root);
+}
+
+int get_process_environ(pid_t pid, char **env) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *outcome = NULL;
+ int c;
+ const char *p;
+ size_t allocated = 0, sz = 0;
+
+ assert(pid >= 0);
+ assert(env);
+
+ p = procfs_file_alloca(pid, "environ");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+ return -ENOMEM;
+
+ if (c == '\0')
+ outcome[sz++] = '\n';
+ else
+ sz += cescape_char(c, outcome + sz);
+ }
+
+ outcome[sz] = '\0';
+ *env = outcome;
+ outcome = NULL;
+
+ return 0;
+}
+
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
@@ -893,6 +1010,28 @@ 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;
@@ -1178,63 +1317,7 @@ char *cescape(const char *s) {
return NULL;
for (f = s, t = r; *f; f++)
-
- switch (*f) {
-
- case '\a':
- *(t++) = '\\';
- *(t++) = 'a';
- break;
- case '\b':
- *(t++) = '\\';
- *(t++) = 'b';
- break;
- case '\f':
- *(t++) = '\\';
- *(t++) = 'f';
- break;
- case '\n':
- *(t++) = '\\';
- *(t++) = 'n';
- break;
- case '\r':
- *(t++) = '\\';
- *(t++) = 'r';
- break;
- case '\t':
- *(t++) = '\\';
- *(t++) = 't';
- break;
- case '\v':
- *(t++) = '\\';
- *(t++) = 'v';
- break;
- case '\\':
- *(t++) = '\\';
- *(t++) = '\\';
- break;
- case '"':
- *(t++) = '\\';
- *(t++) = '"';
- break;
- case '\'':
- *(t++) = '\\';
- *(t++) = '\'';
- break;
-
- default:
- /* For special chars we prefer octal over
- * hexadecimal encoding, simply because glib's
- * g_strescape() does the same */
- if ((*f < ' ') || (*f >= 127)) {
- *(t++) = '\\';
- *(t++) = octchar((unsigned char) *f >> 6);
- *(t++) = octchar((unsigned char) *f >> 3);
- *(t++) = octchar((unsigned char) *f);
- } else
- *(t++) = *f;
- break;
- }
+ t += cescape_char(*f, t);
*t = 0;
@@ -2017,9 +2100,9 @@ int acquire_terminal(
assert(notify >= 0);
for (;;) {
- uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX];
- ssize_t l;
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
struct inotify_event *e;
+ ssize_t l;
if (timeout != USEC_INFINITY) {
usec_t n;
@@ -2040,9 +2123,8 @@ int acquire_terminal(
}
}
- l = read(notify, inotify_buffer, sizeof(inotify_buffer));
+ l = read(notify, buffer, sizeof(buffer));
if (l < 0) {
-
if (errno == EINTR || errno == EAGAIN)
continue;
@@ -2050,21 +2132,11 @@ int acquire_terminal(
goto fail;
}
- e = (struct inotify_event*) inotify_buffer;
-
- while (l > 0) {
- size_t step;
-
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
if (e->wd != wd || !(e->mask & IN_CLOSE)) {
r = -EIO;
goto fail;
}
-
- step = sizeof(struct inotify_event) + e->len;
- assert(step <= (size_t) l);
-
- e = (struct inotify_event*) ((uint8_t*) e + step);
- l -= step;
}
break;
@@ -2081,7 +2153,7 @@ int acquire_terminal(
r = reset_terminal_fd(fd, true);
if (r < 0)
- log_warning("Failed to reset terminal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to reset terminal: %m");
return fd;
@@ -2220,13 +2292,15 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
return n;
}
-ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
const uint8_t *p = buf;
ssize_t n = 0;
assert(fd >= 0);
assert(buf);
+ errno = 0;
+
while (nbytes > 0) {
ssize_t k;
@@ -2245,14 +2319,15 @@ ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
}
if (k <= 0)
- return n > 0 ? n : (k < 0 ? -errno : 0);
+ /* We were not done yet, and a write error occured. */
+ return errno ? -errno : -EIO;
p += k;
nbytes -= k;
n += k;
}
- return n;
+ return 0;
}
int parse_size(const char *t, off_t base, off_t *size) {
@@ -2466,14 +2541,53 @@ char* dirname_malloc(const char *path) {
}
int dev_urandom(void *p, size_t n) {
- _cleanup_close_ int fd;
+ static int have_syscall = -1;
+ int r, fd;
ssize_t k;
+ /* Gathers some randomness from the kernel. This call will
+ * never block, and will always return some data from the
+ * kernel, regardless if the random pool is fully initialized
+ * or not. It thus makes no guarantee for the quality of the
+ * returned entropy, but is good enough for or usual usecases
+ * of seeding the hash functions for hashtable */
+
+ /* Use the getrandom() syscall unless we know we don't have
+ * it, or when the requested size is too large for it. */
+ if (have_syscall != 0 || (size_t) (int) n != n) {
+ r = getrandom(p, n, GRND_NONBLOCK);
+ if (r == (int) n) {
+ have_syscall = true;
+ return 0;
+ }
+
+ if (r < 0) {
+ if (errno == ENOSYS)
+ /* we lack the syscall, continue with
+ * reading from /dev/urandom */
+ have_syscall = false;
+ else if (errno == EAGAIN)
+ /* not enough entropy for now. Let's
+ * remember to use the syscall the
+ * next time, again, but also read
+ * from /dev/urandom for now, which
+ * doesn't care about the current
+ * amount of entropy. */
+ have_syscall = true;
+ else
+ return -errno;
+ } else
+ /* too short read? */
+ return -EIO;
+ }
+
fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return errno == ENOENT ? -ENOSYS : -errno;
k = loop_read(fd, p, n, true);
+ safe_close(fd);
+
if (k < 0)
return (int) k;
if ((size_t) k != n)
@@ -2482,8 +2596,36 @@ int dev_urandom(void *p, size_t n) {
return 0;
}
-void random_bytes(void *p, size_t n) {
+void initialize_srand(void) {
static bool srand_called = false;
+ unsigned x;
+#ifdef HAVE_SYS_AUXV_H
+ void *auxv;
+#endif
+
+ if (srand_called)
+ return;
+
+ x = 0;
+
+#ifdef HAVE_SYS_AUXV_H
+ /* The kernel provides us with a bit of entropy in auxv, so
+ * let's try to make use of that to seed the pseudo-random
+ * generator. It's better than nothing... */
+
+ auxv = (void*) getauxval(AT_RANDOM);
+ if (auxv)
+ x ^= *(unsigned*) auxv;
+#endif
+
+ x ^= (unsigned) now(CLOCK_REALTIME);
+ x ^= (unsigned) gettid();
+
+ srand(x);
+ srand_called = true;
+}
+
+void random_bytes(void *p, size_t n) {
uint8_t *q;
int r;
@@ -2494,28 +2636,7 @@ void random_bytes(void *p, size_t n) {
/* If some idiot made /dev/urandom unavailable to us, he'll
* get a PRNG instead. */
- if (!srand_called) {
- unsigned x = 0;
-
-#ifdef HAVE_SYS_AUXV_H
- /* The kernel provides us with a bit of entropy in
- * auxv, so let's try to make use of that to seed the
- * pseudo-random generator. It's better than
- * nothing... */
-
- void *auxv;
-
- auxv = (void*) getauxval(AT_RANDOM);
- if (auxv)
- x ^= *(unsigned*) auxv;
-#endif
-
- x ^= (unsigned) now(CLOCK_REALTIME);
- x ^= (unsigned) gettid();
-
- srand(x);
- srand_called = true;
- }
+ initialize_srand();
for (q = p; q < (uint8_t*) p + n; q ++)
*q = rand();
@@ -2737,7 +2858,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
if (k < 0)
return k;
- snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
+ sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
k = readlink_malloc(fn, &s);
if (k < 0) {
@@ -2873,6 +2994,15 @@ _pure_ static int is_temporary_fs(struct statfs *s) {
F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
+int is_fd_on_temporary_fs(int fd) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_temporary_fs(&s);
+}
+
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
struct statfs s;
@@ -2895,6 +3025,19 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root
return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev);
}
+static int file_is_priv_sticky(const char *p) {
+ struct stat st;
+
+ assert(p);
+
+ if (lstat(p, &st) < 0)
+ return -errno;
+
+ return
+ (st.st_uid == 0 || st.st_uid == getuid()) &&
+ (st.st_mode & S_ISVTX);
+}
+
static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) {
int fd, r;
struct statfs s;
@@ -2975,11 +3118,11 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
if (chmod(path, mode) < 0)
return -errno;
- if (uid != (uid_t) -1 || gid != (gid_t) -1)
+ if (uid != UID_INVALID || gid != GID_INVALID)
if (chown(path, uid, gid) < 0)
return -errno;
@@ -2993,11 +3136,11 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
* first change the access mode and only then hand out
* ownership to avoid a window where access is too open. */
- if (mode != (mode_t) -1)
+ if (mode != MODE_INVALID)
if (fchmod(fd, mode) < 0)
return -errno;
- if (uid != (uid_t) -1 || gid != (gid_t) -1)
+ if (uid != UID_INVALID || gid != GID_INVALID)
if (fchown(fd, uid, gid) < 0)
return -errno;
@@ -3133,7 +3276,8 @@ char *replace_env(const char *format, char **env) {
case CURLY:
if (*e == '{') {
- if (!(k = strnappend(r, word, e-word-1)))
+ k = strnappend(r, word, e-word-1);
+ if (!k)
goto fail;
free(r);
@@ -3143,7 +3287,8 @@ char *replace_env(const char *format, char **env) {
state = VARIABLE;
} else if (*e == '$') {
- if (!(k = strnappend(r, word, e-word)))
+ k = strnappend(r, word, e-word);
+ if (!k)
goto fail;
free(r);
@@ -3175,7 +3320,8 @@ char *replace_env(const char *format, char **env) {
}
}
- if (!(k = strnappend(r, word, e-word)))
+ k = strnappend(r, word, e-word);
+ if (!k)
goto fail;
free(r);
@@ -3208,7 +3354,7 @@ char **replace_env_argv(char **argv, char **env) {
if (e) {
int r;
- r = strv_split_quoted(&m, e);
+ r = strv_split_quoted(&m, e, true);
if (r < 0) {
ret[k] = NULL;
strv_free(ret);
@@ -3485,7 +3631,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
return -errno;
}
- if (uid != (uid_t) -1 || gid != (gid_t) -1) {
+ if (uid != UID_INVALID || gid != GID_INVALID) {
r = fchown(fd, uid, gid);
if (r < 0)
return -errno;
@@ -3506,7 +3652,7 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
}
int touch(const char *path) {
- return touch_file(path, false, USEC_INFINITY, (uid_t) -1, (gid_t) -1, 0);
+ return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
}
char *unquote(const char *s, const char* quotes) {
@@ -3529,41 +3675,33 @@ char *unquote(const char *s, const char* quotes) {
}
char *normalize_env_assignment(const char *s) {
- _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL;
- char *eq, *r;
+ _cleanup_free_ char *value = NULL;
+ const char *eq;
+ char *p, *name;
eq = strchr(s, '=');
if (!eq) {
- char *t;
+ char *r, *t;
r = strdup(s);
if (!r)
return NULL;
t = strstrip(r);
- if (t == r)
- return r;
+ if (t != r)
+ memmove(r, t, strlen(t) + 1);
- memmove(r, t, strlen(t) + 1);
return r;
}
- name = strndup(s, eq - s);
- if (!name)
- return NULL;
-
- p = strdup(eq + 1);
- if (!p)
- return NULL;
+ name = strndupa(s, eq - s);
+ p = strdupa(eq + 1);
value = unquote(strstrip(p), QUOTES);
if (!value)
return NULL;
- if (asprintf(&r, "%s=%s", strstrip(name), value) < 0)
- r = NULL;
-
- return r;
+ return strjoin(strstrip(name), "=", value, NULL);
}
int wait_for_terminate(pid_t pid, siginfo_t *status) {
@@ -3599,8 +3737,11 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) {
*
* That is, success is indicated by a return value of zero, and an
* error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
*/
-int wait_for_terminate_and_warn(const char *name, pid_t pid) {
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
int r;
siginfo_t status;
@@ -3608,20 +3749,17 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
assert(pid > 1);
r = wait_for_terminate(pid, &status);
- if (r < 0) {
- log_warning("Failed to wait for %s: %s", name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for %s: %m", name);
if (status.si_code == CLD_EXITED) {
- if (status.si_status != 0) {
- log_warning("%s failed with error code %i.", name, status.si_status);
- return status.si_status;
- }
-
- log_debug("%s succeeded.", name);
- return 0;
+ if (status.si_status != 0)
+ log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+ "%s failed with error code %i.", name, status.si_status);
+ else
+ log_debug("%s succeeded.", name);
+ return status.si_status;
} else if (status.si_code == CLD_KILLED ||
status.si_code == CLD_DUMPED) {
@@ -3880,7 +4018,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
executor_pid = fork();
if (executor_pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
return;
} else if (executor_pid == 0) {
@@ -3903,7 +4041,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
if (errno == ENOENT)
_exit(EXIT_SUCCESS);
- log_error("Failed to enumerate directory %s: %m", directory);
+ log_error_errno(errno, "Failed to enumerate directory %s: %m", directory);
_exit(EXIT_FAILURE);
}
}
@@ -3929,7 +4067,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
pid = fork();
if (pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
continue;
} else if (pid == 0) {
char *_argv[2];
@@ -3944,7 +4082,7 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
argv[0] = path;
execv(path, argv);
- log_error("Failed to execute %s: %m", path);
+ log_error_errno(errno, "Failed to execute %s: %m", path);
_exit(EXIT_FAILURE);
}
@@ -3976,13 +4114,13 @@ void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv
path = hashmap_remove(pids, UINT_TO_PTR(pid));
assert(path);
- wait_for_terminate_and_warn(path, pid);
+ wait_for_terminate_and_warn(path, pid, true);
}
_exit(EXIT_SUCCESS);
}
- wait_for_terminate_and_warn(directory, executor_pid);
+ wait_for_terminate_and_warn(directory, executor_pid, true);
}
int kill_and_sigcont(pid_t pid, int sig) {
@@ -4780,19 +4918,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
return -ENOENT;
}
-int file_is_priv_sticky(const char *p) {
- struct stat st;
-
- assert(p);
-
- if (lstat(p, &st) < 0)
- return -errno;
-
- return
- (st.st_uid == 0 || st.st_uid == getuid()) &&
- (st.st_mode & S_ISVTX);
-}
-
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
@@ -5149,7 +5274,7 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
* keep an unused copy of stdin around. */
fd = open("/dev/tty", O_WRONLY);
if (fd < 0) {
- log_error("Failed to open /dev/tty: %m");
+ log_error_errno(errno, "Failed to open /dev/tty: %m");
_exit(EXIT_FAILURE);
}
@@ -5332,16 +5457,12 @@ int make_console_stdio(void) {
/* Make /dev/console the controlling terminal and stdin/stdout/stderr */
fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
- if (fd < 0) {
- log_error("Failed to acquire terminal: %s", strerror(-fd));
- return fd;
- }
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to acquire terminal: %m");
r = make_stdio(fd);
- if (r < 0) {
- log_error("Failed to duplicate terminal fd: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to duplicate terminal fd: %m");
return 0;
}
@@ -6096,85 +6217,48 @@ int split_pair(const char *s, const char *sep, char **l, char **r) {
}
int shall_restore_state(void) {
- _cleanup_free_ char *line = NULL;
- const char *word, *state;
- size_t l;
+ _cleanup_free_ char *value = NULL;
int r;
- r = proc_cmdline(&line);
+ r = get_proc_cmdline_key("systemd.restore_state=", &value);
if (r < 0)
return r;
- if (r == 0) /* Container ... */
- return 1;
-
- r = 1;
-
- FOREACH_WORD_QUOTED(word, l, line, state) {
- const char *e;
- char n[l+1];
- int k;
-
- memcpy(n, word, l);
- n[l] = 0;
-
- e = startswith(n, "systemd.restore_state=");
- if (!e)
- continue;
-
- k = parse_boolean(e);
- if (k >= 0)
- r = k;
- }
+ if (r == 0)
+ return true;
- return r;
+ return parse_boolean(value) != 0;
}
int proc_cmdline(char **ret) {
- int r;
-
- if (detect_container(NULL) > 0) {
- char *buf = NULL, *p;
- size_t sz = 0;
-
- r = read_full_file("/proc/1/cmdline", &buf, &sz);
- if (r < 0)
- return r;
-
- for (p = buf; p + 1 < buf + sz; p++)
- if (*p == 0)
- *p = ' ';
-
- *p = 0;
- *ret = buf;
- return 1;
- }
-
- r = read_one_line_file("/proc/cmdline", ret);
- if (r < 0)
- return r;
+ assert(ret);
- return 1;
+ if (detect_container(NULL) > 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 *w, *state;
- size_t l;
+ const char *p;
int r;
assert(parse_item);
r = proc_cmdline(&line);
if (r < 0)
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- if (r <= 0)
- return 0;
+ return r;
- FOREACH_WORD_QUOTED(w, l, line, state) {
- char word[l+1], *value;
+ p = line;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ char *value = NULL;
- memcpy(word, w, l);
- word[l] = 0;
+ r = unquote_first_word(&p, &word, true);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
/* Filter out arguments that are intended only for the
* initrd */
@@ -6193,6 +6277,59 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
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 = unquote_first_word(&p, &word, true);
+ 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;
@@ -6363,6 +6500,10 @@ int getpeercred(int fd, struct ucred *ucred) {
* 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;
@@ -6938,19 +7079,19 @@ int is_symlink(const char *path) {
int is_dir(const char* path, bool follow) {
struct stat st;
+ int r;
- if (follow) {
- if (stat(path, &st) < 0)
- return -errno;
- } else {
- if (lstat(path, &st) < 0)
- return -errno;
- }
+ if (follow)
+ r = stat(path, &st);
+ else
+ r = lstat(path, &st);
+ if (r < 0)
+ return -errno;
return !!S_ISDIR(st.st_mode);
}
-int unquote_first_word(const char **p, char **ret) {
+int unquote_first_word(const char **p, char **ret, bool relax) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
@@ -7009,8 +7150,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case VALUE_ESCAPE:
- if (c == 0)
+ if (c == 0) {
+ if (relax)
+ goto finish;
return -EINVAL;
+ }
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@@ -7021,9 +7165,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case SINGLE_QUOTE:
- if (c == 0)
+ if (c == 0) {
+ if (relax)
+ goto finish;
return -EINVAL;
- else if (c == '\'')
+ } else if (c == '\'')
state = VALUE;
else if (c == '\\')
state = SINGLE_QUOTE_ESCAPE;
@@ -7037,8 +7183,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case SINGLE_QUOTE_ESCAPE:
- if (c == 0)
+ if (c == 0) {
+ if (relax)
+ goto finish;
return -EINVAL;
+ }
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@@ -7064,8 +7213,11 @@ int unquote_first_word(const char **p, char **ret) {
break;
case DOUBLE_QUOTE_ESCAPE:
- if (c == 0)
+ if (c == 0) {
+ if (relax)
+ goto finish;
return -EINVAL;
+ }
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@@ -7125,7 +7277,7 @@ int unquote_many_words(const char **p, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
- r = unquote_first_word(p, &l[c]);
+ r = unquote_first_word(p, &l[c], false);
if (r < 0) {
int j;
diff --git a/src/shared/util.h b/src/shared/util.h
index 35584467c1..73bd9012fd 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -112,7 +112,7 @@
#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
-size_t page_size(void);
+size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
#define streq(a,b) (strcmp((a),(b)) == 0)
@@ -245,6 +245,9 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
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) \
@@ -260,7 +263,6 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
-int get_starttime_of_pid(pid_t pid, unsigned long long *st);
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
@@ -270,6 +272,7 @@ char **replace_env_argv(char **argv, char **env);
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);
@@ -291,6 +294,9 @@ int get_process_exe(pid_t pid, char **name);
int get_process_uid(pid_t pid, uid_t *uid);
int get_process_gid(pid_t pid, gid_t *gid);
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);
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
@@ -321,6 +327,7 @@ int make_console_stdio(void);
int dev_urandom(void *p, size_t n);
void random_bytes(void *p, size_t n);
+void initialize_srand(void);
static inline uint64_t random_u64(void) {
uint64_t u;
@@ -418,7 +425,7 @@ int sigaction_many(const struct sigaction *sa, ...);
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);
-ssize_t loop_write(int fd, const 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);
@@ -446,6 +453,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
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 is_fd_on_temporary_fs(int fd);
+
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
@@ -505,7 +514,7 @@ char *unquote(const char *s, const char *quotes);
char *normalize_env_assignment(const char *s);
int wait_for_terminate(pid_t pid, siginfo_t *status);
-int wait_for_terminate_and_warn(const char *name, pid_t pid);
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
noreturn void freeze(void);
@@ -581,8 +590,6 @@ static inline bool _pure_ in_charset(const char *s, const char* charset) {
int block_get_whole_disk(dev_t d, dev_t *ret);
-int file_is_priv_sticky(const char *p);
-
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
@@ -793,6 +800,15 @@ static inline void _reset_errno_(int *saved_errno) {
#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno
+static inline int negative_errno(void) {
+ /* This helper should be used to shut up gcc if you know 'errno' is
+ * negative. Instead of "return -errno;", use "return negative_errno();"
+ * It will suppress bogus gcc warnings in case it assumes 'errno' might
+ * be 0 and thus the caller's error-handling might not be triggered. */
+ assert_return(errno > 0, -EINVAL);
+ return -errno;
+}
+
struct _umask_struct_ {
mode_t mask;
bool quit;
@@ -829,6 +845,21 @@ static inline int log2i(int x) {
return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1;
}
+static inline unsigned log2u(unsigned x) {
+ assert(x > 0);
+
+ return sizeof(unsigned) * 8 - __builtin_clz(x) - 1;
+}
+
+static inline unsigned log2u_round_up(unsigned x) {
+ assert(x > 0);
+
+ if (x == 1)
+ return 0;
+
+ return log2u(x - 1) + 1;
+}
+
static inline bool logind_running(void) {
return access("/run/systemd/seats/", F_OK) >= 0;
}
@@ -942,6 +973,7 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size,
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);
@@ -993,9 +1025,16 @@ int take_password_lock(const char *root);
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
-int unquote_first_word(const char **p, char **ret);
+int unquote_first_word(const char **p, char **ret, bool relax);
int unquote_many_words(const char **p, ...) _sentinel_;
int free_and_strdup(char **p, const char *s);
int sethostname_idempotent(const char *s);
+
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
+
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
+ for ((e) = (struct inotify_event*) (buffer); \
+ (uint8_t*) (e) < (uint8_t*) (buffer) + (sz); \
+ (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
diff --git a/src/shared/virt.c b/src/shared/virt.c
index f9c4e67c74..f10baab40b 100644
--- a/src/shared/virt.c
+++ b/src/shared/virt.c
@@ -293,8 +293,26 @@ int detect_container(const char **id) {
r = read_one_line_file("/run/systemd/container", &m);
if (r == -ENOENT) {
- r = 0;
- goto finish;
+
+ /* Fallback for cases where PID 1 was not
+ * systemd (for example, cases where
+ * init=/bin/sh is used. */
+
+ r = getenv_for_pid(1, "container", &m);
+ if (r <= 0) {
+
+ /* If that didn't work, give up,
+ * assume no container manager.
+ *
+ * Note: This means we still cannot
+ * detect containers if init=/bin/sh
+ * is passed but privileges dropped,
+ * as /proc/1/environ is only readable
+ * with privileges. */
+
+ r = 0;
+ goto finish;
+ }
}
if (r < 0)
return r;
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
index 7d188d98e8..2fe4eb81cf 100644
--- a/src/shared/watchdog.c
+++ b/src/shared/watchdog.c
@@ -44,36 +44,28 @@ static int update_timeout(void) {
flags = WDIOS_DISABLECARD;
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
- if (r < 0) {
- log_warning("Failed to disable hardware watchdog: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
} else {
int sec, flags;
char buf[FORMAT_TIMESPAN_MAX];
sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC);
r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec);
- if (r < 0) {
- log_warning("Failed to set timeout to %is: %m", sec);
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Failed to set timeout to %is: %m", sec);
watchdog_timeout = (usec_t) sec * USEC_PER_SEC;
log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout, 0));
flags = WDIOS_ENABLECARD;
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
- if (r < 0) {
- log_warning("Failed to enable hardware watchdog: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Failed to enable hardware watchdog: %m");
r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
- if (r < 0) {
- log_warning("Failed to ping hardware watchdog: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
}
return 0;
@@ -127,10 +119,8 @@ int watchdog_ping(void) {
}
r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0);
- if (r < 0) {
- log_warning("Failed to ping hardware watchdog: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_warning_errno(errno, "Failed to ping hardware watchdog: %m");
return 0;
}
@@ -148,7 +138,7 @@ void watchdog_close(bool disarm) {
flags = WDIOS_DISABLECARD;
r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags);
if (r < 0)
- log_warning("Failed to disable hardware watchdog: %m");
+ log_warning_errno(errno, "Failed to disable hardware watchdog: %m");
/* To be sure, use magic close logic, too */
for (;;) {
@@ -158,7 +148,7 @@ void watchdog_close(bool disarm) {
break;
if (errno != EINTR) {
- log_error("Failed to disarm watchdog timer: %m");
+ log_error_errno(errno, "Failed to disarm watchdog timer: %m");
break;
}
}
diff --git a/src/shutdownd/shutdownd.c b/src/shutdownd/shutdownd.c
index 0f008a6100..826efbfeab 100644
--- a/src/shutdownd/shutdownd.c
+++ b/src/shutdownd/shutdownd.c
@@ -79,7 +79,7 @@ static int read_packet(int fd, union shutdown_buffer *_b) {
if (errno == EAGAIN || errno == EINTR)
return 0;
- log_error("recvmsg(): %m");
+ log_error_errno(errno, "recvmsg(): %m");
return -errno;
}
@@ -203,20 +203,16 @@ static int update_schedule_file(struct sd_shutdown_command *c) {
assert(c);
r = mkdir_safe_label("/run/systemd/shutdown", 0755, 0, 0);
- if (r < 0) {
- log_error("Failed to create shutdown subdirectory: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create shutdown subdirectory: %m");
t = cescape(c->wall_message);
if (!t)
return log_oom();
r = fopen_temporary("/run/systemd/shutdown/scheduled", &f, &temp_path);
- if (r < 0) {
- log_error("Failed to save information about scheduled shutdowns: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to save information about scheduled shutdowns: %m");
fchmod(fileno(f), 0644);
@@ -237,7 +233,7 @@ static int update_schedule_file(struct sd_shutdown_command *c) {
fflush(f);
if (ferror(f) || rename(temp_path, "/run/systemd/shutdown/scheduled") < 0) {
- log_error("Failed to write information about scheduled shutdowns: %m");
+ log_error_errno(errno, "Failed to write information about scheduled shutdowns: %m");
r = -errno;
unlink(temp_path);
@@ -284,7 +280,7 @@ int main(int argc, char *argv[]) {
n_fds = sd_listen_fds(true);
if (n_fds < 0) {
- log_error("Failed to read listening file descriptors from environment: %s", strerror(-r));
+ log_error_errno(r, "Failed to read listening file descriptors from environment: %m");
return EXIT_FAILURE;
}
@@ -300,7 +296,7 @@ int main(int argc, char *argv[]) {
pollfd[i].events = POLLIN;
pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
if (pollfd[i].fd < 0) {
- log_error("timerfd_create(): %m");
+ log_error_errno(errno, "timerfd_create(): %m");
goto finish;
}
}
@@ -321,7 +317,7 @@ int main(int argc, char *argv[]) {
if (errno == EAGAIN || errno == EINTR)
continue;
- log_error("poll(): %m");
+ log_error_errno(errno, "poll(): %m");
goto finish;
}
@@ -358,7 +354,7 @@ int main(int argc, char *argv[]) {
warn_wall(n, &b.command);
}
if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error("timerfd_settime(): %m");
+ log_error_errno(errno, "timerfd_settime(): %m");
goto finish;
}
@@ -366,7 +362,7 @@ int main(int argc, char *argv[]) {
zero(its);
timespec_store(&its.it_value, when_nologin(b.command.usec));
if (timerfd_settime(pollfd[FD_NOLOGIN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error("timerfd_settime(): %m");
+ log_error_errno(errno, "timerfd_settime(): %m");
goto finish;
}
@@ -374,7 +370,7 @@ int main(int argc, char *argv[]) {
zero(its);
timespec_store(&its.it_value, b.command.usec);
if (timerfd_settime(pollfd[FD_SHUTDOWN_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error("timerfd_settime(): %m");
+ log_error_errno(errno, "timerfd_settime(): %m");
goto finish;
}
@@ -398,7 +394,7 @@ int main(int argc, char *argv[]) {
/* Restart timer */
timespec_store(&its.it_value, when_wall(n, b.command.usec));
if (timerfd_settime(pollfd[FD_WALL_TIMER].fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) {
- log_error("timerfd_settime(): %m");
+ log_error_errno(errno, "timerfd_settime(): %m");
goto finish;
}
}
@@ -410,7 +406,7 @@ int main(int argc, char *argv[]) {
e = write_string_file_atomic("/run/nologin", "System is going down.");
if (e < 0)
- log_error("Failed to create /run/nologin: %s", strerror(-e));
+ log_error_errno(e, "Failed to create /run/nologin: %m");
else
unlink_nologin = true;
@@ -452,7 +448,7 @@ finish:
(b.command.warn_wall ? NULL : "--no-wall"),
NULL);
- log_error("Failed to execute /sbin/shutdown: %m");
+ log_error_errno(errno, "Failed to execute /sbin/shutdown: %m");
}
sd_notify(false,
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index ca00eea4ab..56b963a729 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -48,15 +48,14 @@ static int write_mode(char **modes) {
if (k == 0)
return 0;
- log_debug("Failed to write '%s' to /sys/power/disk: %s",
- *mode, strerror(-k));
+ log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
+ *mode);
if (r == 0)
r = k;
}
if (r < 0)
- log_error("Failed to write mode to /sys/power/disk: %s",
- strerror(-r));
+ log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
return r;
}
@@ -71,51 +70,49 @@ static int write_state(FILE **f, char **states) {
k = write_string_stream(*f, *state);
if (k == 0)
return 0;
- log_debug("Failed to write '%s' to /sys/power/state: %s",
- *state, strerror(-k));
+ log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
+ *state);
if (r == 0)
r = k;
fclose(*f);
*f = fopen("/sys/power/state", "we");
- if (!*f) {
- log_error("Failed to open /sys/power/state: %m");
- return -errno;
- }
+ if (!*f)
+ return log_error_errno(errno, "Failed to open /sys/power/state: %m");
}
return r;
}
static int execute(char **modes, char **states) {
- char* arguments[4];
+
+ char *arguments[] = {
+ NULL,
+ (char*) "pre",
+ arg_verb,
+ NULL
+ };
+
int r;
_cleanup_fclose_ FILE *f = NULL;
- const char* note = strappenda("SLEEP=", arg_verb);
/* This file is opened first, so that if we hit an error,
* we can abort before modifying any state. */
f = fopen("/sys/power/state", "we");
- if (!f) {
- log_error("Failed to open /sys/power/state: %m");
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to open /sys/power/state: %m");
/* Configure the hibernation mode */
r = write_mode(modes);
if (r < 0)
return r;
- arguments[0] = NULL;
- arguments[1] = (char*) "pre";
- arguments[2] = arg_verb;
- arguments[3] = NULL;
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_START),
- "MESSAGE=Suspending system...",
- note,
+ LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+ LOG_MESSAGE("Suspending system..."),
+ "SLEEP=%s", arg_verb,
NULL);
r = write_state(&f, states);
@@ -123,9 +120,9 @@ static int execute(char **modes, char **states) {
return r;
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
- "MESSAGE=System resumed.",
- note,
+ LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
+ LOG_MESSAGE("System resumed."),
+ "SLEEP=%s", arg_verb,
NULL);
arguments[1] = (char*) "post";
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 3041903757..a3c3c87f11 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -120,18 +120,14 @@ static int connection_create_pipes(Connection *c, int buffer[2], size_t *sz) {
return 0;
r = pipe2(buffer, O_CLOEXEC|O_NONBLOCK);
- if (r < 0) {
- log_error("Failed to allocate pipe buffer: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to allocate pipe buffer: %m");
(void) fcntl(buffer[0], F_SETPIPE_SZ, BUFFER_SIZE);
r = fcntl(buffer[0], F_GETPIPE_SZ);
- if (r < 0) {
- log_error("Failed to get pipe buffer size: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to get pipe buffer size: %m");
assert(r > 0);
*sz = r;
@@ -171,10 +167,8 @@ static int connection_shovel(
} else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
*from_source = sd_event_source_unref(*from_source);
*from = safe_close(*from);
- } else if (errno != EAGAIN && errno != EINTR) {
- log_error("Failed to splice: %m");
- return -errno;
- }
+ } else if (errno != EAGAIN && errno != EINTR)
+ return log_error_errno(errno, "Failed to splice: %m");
}
if (*full > 0 && *to >= 0) {
@@ -185,10 +179,8 @@ static int connection_shovel(
} else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
*to_source = sd_event_source_unref(*to_source);
*to = safe_close(*to);
- } else if (errno != EAGAIN && errno != EINTR) {
- log_error("Failed to splice: %m");
- return -errno;
- }
+ } else if (errno != EAGAIN && errno != EINTR)
+ return log_error_errno(errno, "Failed to splice: %m");
}
} while (shoveled);
@@ -265,10 +257,8 @@ static int connection_enable_event_sources(Connection *c) {
else
r = 0;
- if (r < 0) {
- log_error("Failed to set up server event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up server event source: %m");
if (c->client_event_source)
r = sd_event_source_set_io_events(c->client_event_source, b);
@@ -277,10 +267,8 @@ static int connection_enable_event_sources(Connection *c) {
else
r = 0;
- if (r < 0) {
- log_error("Failed to set up client event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up client event source: %m");
return 0;
}
@@ -321,12 +309,12 @@ static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userda
solen = sizeof(error);
r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &solen);
if (r < 0) {
- log_error("Failed to issue SO_ERROR: %m");
+ log_error_errno(errno, "Failed to issue SO_ERROR: %m");
goto fail;
}
if (error != 0) {
- log_error("Failed to connect to remote host: %s", strerror(error));
+ log_error_errno(error, "Failed to connect to remote host: %m");
goto fail;
}
@@ -348,7 +336,7 @@ static int connection_start(Connection *c, struct sockaddr *sa, socklen_t salen)
c->client_fd = socket(sa->sa_family, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
if (c->client_fd < 0) {
- log_error("Failed to get remote socket: %m");
+ log_error_errno(errno, "Failed to get remote socket: %m");
goto fail;
}
@@ -357,17 +345,17 @@ static int connection_start(Connection *c, struct sockaddr *sa, socklen_t salen)
if (errno == EINPROGRESS) {
r = sd_event_add_io(c->context->event, &c->client_event_source, c->client_fd, EPOLLOUT, connect_cb, c);
if (r < 0) {
- log_error("Failed to add connection socket: %s", strerror(-r));
+ log_error_errno(r, "Failed to add connection socket: %m");
goto fail;
}
r = sd_event_source_set_enabled(c->client_event_source, SD_EVENT_ONESHOT);
if (r < 0) {
- log_error("Failed to enable oneshot event source: %s", strerror(-r));
+ log_error_errno(r, "Failed to enable oneshot event source: %m");
goto fail;
}
} else {
- log_error("Failed to connect to remote host: %m");
+ log_error_errno(errno, "Failed to connect to remote host: %m");
goto fail;
}
} else {
@@ -449,7 +437,7 @@ static int resolve_remote(Connection *c) {
log_debug("Looking up address info for %s:%s", node, service);
r = sd_resolve_getaddrinfo(c->context->resolve, &c->resolve_query, node, service, &hints, resolve_cb, c);
if (r < 0) {
- log_error("Failed to resolve remote host: %s", strerror(-r));
+ log_error_errno(r, "Failed to resolve remote host: %m");
goto fail;
}
@@ -514,21 +502,21 @@ static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdat
nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (nfd < 0) {
if (errno != -EAGAIN)
- log_warning("Failed to accept() socket: %m");
+ log_warning_errno(errno, "Failed to accept() socket: %m");
} else {
getpeername_pretty(nfd, &peer);
log_debug("New connection from %s", strna(peer));
r = add_connection_socket(context, nfd);
if (r < 0) {
- log_error("Failed to accept connection, ignoring: %s", strerror(-r));
+ log_error_errno(r, "Failed to accept connection, ignoring: %m");
safe_close(fd);
}
}
r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
if (r < 0) {
- log_error("Error while re-enabling listener with ONESHOT: %s", strerror(-r));
+ log_error_errno(r, "Error while re-enabling listener with ONESHOT: %m");
sd_event_exit(context->event, r);
return r;
}
@@ -550,30 +538,24 @@ static int add_listen_socket(Context *context, int fd) {
}
r = sd_is_socket(fd, 0, SOCK_STREAM, 1);
- if (r < 0) {
- log_error("Failed to determine socket type: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine socket type: %m");
if (r == 0) {
log_error("Passed in socket is not a stream socket.");
return -EINVAL;
}
r = fd_nonblock(fd, true);
- if (r < 0) {
- log_error("Failed to mark file descriptor non-blocking: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to mark file descriptor non-blocking: %m");
r = sd_event_add_io(context->event, &source, fd, EPOLLIN, accept_cb, context);
- if (r < 0) {
- log_error("Failed to add event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add event source: %m");
r = set_put(context->listen, source);
if (r < 0) {
- log_error("Failed to add source to set: %s", strerror(-r));
+ log_error_errno(r, "Failed to add source to set: %m");
sd_event_source_unref(source);
return r;
}
@@ -581,10 +563,8 @@ static int add_listen_socket(Context *context, int fd) {
/* Set the watcher to oneshot in case other processes are also
* watching to accept(). */
r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
- if (r < 0) {
- log_error("Failed to enable oneshot mode: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable oneshot mode: %m");
return 0;
}
@@ -663,19 +643,19 @@ int main(int argc, char *argv[]) {
r = sd_event_default(&context.event);
if (r < 0) {
- log_error("Failed to allocate event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate event loop: %m");
goto finish;
}
r = sd_resolve_default(&context.resolve);
if (r < 0) {
- log_error("Failed to allocate resolver: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate resolver: %m");
goto finish;
}
r = sd_resolve_attach_event(context.resolve, context.event, 0);
if (r < 0) {
- log_error("Failed to attach resolver: %s", strerror(-r));
+ log_error_errno(r, "Failed to attach resolver: %m");
goto finish;
}
@@ -700,7 +680,7 @@ int main(int argc, char *argv[]) {
r = sd_event_loop(context.event);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 809e59b71f..973e67e3c8 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -38,15 +38,7 @@
static char **arg_prefixes = NULL;
-static const char conf_file_dirs[] =
- "/etc/sysctl.d\0"
- "/run/sysctl.d\0"
- "/usr/local/lib/sysctl.d\0"
- "/usr/lib/sysctl.d\0"
-#ifdef HAVE_SPLIT_USR
- "/lib/sysctl.d\0"
-#endif
- ;
+static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl");
static char* normalize_sysctl(char *s) {
char *n;
@@ -142,8 +134,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
if (ignore_enoent && r == -ENOENT)
return 0;
- log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
}
log_debug("parse: %s", path);
@@ -156,7 +147,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
if (feof(f))
break;
- log_error("Failed to read file '%s', ignoring: %m", path);
+ log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
return -errno;
}
@@ -204,7 +195,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
k = hashmap_put(sysctl_options, property, new_value);
if (k < 0) {
- log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-k));
+ log_error_errno(k, "Failed to add sysctl variable %s to hashmap: %m", property);
free(property);
free(new_value);
return k;
@@ -322,7 +313,7 @@ int main(int argc, char *argv[]) {
r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
if (r < 0) {
- log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
+ log_error_errno(r, "Failed to enumerate sysctl.d files: %m");
goto finish;
}
diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c
index 4f22c9c359..464ee22b20 100644
--- a/src/system-update-generator/system-update-generator.c
+++ b/src/system-update-generator/system-update-generator.c
@@ -41,15 +41,13 @@ static int generate_symlink(void) {
if (errno == ENOENT)
return 0;
- log_error("Failed to check for system update: %m");
+ log_error_errno(errno, "Failed to check for system update: %m");
return -EINVAL;
}
p = strappenda(arg_dest, "/default.target");
- if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0) {
- log_error("Failed to create symlink %s: %m", p);
- return -errno;
- }
+ if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0)
+ return log_error_errno(errno, "Failed to create symlink %s: %m", p);
return 0;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 28eaa6a847..b1441ad86a 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -67,11 +67,13 @@
#include "logs-show.h"
#include "socket-util.h"
#include "fileio.h"
+#include "copy.h"
#include "env-util.h"
#include "bus-util.h"
#include "bus-message.h"
#include "bus-error.h"
-#include "bus-errors.h"
+#include "bus-common-errors.h"
+#include "mkdir.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -301,21 +303,37 @@ static int compare_unit_info(const void *a, const void *b) {
}
static bool output_show_unit(const UnitInfo *u, char **patterns) {
- const char *dot;
-
if (!strv_isempty(patterns)) {
char **pattern;
STRV_FOREACH(pattern, patterns)
if (fnmatch(*pattern, u->id, FNM_NOESCAPE) == 0)
- return true;
+ goto next;
return false;
}
- return (!arg_types || ((dot = strrchr(u->id, '.')) &&
- strv_find(arg_types, dot+1))) &&
- (arg_all || !(streq(u->active_state, "inactive")
- || u->following[0]) || u->job_id > 0);
+next:
+ if (arg_types) {
+ const char *dot;
+
+ dot = strrchr(u->id, '.');
+ if (!dot)
+ return false;
+
+ if (!strv_find(arg_types, dot+1))
+ return false;
+ }
+
+ if (arg_all)
+ return true;
+
+ if (u->job_id > 0)
+ return true;
+
+ if (streq(u->active_state, "inactive") || u->following[0])
+ return false;
+
+ return true;
}
static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
@@ -605,7 +623,7 @@ static int get_unit_list_recursive(
r = sd_bus_open_system_container(&container, *i);
if (r < 0) {
- log_error("Failed to connect to container %s: %s", *i, strerror(-r));
+ log_error_errno(r, "Failed to connect to container %s: %m", *i);
continue;
}
@@ -1231,18 +1249,33 @@ static int compare_unit_file_list(const void *a, const void *b) {
}
static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
- const char *dot;
-
if (!strv_isempty(patterns)) {
char **pattern;
STRV_FOREACH(pattern, patterns)
if (fnmatch(*pattern, basename(u->path), FNM_NOESCAPE) == 0)
- return true;
+ goto next;
return false;
}
- return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
+next:
+ if (!strv_isempty(arg_types)) {
+ const char *dot;
+
+ dot = strrchr(u->path, '.');
+ if (!dot)
+ return false;
+
+ if (!strv_find(arg_types, dot+1))
+ return false;
+ }
+
+ if (!strv_isempty(arg_states)) {
+ if (!strv_find(arg_states, unit_file_state_to_string(u->state)))
+ return false;
+ }
+
+ return true;
}
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
@@ -1328,7 +1361,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
r = unit_file_get_list(arg_scope, arg_root, h);
if (r < 0) {
unit_file_list_free(h);
- log_error("Failed to get unit file list: %s", strerror(-r));
+ log_error_errno(r, "Failed to get unit file list: %m");
return r;
}
@@ -1448,11 +1481,13 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
"RequiresOverridable\0"
"Requisite\0"
"RequisiteOverridable\0"
- "Wants\0",
+ "Wants\0"
+ "BindsTo\0",
[DEPENDENCY_REVERSE] = "RequiredBy\0"
"RequiredByOverridable\0"
"WantedBy\0"
- "PartOf\0",
+ "PartOf\0"
+ "BoundBy\0",
[DEPENDENCY_AFTER] = "After\0",
[DEPENDENCY_BEFORE] = "Before\0",
};
@@ -1872,10 +1907,8 @@ static int get_default(sd_bus *bus, char **args) {
if (!bus || avoid_bus()) {
r = unit_file_get_default(arg_scope, arg_root, &_path);
- if (r < 0) {
- log_error("Failed to get default target: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get default target: %m");
path = _path;
} else {
@@ -1955,10 +1988,8 @@ static int set_default(sd_bus *bus, char **args) {
if (!bus || avoid_bus()) {
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
- if (r < 0) {
- log_error("Failed to set default target: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default target: %m");
if (!arg_quiet)
dump_unit_file_changes(changes, n_changes);
@@ -2166,10 +2197,8 @@ static int cancel_job(sd_bus *bus, char **args) {
int q;
q = safe_atou32(*name, &id);
- if (q < 0) {
- log_error("Failed to parse job id \"%s\": %s", *name, strerror(-q));
- return q;
- }
+ if (q < 0)
+ return log_error_errno(q, "Failed to parse job id \"%s\": %m", *name);
q = sd_bus_message_new_method_call(
bus,
@@ -2397,10 +2426,8 @@ static int wait_for_jobs(sd_bus *bus, Set *s) {
while (!set_isempty(s)) {
q = bus_process_wait(bus);
- if (q < 0) {
- log_error("Failed to wait for response: %s", strerror(-q));
- return q;
- }
+ if (q < 0)
+ return log_error_errno(q, "Failed to wait for response: %m");
if (d.result) {
q = check_wait_response(&d);
@@ -2526,10 +2553,8 @@ static int check_triggering_units(
STRV_FOREACH(i, triggered_by) {
r = check_one_unit(bus, *i, "active\0reloading\0", true);
- if (r < 0) {
- log_error("Failed to check unit: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to check unit: %m");
if (r == 0)
continue;
@@ -2773,15 +2798,13 @@ static int start_unit(sd_bus *bus, char **args) {
else {
r = expand_names(bus, args + 1, suffix, &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
}
if (!arg_no_block) {
r = enable_wait_for_jobs(bus);
- if (r < 0) {
- log_error("Could not watch jobs: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not watch jobs: %m");
s = set_new(&string_hash_ops);
if (!s)
@@ -3040,10 +3063,8 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
assert(args);
r = expand_names(bus, args, NULL, &names);
- if (r < 0) {
- log_error("Failed to expand names: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
int state;
@@ -3081,7 +3102,7 @@ static int kill_unit(sd_bus *bus, char **args) {
r = expand_names(bus, args + 1, NULL, &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
@@ -3199,6 +3220,7 @@ typedef struct UnitStatusInfo {
const char *active_state;
const char *sub_state;
const char *unit_file_state;
+ const char *unit_file_preset;
const char *description;
const char *following;
@@ -3240,7 +3262,14 @@ typedef struct UnitStatusInfo {
bool failed_condition_trigger;
bool failed_condition_negate;
const char *failed_condition;
- const char *failed_condition_param;
+ const char *failed_condition_parameter;
+
+ usec_t assert_timestamp;
+ bool assert_result;
+ bool failed_assert_trigger;
+ bool failed_assert_negate;
+ const char *failed_assert;
+ const char *failed_assert_parameter;
/* Socket */
unsigned n_accepted;
@@ -3315,7 +3344,10 @@ static void print_status_info(
if (i->load_error)
printf(" Loaded: %s%s%s (Reason: %s)\n",
on, strna(i->load_state), off, i->load_error);
- else if (path && i->unit_file_state)
+ else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset))
+ printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
+ on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
+ else if (path && !isempty(i->unit_file_state))
printf(" Loaded: %s%s%s (%s; %s)\n",
on, strna(i->load_state), off, path, i->unit_file_state);
else if (path)
@@ -3384,7 +3416,8 @@ static void print_status_info(
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
- printf(" start condition failed at %s%s%s\n",
+ printf("Condition: start %scondition failed%s at %s%s%s\n",
+ ansi_highlight_yellow(), ansi_highlight_off(),
s2, s1 ? "; " : "", s1 ? s1 : "");
if (i->failed_condition_trigger)
printf(" none of the trigger conditions were met\n");
@@ -3392,7 +3425,23 @@ static void print_status_info(
printf(" %s=%s%s was not met\n",
i->failed_condition,
i->failed_condition_negate ? "!" : "",
- i->failed_condition_param);
+ i->failed_condition_parameter);
+ }
+
+ if (!i->assert_result && i->assert_timestamp > 0) {
+ s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
+ s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
+
+ printf(" Assert: start %sassertion failed%s at %s%s%s\n",
+ ansi_highlight_red(), ansi_highlight_off(),
+ s2, s1 ? "; " : "", s1 ? s1 : "");
+ if (i->failed_assert_trigger)
+ printf(" none of the trigger assertions were met\n");
+ else if (i->failed_assert)
+ printf(" %s=%s%s was not met\n",
+ i->failed_assert,
+ i->failed_assert_negate ? "!" : "",
+ i->failed_assert_parameter);
}
if (i->sysfs_path)
@@ -3623,6 +3672,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->following = s;
else if (streq(name, "UnitFileState"))
i->unit_file_state = s;
+ else if (streq(name, "UnitFilePreset"))
+ i->unit_file_preset = s;
else if (streq(name, "Result"))
i->result = s;
}
@@ -3643,6 +3694,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->need_daemon_reload = b;
else if (streq(name, "ConditionResult"))
i->condition_result = b;
+ else if (streq(name, "AssertResult"))
+ i->assert_result = b;
break;
}
@@ -3712,6 +3765,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->active_exit_timestamp = (usec_t) u;
else if (streq(name, "ConditionTimestamp"))
i->condition_timestamp = (usec_t) u;
+ else if (streq(name, "AssertTimestamp"))
+ i->assert_timestamp = (usec_t) u;
break;
}
@@ -3804,7 +3859,32 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->failed_condition = cond;
i->failed_condition_trigger = trigger;
i->failed_condition_negate = negate;
- i->failed_condition_param = param;
+ i->failed_condition_parameter = param;
+ }
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
+ const char *cond, *param;
+ int trigger, negate;
+ int32_t state;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
+ log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
+ if (state < 0 && (!trigger || !i->failed_assert)) {
+ i->failed_assert = cond;
+ i->failed_assert_trigger = trigger;
+ i->failed_assert_negate = negate;
+ i->failed_assert_parameter = param;
}
}
if (r < 0)
@@ -4351,10 +4431,8 @@ static int show_system_status(sd_bus *bus) {
return log_oom();
r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
- if (r < 0) {
- log_error("Failed to read server status: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read server status: %m");
if (streq_ptr(mi.state, "degraded")) {
on = ansi_highlight_red();
@@ -4471,7 +4549,7 @@ static int show(sd_bus *bus, char **args) {
r = expand_names(bus, patterns, NULL, &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_free_ char *unit;
@@ -4507,7 +4585,7 @@ static int cat(sd_bus *bus, char **args) {
r = expand_names(bus, args + 1, NULL, &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
pager_open_if_enabled();
@@ -4563,9 +4641,9 @@ static int cat(sd_bus *bus, char **args) {
ansi_highlight_off());
fflush(stdout);
- r = sendfile_full(STDOUT_FILENO, fragment_path);
+ r = copy_file_fd(fragment_path, STDOUT_FILENO);
if (r < 0) {
- log_warning("Failed to cat %s: %s", fragment_path, strerror(-r));
+ log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
continue;
}
}
@@ -4578,9 +4656,9 @@ static int cat(sd_bus *bus, char **args) {
ansi_highlight_off());
fflush(stdout);
- r = sendfile_full(STDOUT_FILENO, *path);
+ r = copy_file_fd(*path, STDOUT_FILENO);
if (r < 0) {
- log_warning("Failed to cat %s: %s", *path, strerror(-r));
+ log_warning_errno(r, "Failed to cat %s: %m", *path);
continue;
}
}
@@ -4720,7 +4798,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
r = expand_names(bus, args + 1, ".snapshot", &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
@@ -4821,7 +4899,7 @@ static int reset_failed(sd_bus *bus, char **args) {
r = expand_names(bus, args + 1, NULL, &names);
if (r < 0)
- log_error("Failed to expand names: %s", strerror(-r));
+ log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
@@ -4915,7 +4993,7 @@ static int switch_root(sd_bus *bus, char **args) {
"init", &cmdline_init,
NULL);
if (r < 0)
- log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
+ log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
init = cmdline_init;
}
@@ -5065,7 +5143,7 @@ static int enable_sysv_units(const char *verb, char **args) {
int r = 0;
#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
- unsigned f = 1, t = 1;
+ unsigned f = 0;
_cleanup_lookup_paths_free_ LookupPaths paths = {};
if (arg_scope != UNIT_FILE_SYSTEM)
@@ -5084,7 +5162,7 @@ static int enable_sysv_units(const char *verb, char **args) {
return r;
r = 0;
- for (f = 0; args[f]; f++) {
+ while (args[f]) {
const char *name;
_cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
bool found_native = false, found_sysv;
@@ -5095,7 +5173,7 @@ static int enable_sysv_units(const char *verb, char **args) {
pid_t pid;
siginfo_t status;
- name = args[f];
+ name = args[f++];
if (!endswith(name, ".service"))
continue;
@@ -5127,9 +5205,6 @@ static int enable_sysv_units(const char *verb, char **args) {
if (!found_sysv)
continue;
- /* Mark this entry, so that we don't try enabling it as native unit */
- args[f] = (char*) "";
-
log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
if (!isempty(arg_root))
@@ -5148,10 +5223,9 @@ static int enable_sysv_units(const char *verb, char **args) {
log_info("Executing %s", l);
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork: %m");
- return -errno;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
+ else if (pid == 0) {
/* Child */
execv(argv[0], (char**) argv);
@@ -5160,7 +5234,7 @@ static int enable_sysv_units(const char *verb, char **args) {
j = wait_for_terminate(pid, &status);
if (j < 0) {
- log_error("Failed to wait for child: %s", strerror(-r));
+ log_error_errno(r, "Failed to wait for child: %m");
return j;
}
@@ -5179,19 +5253,12 @@ static int enable_sysv_units(const char *verb, char **args) {
return -EINVAL;
} else
return -EPROTO;
- }
-
- /* Drop all SysV units */
- for (f = 0, t = 0; args[f]; f++) {
-
- if (isempty(args[f]))
- continue;
- args[t++] = args[f];
+ /* Remove this entry, so that we don't try enabling it as native unit */
+ assert(f > 0 && streq(args[f-1], name));
+ assert_se(strv_remove(args + f - 1, name));
}
- args[t] = NULL;
-
#endif
return r;
}
@@ -5274,7 +5341,7 @@ static int enable_unit(sd_bus *bus, char **args) {
assert_not_reached("Unknown verb");
if (r < 0) {
- log_error("Operation failed: %s", strerror(-r));
+ log_error_errno(r, "Operation failed: %m");
goto finish;
}
@@ -5422,10 +5489,8 @@ static int add_dependency(sd_bus *bus, char **args) {
r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
- if (r < 0) {
- log_error("Can't add dependency: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Can't add dependency: %m");
if (!arg_quiet)
dump_unit_file_changes(changes, n_changes);
@@ -5486,7 +5551,7 @@ static int preset_all(sd_bus *bus, char **args) {
r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
if (r < 0) {
- log_error("Operation failed: %s", strerror(-r));
+ log_error_errno(r, "Operation failed: %m");
goto finish;
}
@@ -5568,14 +5633,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
UnitFileState state;
state = unit_file_get_state(arg_scope, arg_root, *name);
- if (state < 0) {
- log_error("Failed to get unit file state for %s: %s", *name, strerror(-state));
- return state;
- }
+ if (state < 0)
+ return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
if (state == UNIT_FILE_ENABLED ||
state == UNIT_FILE_ENABLED_RUNTIME ||
- state == UNIT_FILE_STATIC)
+ state == UNIT_FILE_STATIC ||
+ state == UNIT_FILE_INDIRECT)
enabled = true;
if (!arg_quiet)
@@ -5605,9 +5669,7 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_parse_error(r);
- if (streq(s, "enabled") ||
- streq(s, "enabled-runtime") ||
- streq(s, "static"))
+ if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
enabled = true;
if (!arg_quiet)
@@ -5642,6 +5704,519 @@ static int is_system_running(sd_bus *bus, char **args) {
return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
}
+static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
+ char **p;
+
+ assert(lp);
+ assert(unit_name);
+ assert(unit_path);
+
+ STRV_FOREACH(p, lp->unit_path) {
+ char *path;
+
+ path = path_join(arg_root, *p, unit_name);
+ if (!path)
+ return log_oom();
+
+ if (access(path, F_OK) == 0) {
+ *unit_path = path;
+ return 1;
+ }
+
+ free(path);
+ }
+
+ return 0;
+}
+
+static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
+ int r;
+ char *t;
+
+ assert(new_path);
+ assert(original_path);
+ assert(ret_tmp_fn);
+
+ t = tempfn_random(new_path);
+ if (!t)
+ return log_oom();
+
+ r = mkdir_parents(new_path, 0755);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create directories for %s: %m", new_path);
+ free(t);
+ return r;
+ }
+
+ r = copy_file(original_path, t, 0, 0644);
+ if (r == -ENOENT) {
+ r = touch(t);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create temporary file %s: %m", t);
+ free(t);
+ return r;
+ }
+ } else if (r < 0) {
+ log_error_errno(r, "Failed to copy %s to %s: %m", original_path, t);
+ free(t);
+ return r;
+ }
+
+ *ret_tmp_fn = t;
+
+ return 0;
+}
+
+static int get_drop_in_to_edit(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_path) {
+ char *tmp_new_path;
+ char *tmp;
+
+ assert(unit_name);
+ assert(ret_path);
+
+ switch (arg_scope) {
+ case UNIT_FILE_SYSTEM:
+ tmp = strappenda(arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
+ break;
+ case UNIT_FILE_GLOBAL:
+ tmp = strappenda(arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
+ break;
+ case UNIT_FILE_USER:
+ assert(user_home);
+ assert(user_runtime);
+
+ tmp = strappenda(arg_runtime ? user_runtime : user_home, "/", unit_name, ".d/override.conf");
+ break;
+ default:
+ assert_not_reached("Invalid scope");
+ }
+
+ tmp_new_path = path_join(arg_root, tmp, NULL);
+ if (!tmp_new_path)
+ return log_oom();
+
+ *ret_path = tmp_new_path;
+
+ return 0;
+}
+
+static int unit_file_create_drop_in(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
+ char *tmp_new_path;
+ char *tmp_tmp_path;
+ int r;
+
+ assert(unit_name);
+ assert(ret_new_path);
+ assert(ret_tmp_path);
+
+ r = get_drop_in_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
+ if (r < 0)
+ return r;
+
+ r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
+ if (r < 0) {
+ free(tmp_new_path);
+ return r;
+ }
+
+ *ret_new_path = tmp_new_path;
+ *ret_tmp_path = tmp_tmp_path;
+
+ return 0;
+}
+
+static bool unit_is_editable(const char *unit_name, const char *fragment_path, const char *user_home) {
+ bool editable = true;
+ const char *invalid_path;
+
+ assert(unit_name);
+
+ if (!arg_runtime)
+ return true;
+
+ switch (arg_scope) {
+ case UNIT_FILE_SYSTEM:
+ if (path_startswith(fragment_path, "/etc/systemd/system")) {
+ editable = false;
+ invalid_path = "/etc/systemd/system";
+ } else if (path_startswith(fragment_path, SYSTEM_CONFIG_UNIT_PATH)) {
+ editable = false;
+ invalid_path = SYSTEM_CONFIG_UNIT_PATH;
+ }
+ break;
+ case UNIT_FILE_GLOBAL:
+ if (path_startswith(fragment_path, "/etc/systemd/user")) {
+ editable = false;
+ invalid_path = "/etc/systemd/user";
+ } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
+ editable = false;
+ invalid_path = USER_CONFIG_UNIT_PATH;
+ }
+ break;
+ case UNIT_FILE_USER:
+ assert(user_home);
+
+ if (path_startswith(fragment_path, "/etc/systemd/user")) {
+ editable = false;
+ invalid_path = "/etc/systemd/user";
+ } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
+ editable = false;
+ invalid_path = USER_CONFIG_UNIT_PATH;
+ } else if (path_startswith(fragment_path, user_home)) {
+ editable = false;
+ invalid_path = user_home;
+ }
+ break;
+ default:
+ assert_not_reached("Invalid scope");
+ }
+
+ if (!editable)
+ log_error("%s ignored: cannot temporarily edit units from %s", unit_name, invalid_path);
+
+ return editable;
+}
+
+static int get_copy_to_edit(const char *unit_name, const char *fragment_path, const char *user_home, const char *user_runtime, char **ret_path) {
+ char *tmp_new_path;
+
+ assert(unit_name);
+ assert(ret_path);
+
+ if (!unit_is_editable(unit_name, fragment_path, user_home))
+ return -EINVAL;
+
+ switch (arg_scope) {
+ case UNIT_FILE_SYSTEM:
+ tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH, unit_name);
+ break;
+ case UNIT_FILE_GLOBAL:
+ tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH, unit_name);
+ break;
+ case UNIT_FILE_USER:
+ assert(user_home);
+ assert(user_runtime);
+
+ tmp_new_path = path_join(arg_root, arg_runtime ? user_runtime : user_home, unit_name);
+ break;
+ default:
+ assert_not_reached("Invalid scope");
+ }
+ if (!tmp_new_path)
+ return log_oom();
+
+ *ret_path = tmp_new_path;
+
+ return 0;
+}
+
+static int unit_file_create_copy(const char *unit_name,
+ const char *fragment_path,
+ const char *user_home,
+ const char *user_runtime,
+ char **ret_new_path,
+ char **ret_tmp_path) {
+ char *tmp_new_path;
+ char *tmp_tmp_path;
+ int r;
+
+ assert(fragment_path);
+ assert(unit_name);
+ assert(ret_new_path);
+ assert(ret_tmp_path);
+
+ r = get_copy_to_edit(unit_name, fragment_path, user_home, user_runtime, &tmp_new_path);
+ if (r < 0)
+ return r;
+
+ if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
+ char response;
+
+ r = ask_char(&response, "yn", "%s already exists, are you sure to overwrite it with %s? [(y)es, (n)o] ", tmp_new_path, fragment_path);
+ if (r < 0) {
+ free(tmp_new_path);
+ return r;
+ }
+ if (response != 'y') {
+ log_warning("%s ignored", unit_name);
+ free(tmp_new_path);
+ return -1;
+ }
+ }
+
+ r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create temporary file for %s: %m", tmp_new_path);
+ free(tmp_new_path);
+ return r;
+ }
+
+ *ret_new_path = tmp_new_path;
+ *ret_tmp_path = tmp_tmp_path;
+
+ return 0;
+}
+
+static int run_editor(char **paths) {
+ pid_t pid;
+ int r;
+
+ assert(paths);
+
+ pid = fork();
+ if (pid < 0) {
+ log_error_errno(errno, "Failed to fork: %m");
+ return -errno;
+ }
+
+ if (pid == 0) {
+ const char **args;
+ char **backup_editors = STRV_MAKE("nano", "vim", "vi");
+ char *editor;
+ char **tmp_path, **original_path, **p;
+ unsigned i = 1;
+ size_t argc;
+
+ argc = strv_length(paths)/2 + 1;
+ args = newa(const char*, argc + 1);
+
+ args[0] = NULL;
+ STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
+ args[i] = *tmp_path;
+ i++;
+ }
+ args[argc] = NULL;
+
+ /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
+ * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
+ * we try to execute well known editors
+ */
+ editor = getenv("SYSTEMD_EDITOR");
+ if (!editor)
+ editor = getenv("EDITOR");
+ if (!editor)
+ editor = getenv("VISUAL");
+
+ if (!isempty(editor)) {
+ args[0] = editor;
+ execvp(editor, (char* const*) args);
+ }
+
+ STRV_FOREACH(p, backup_editors) {
+ args[0] = *p;
+ execvp(*p, (char* const*) args);
+ /* We do not fail if the editor doesn't exist
+ * because we want to try each one of them before
+ * failing.
+ */
+ if (errno != ENOENT) {
+ log_error("Failed to execute %s: %m", editor);
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ log_error("Cannot edit unit(s): No editor available. Please set either SYSTEMD_EDITOR or EDITOR or VISUAL environment variable");
+ _exit(EXIT_FAILURE);
+ }
+
+ r = wait_for_terminate_and_warn("editor", pid, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to wait for child: %m");
+
+ return r;
+}
+
+static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
+ _cleanup_free_ char *user_home = NULL;
+ _cleanup_free_ char *user_runtime = NULL;
+ char **name;
+ int r;
+
+ assert(names);
+ assert(paths);
+
+ if (arg_scope == UNIT_FILE_USER) {
+ r = user_config_home(&user_home);
+ if (r < 0)
+ return log_oom();
+ else if (r == 0) {
+ log_error("Cannot edit units for the user instance: home directory unknown");
+ return -1;
+ }
+
+ r = user_runtime_dir(&user_runtime);
+ if (r < 0)
+ return log_oom();
+ else if (r == 0) {
+ log_error("Cannot edit units for the user instance: runtime directory unknown");
+ return -1;
+ }
+ }
+
+ if (!bus || avoid_bus()) {
+ _cleanup_lookup_paths_free_ LookupPaths lp = {};
+
+ /* If there is no bus, we try to find the units by testing each available directory
+ * according to the scope.
+ */
+ r = lookup_paths_init(&lp,
+ arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
+ arg_scope == UNIT_FILE_USER,
+ arg_root,
+ NULL, NULL, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed get lookup paths: %m");
+ return r;
+ }
+
+ STRV_FOREACH(name, names) {
+ _cleanup_free_ char *path = NULL;
+ char *new_path, *tmp_path;
+
+ r = unit_file_find_path(&lp, *name, &path);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ log_warning("%s ignored: not found", *name);
+ continue;
+ }
+
+ if (arg_full)
+ r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
+ else
+ r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
+
+ if (r < 0)
+ continue;
+
+ r = strv_push(paths, new_path);
+ if (r < 0)
+ return log_oom();
+
+ r = strv_push(paths, tmp_path);
+ if (r < 0)
+ return log_oom();
+ }
+ } else {
+ STRV_FOREACH(name, names) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *fragment_path = NULL;
+ _cleanup_free_ char *unit = NULL;
+ char *new_path, *tmp_path;
+
+ unit = unit_dbus_path_from_name(*name);
+ if (!unit)
+ return log_oom();
+
+ if (need_daemon_reload(bus, *name) > 0) {
+ log_warning("%s ignored: unit file changed on disk. Run 'systemctl%s daemon-reload'.",
+ *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+ continue;
+ }
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ unit,
+ "org.freedesktop.systemd1.Unit",
+ "FragmentPath",
+ &error,
+ &fragment_path);
+ if (r < 0) {
+ log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
+ continue;
+ }
+
+ if (isempty(fragment_path)) {
+ log_warning("%s ignored: not found", *name);
+ continue;
+ }
+
+ if (arg_full)
+ r = unit_file_create_copy(*name, fragment_path, user_home, user_runtime, &new_path, &tmp_path);
+ else
+ r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
+ if (r < 0)
+ continue;
+
+ r = strv_push(paths, new_path);
+ if (r < 0)
+ return log_oom();
+
+ r = strv_push(paths, tmp_path);
+ if (r < 0)
+ return log_oom();
+ }
+ }
+
+ return 0;
+}
+
+static int edit(sd_bus *bus, char **args) {
+ _cleanup_strv_free_ char **names = NULL;
+ _cleanup_strv_free_ char **paths = NULL;
+ char **original, **tmp;
+ int r;
+
+ assert(args);
+
+ if (!on_tty()) {
+ log_error("Cannot edit units if we are not on a tty");
+ return -EINVAL;
+ }
+
+ if (arg_transport != BUS_TRANSPORT_LOCAL) {
+ log_error("Cannot remotely edit units");
+ return -EINVAL;
+ }
+
+ r = expand_names(bus, args + 1, NULL, &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
+
+ if (!names) {
+ log_error("No unit name found by expanding names");
+ return -ENOENT;
+ }
+
+ r = find_paths_to_edit(bus, names, &paths);
+ if (r < 0)
+ return r;
+
+ if (strv_isempty(paths)) {
+ log_error("Cannot find any units to edit");
+ return -ENOENT;
+ }
+
+ r = run_editor(paths);
+ if (r < 0)
+ goto end;
+
+ STRV_FOREACH_PAIR(original, tmp, paths) {
+ /* If the temporary file is empty we ignore it.
+ * It's useful if the user wants to cancel its modification
+ */
+ if (null_or_empty_path(*tmp)) {
+ log_warning("Edition of %s canceled: temporary file empty", *original);
+ continue;
+ }
+ r = rename(*tmp, *original);
+ if (r < 0) {
+ r = log_error_errno(errno, "Failed to rename %s to %s: %m", *tmp, *original);
+ goto end;
+ }
+ }
+
+ if (!arg_no_reload && bus && !avoid_bus())
+ r = daemon_reload(bus, args);
+
+end:
+ STRV_FOREACH_PAIR(original, tmp, paths)
+ unlink_noerrno(*tmp);
+
+ return r;
+}
+
static void systemctl_help(void) {
pager_open_if_enabled();
@@ -5739,7 +6314,9 @@ static void systemctl_help(void) {
" add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
" on specified one or more units\n"
" get-default Get the name of the default target\n"
- " set-default NAME Set the default target\n\n"
+ " set-default NAME Set the default target\n"
+ " edit NAME... Edit one or more unit files\n"
+ "\n"
"Machine Commands:\n"
" list-machines [PATTERN...] List local containers and host\n\n"
"Job Commands:\n"
@@ -6655,16 +7232,13 @@ static int talk_initctl(void) {
if (errno == ENOENT)
return 0;
- log_error("Failed to open "INIT_FIFO": %m");
+ log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
return -errno;
}
- errno = 0;
- r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
- if (r) {
- log_error("Failed to write to "INIT_FIFO": %m");
- return errno > 0 ? -errno : -EIO;
- }
+ r = loop_write(fd, &request, sizeof(request), false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
return 1;
}
@@ -6748,8 +7322,9 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "get-default", EQUAL, 1, get_default, NOBUS },
{ "set-property", MORE, 3, set_property },
{ "is-system-running", EQUAL, 1, is_system_running },
- { "add-wants", MORE, 3, add_dependency, NOBUS },
- { "add-requires", MORE, 3, add_dependency, NOBUS },
+ { "add-wants", MORE, 3, add_dependency, NOBUS },
+ { "add-requires", MORE, 3, add_dependency, NOBUS },
+ { "edit", MORE, 2, edit, NOBUS },
{}
}, *verb = verbs;
@@ -6811,7 +7386,7 @@ found:
* enable/disable */
if (verb->bus == NOBUS) {
if (!bus && !avoid_bus()) {
- log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
+ log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
return -EIO;
}
@@ -6822,7 +7397,7 @@ found:
}
if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
- log_error("Failed to get D-Bus connection: %s", strerror(-bus_error));
+ log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
return -EIO;
}
}
@@ -6886,10 +7461,8 @@ static int reload_with_fallback(sd_bus *bus) {
/* Nothing else worked, so let's try signals */
assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
- if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
- log_error("kill() failed: %m");
- return -errno;
- }
+ if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
+ return log_error_errno(errno, "kill() failed: %m");
return 0;
}
@@ -6917,8 +7490,13 @@ done:
static int halt_now(enum action a) {
-/* Make sure C-A-D is handled by the kernel from this
- * point on... */
+ /* The kernel will automaticall flush ATA disks and suchlike
+ * on reboot(), but the file systems need to be synce'd
+ * explicitly in advance. */
+ sync();
+
+ /* Make sure C-A-D is handled by the kernel from this point
+ * on... */
reboot(RB_ENABLE_CAD);
switch (a) {
@@ -6995,7 +7573,7 @@ static int halt_main(sd_bus *bus) {
m);
if (r < 0)
- log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
+ log_warning_errno(r, "Failed to talk to shutdownd, proceeding with immediate shutdown: %m");
else {
char date[FORMAT_TIMESTAMP_MAX];
@@ -7014,7 +7592,7 @@ static int halt_main(sd_bus *bus) {
else {
r = utmp_put_shutdown();
if (r < 0)
- log_warning("Failed to write utmp record: %s", strerror(-r));
+ log_warning_errno(r, "Failed to write utmp record: %m");
}
}
@@ -7022,7 +7600,7 @@ static int halt_main(sd_bus *bus) {
return 0;
r = halt_now(arg_action);
- log_error("Failed to reboot: %s", strerror(-r));
+ log_error_errno(r, "Failed to reboot: %m");
return r;
}
@@ -7120,7 +7698,7 @@ int main(int argc, char*argv[]) {
r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
if (r < 0)
- log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
+ log_warning_errno(r, "Failed to talk to shutdownd, shutdown hasn't been cancelled: %m");
break;
}
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 18acfc2ad7..c27537f862 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -46,35 +46,47 @@ typedef struct {
int _need_free;
} sd_bus_error;
+typedef struct {
+ const char* name;
+ int code;
+} sd_bus_error_map;
+
/* Flags */
enum {
- SD_BUS_CREDS_PID = 1ULL << 0,
- SD_BUS_CREDS_PID_STARTTIME = 1ULL << 1,
- SD_BUS_CREDS_TID = 1ULL << 2,
- SD_BUS_CREDS_UID = 1ULL << 3,
- SD_BUS_CREDS_GID = 1ULL << 4,
- SD_BUS_CREDS_COMM = 1ULL << 5,
- SD_BUS_CREDS_TID_COMM = 1ULL << 6,
- SD_BUS_CREDS_EXE = 1ULL << 7,
- SD_BUS_CREDS_CMDLINE = 1ULL << 8,
- SD_BUS_CREDS_CGROUP = 1ULL << 9,
- SD_BUS_CREDS_UNIT = 1ULL << 10,
- SD_BUS_CREDS_USER_UNIT = 1ULL << 11,
- SD_BUS_CREDS_SLICE = 1ULL << 12,
- SD_BUS_CREDS_SESSION = 1ULL << 13,
- SD_BUS_CREDS_OWNER_UID = 1ULL << 14,
- SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 15,
- SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 16,
- SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 17,
- SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 18,
- SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 19,
- SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 20,
- SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 21,
- SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 22,
- SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 23,
- SD_BUS_CREDS_CONNECTION_NAME = 1ULL << 24,
- _SD_BUS_CREDS_ALL = (1ULL << 25) -1,
+ SD_BUS_CREDS_PID = 1ULL << 0,
+ SD_BUS_CREDS_TID = 1ULL << 1,
+ SD_BUS_CREDS_UID = 1ULL << 2,
+ SD_BUS_CREDS_EUID = 1ULL << 3,
+ SD_BUS_CREDS_SUID = 1ULL << 4,
+ SD_BUS_CREDS_FSUID = 1ULL << 5,
+ SD_BUS_CREDS_GID = 1ULL << 6,
+ SD_BUS_CREDS_EGID = 1ULL << 7,
+ SD_BUS_CREDS_SGID = 1ULL << 8,
+ SD_BUS_CREDS_FSGID = 1ULL << 9,
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS = 1ULL << 10,
+ SD_BUS_CREDS_COMM = 1ULL << 11,
+ SD_BUS_CREDS_TID_COMM = 1ULL << 12,
+ SD_BUS_CREDS_EXE = 1ULL << 13,
+ SD_BUS_CREDS_CMDLINE = 1ULL << 14,
+ SD_BUS_CREDS_CGROUP = 1ULL << 15,
+ SD_BUS_CREDS_UNIT = 1ULL << 16,
+ SD_BUS_CREDS_USER_UNIT = 1ULL << 17,
+ SD_BUS_CREDS_SLICE = 1ULL << 18,
+ SD_BUS_CREDS_SESSION = 1ULL << 19,
+ SD_BUS_CREDS_OWNER_UID = 1ULL << 20,
+ SD_BUS_CREDS_EFFECTIVE_CAPS = 1ULL << 21,
+ SD_BUS_CREDS_PERMITTED_CAPS = 1ULL << 22,
+ SD_BUS_CREDS_INHERITABLE_CAPS = 1ULL << 23,
+ SD_BUS_CREDS_BOUNDING_CAPS = 1ULL << 24,
+ SD_BUS_CREDS_SELINUX_CONTEXT = 1ULL << 25,
+ SD_BUS_CREDS_AUDIT_SESSION_ID = 1ULL << 26,
+ SD_BUS_CREDS_AUDIT_LOGIN_UID = 1ULL << 27,
+ SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 28,
+ SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 29,
+ SD_BUS_CREDS_DESCRIPTION = 1ULL << 30,
+ SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */
+ _SD_BUS_CREDS_ALL = (1ULL << 32) -1,
};
enum {
@@ -108,18 +120,29 @@ int sd_bus_open_system_remote(sd_bus **ret, const char *host);
int sd_bus_open_system_container(sd_bus **ret, const char *machine);
int sd_bus_new(sd_bus **ret);
+
int sd_bus_set_address(sd_bus *bus, const char *address);
int sd_bus_set_fd(sd_bus *bus, int input_fd, int output_fd);
int sd_bus_set_exec(sd_bus *bus, const char *path, char *const argv[]);
+int sd_bus_get_address(sd_bus *bus, const char **address);
int sd_bus_set_bus_client(sd_bus *bus, int b);
-int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id);
+int sd_bus_is_bus_client(sd_bus *bus);
+int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t bus_id);
+int sd_bus_is_server(sd_bus *bus);
int sd_bus_set_anonymous(sd_bus *bus, int b);
+int sd_bus_is_anonymous(sd_bus *bus);
int sd_bus_set_trusted(sd_bus *bus, int b);
-int sd_bus_set_name(sd_bus *bus, const char *name);
+int sd_bus_is_trusted(sd_bus *bus);
int sd_bus_set_monitor(sd_bus *bus, int b);
+int sd_bus_is_monitor(sd_bus *bus);
+int sd_bus_set_description(sd_bus *bus, const char *description);
+int sd_bus_get_description(sd_bus *bus, const char **description);
int sd_bus_negotiate_fds(sd_bus *bus, int b);
+int sd_bus_can_send(sd_bus *bus, char type);
int sd_bus_negotiate_timestamp(sd_bus *bus, int b);
-int sd_bus_negotiate_creds(sd_bus *bus, uint64_t creds_mask);
+int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t creds_mask);
+int sd_bus_get_creds_mask(sd_bus *bus, uint64_t *creds_mask);
+
int sd_bus_start(sd_bus *ret);
int sd_bus_try_close(sd_bus *bus);
@@ -129,11 +152,11 @@ sd_bus *sd_bus_ref(sd_bus *bus);
sd_bus *sd_bus_unref(sd_bus *bus);
int sd_bus_is_open(sd_bus *bus);
-int sd_bus_can_send(sd_bus *bus, char type);
-int sd_bus_get_server_id(sd_bus *bus, sd_id128_t *peer);
-int sd_bus_get_owner_creds(sd_bus *bus, uint64_t creds_mask, sd_bus_creds **ret);
-int sd_bus_get_name(sd_bus *bus, const char **name);
+
+int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id);
+int sd_bus_get_scope(sd_bus *bus, const char **scope);
int sd_bus_get_tid(sd_bus *bus, pid_t *tid);
+int sd_bus_get_owner_creds(sd_bus *bus, uint64_t creds_mask, sd_bus_creds **ret);
int sd_bus_send(sd_bus *bus, sd_bus_message *m, uint64_t *cookie);
int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destination, uint64_t *cookie);
@@ -147,6 +170,7 @@ int sd_bus_process(sd_bus *bus, sd_bus_message **r);
int sd_bus_process_priority(sd_bus *bus, int64_t max_priority, sd_bus_message **r);
int sd_bus_wait(sd_bus *bus, uint64_t timeout_usec);
int sd_bus_flush(sd_bus *bus);
+
sd_bus_slot* sd_bus_get_current_slot(sd_bus *bus);
sd_bus_message* sd_bus_get_current_message(sd_bus *bus);
sd_bus_message_handler_t sd_bus_get_current_handler(sd_bus *bus);
@@ -171,9 +195,10 @@ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot);
sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot);
sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot);
-
void *sd_bus_slot_get_userdata(sd_bus_slot *slot);
void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata);
+int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description);
+int sd_bus_slot_get_description(sd_bus_slot *slot, char **description);
sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *bus);
@@ -220,6 +245,8 @@ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m); /* do not unref the r
int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member);
int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member);
int sd_bus_message_is_method_error(sd_bus_message *m, const char *name);
+int sd_bus_message_is_empty(sd_bus_message *m);
+int sd_bus_message_has_signature(sd_bus_message *m, const char *signature);
int sd_bus_message_set_expect_reply(sd_bus_message *m, int b);
int sd_bus_message_set_auto_start(sd_bus_message *m, int b);
@@ -233,10 +260,10 @@ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p);
int sd_bus_message_append_array(sd_bus_message *m, char type, const void *ptr, size_t size);
int sd_bus_message_append_array_space(sd_bus_message *m, char type, size_t size, void **ptr);
int sd_bus_message_append_array_iovec(sd_bus_message *m, char type, const struct iovec *iov, unsigned n);
-int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, int memfd);
+int sd_bus_message_append_array_memfd(sd_bus_message *m, char type, int memfd, uint64_t offset, uint64_t size);
int sd_bus_message_append_string_space(sd_bus_message *m, size_t size, char **s);
int sd_bus_message_append_string_iovec(sd_bus_message *m, const struct iovec *iov, unsigned n);
-int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd);
+int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd, uint64_t offset, uint64_t size);
int sd_bus_message_append_strv(sd_bus_message *m, char **l);
int sd_bus_message_open_container(sd_bus_message *m, char type, const char *contents);
int sd_bus_message_close_container(sd_bus_message *m);
@@ -299,10 +326,16 @@ sd_bus_creds *sd_bus_creds_unref(sd_bus_creds *c);
uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c);
int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid);
-int sd_bus_creds_get_pid_starttime(sd_bus_creds *c, uint64_t *usec);
int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid);
int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);
+int sd_bus_creds_get_euid(sd_bus_creds *c, uid_t *euid);
+int sd_bus_creds_get_suid(sd_bus_creds *c, uid_t *suid);
+int sd_bus_creds_get_fsuid(sd_bus_creds *c, uid_t *fsuid);
int sd_bus_creds_get_gid(sd_bus_creds *c, gid_t *gid);
+int sd_bus_creds_get_egid(sd_bus_creds *c, gid_t *egid);
+int sd_bus_creds_get_sgid(sd_bus_creds *c, gid_t *sgid);
+int sd_bus_creds_get_fsgid(sd_bus_creds *c, gid_t *fsgid);
+int sd_bus_creds_get_supplementary_gids(sd_bus_creds *c, const gid_t **gids);
int sd_bus_creds_get_comm(sd_bus_creds *c, const char **comm);
int sd_bus_creds_get_tid_comm(sd_bus_creds *c, const char **comm);
int sd_bus_creds_get_exe(sd_bus_creds *c, const char **exe);
@@ -322,7 +355,7 @@ int sd_bus_creds_get_audit_session_id(sd_bus_creds *c, uint32_t *sessionid);
int sd_bus_creds_get_audit_login_uid(sd_bus_creds *c, uid_t *loginuid);
int sd_bus_creds_get_unique_name(sd_bus_creds *c, const char **name);
int sd_bus_creds_get_well_known_names(sd_bus_creds *c, char ***names);
-int sd_bus_creds_get_connection_name(sd_bus_creds *c, const char **name);
+int sd_bus_creds_get_description(sd_bus_creds *c, const char **name);
/* Error structures */
@@ -340,6 +373,19 @@ int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e);
int sd_bus_error_is_set(const sd_bus_error *e);
int sd_bus_error_has_name(const sd_bus_error *e, const char *name);
+#define SD_BUS_ERROR_MAP(_name, _code) \
+ { \
+ .name = _name, \
+ .code = _code, \
+ }
+#define SD_BUS_ERROR_MAP_END \
+ { \
+ .name = NULL, \
+ .code = - 'x', \
+ }
+
+int sd_bus_error_add_map(const sd_bus_error_map *map);
+
/* Auxiliary macros */
#define SD_BUS_MESSAGE_APPEND_ID128(x) 16, \
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 7416f82193..951662e56c 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -51,6 +51,10 @@ int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type);
+int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
+ const uint8_t *data, size_t data_len);
+int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
+ const uint8_t **data, size_t *data_len);
int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h
index a3728a702f..4296b91d8a 100644
--- a/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/sd-dhcp-lease.h
@@ -45,5 +45,10 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
+int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
+ size_t *client_id_len);
+
+int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
+int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file);
#endif
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index c7f168fe21..e9663c0c71 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -33,6 +33,7 @@ enum {
DHCP6_EVENT_RESEND_EXPIRE = 10,
DHCP6_EVENT_RETRANS_MAX = 11,
DHCP6_EVENT_IP_ACQUIRE = 12,
+ DHCP6_EVENT_INFORMATION_REQUEST = 13,
};
typedef struct sd_dhcp6_client sd_dhcp6_client;
@@ -47,6 +48,10 @@ 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_request_option(sd_dhcp6_client *client,
uint16_t option);
diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h
index 0dbdcdf2a5..25a10f99ab 100644
--- a/src/systemd/sd-event.h
+++ b/src/systemd/sd-event.h
@@ -109,8 +109,8 @@ sd_event *sd_event_source_get_event(sd_event_source *s);
void* sd_event_source_get_userdata(sd_event_source *s);
void* sd_event_source_set_userdata(sd_event_source *s, void *userdata);
-int sd_event_source_set_name(sd_event_source *s, const char *name);
-int sd_event_source_get_name(sd_event_source *s, const char **name);
+int sd_event_source_set_description(sd_event_source *s, const char *description);
+int sd_event_source_get_description(sd_event_source *s, const char **description);
int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback);
int sd_event_source_get_pending(sd_event_source *s);
int sd_event_source_get_priority(sd_event_source *s, int64_t *priority);
diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h
new file mode 100644
index 0000000000..318d2f033b
--- /dev/null
+++ b/src/systemd/sd-pppoe.h
@@ -0,0 +1,53 @@
+/*-*- 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 {
+ PPPOE_EVENT_RUNNING = 0,
+ 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
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index 1e7eb811d1..b05f83ce41 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -26,6 +26,7 @@
#include <netinet/in.h>
#include <netinet/ether.h>
#include <linux/rtnetlink.h>
+#include <linux/neighbour.h>
#include "sd-event.h"
#include "_sd-common.h"
@@ -41,6 +42,7 @@ typedef int (*sd_rtnl_message_handler_t)(sd_rtnl *rtnl, sd_rtnl_message *m, void
/* bus */
int sd_rtnl_open(sd_rtnl **nl, unsigned n_groups, ...);
+int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size);
sd_rtnl *sd_rtnl_ref(sd_rtnl *nl);
sd_rtnl *sd_rtnl_unref(sd_rtnl *nl);
@@ -73,11 +75,13 @@ int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_
int family);
int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type,
int rtm_family, unsigned char rtm_protocol);
+int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t msg_type, int index, int nda_family);
sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m);
sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m);
int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump);
+int sd_rtnl_message_is_error(sd_rtnl_message *m);
int sd_rtnl_message_get_errno(sd_rtnl_message *m);
int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type);
int sd_rtnl_message_is_broadcast(sd_rtnl_message *m);
@@ -93,12 +97,20 @@ int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex);
int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change);
int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type);
+int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family);
int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags);
int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type);
int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
+int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope);
+int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family);
+int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len);
+int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len);
+
+int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family);
+int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *family);
int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data);
int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data);
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 9b9be96a0a..647eb577a6 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -67,15 +67,7 @@ typedef struct Item {
static char *arg_root = NULL;
-static const char conf_file_dirs[] =
- "/etc/sysusers.d\0"
- "/run/sysusers.d\0"
- "/usr/local/lib/sysusers.d\0"
- "/usr/lib/sysusers.d\0"
-#ifdef HAVE_SPLIT_USR
- "/lib/sysusers.d\0"
-#endif
- ;
+static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers");
static Hashmap *users = NULL, *groups = NULL;
static Hashmap *todo_uids = NULL, *todo_gids = NULL;
@@ -84,7 +76,7 @@ static Hashmap *members = NULL;
static Hashmap *database_uid = NULL, *database_user = NULL;
static Hashmap *database_gid = NULL, *database_group = NULL;
-static uid_t search_uid = (uid_t) -1;
+static uid_t search_uid = UID_INVALID;
static UidRange *uid_range = NULL;
static unsigned n_uid_range = 0;
@@ -234,14 +226,15 @@ static int make_backup(const char *target, const char *x) {
/* Copy over the access mask */
if (fchmod(fileno(dst), st.st_mode & 07777) < 0)
- log_warning("Failed to change mode on %s: %m", backup);
+ log_warning_errno(errno, "Failed to change mode on %s: %m", backup);
if (fchown(fileno(dst), st.st_uid, st.st_gid)< 0)
- log_warning("Failed to change ownership of %s: %m", backup);
+ log_warning_errno(errno, "Failed to change ownership of %s: %m", backup);
ts[0] = st.st_atim;
ts[1] = st.st_mtim;
- futimens(fileno(dst), ts);
+ if (futimens(fileno(dst), ts) < 0)
+ log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup);
if (rename(temp, backup) < 0)
goto fail;
@@ -353,6 +346,21 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) {
return 0;
}
+static int sync_rights(FILE *from, FILE *to) {
+ struct stat st;
+
+ if (fstat(fileno(from), &st) < 0)
+ return -errno;
+
+ if (fchmod(fileno(to), st.st_mode & 07777) < 0)
+ return -errno;
+
+ if (fchown(fileno(to), st.st_uid, st.st_gid) < 0)
+ return -errno;
+
+ return 0;
+}
+
static int write_files(void) {
_cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
@@ -372,15 +380,14 @@ static int write_files(void) {
if (r < 0)
goto finish;
- if (fchmod(fileno(group), 0644) < 0) {
- r = -errno;
- goto finish;
- }
-
original = fopen(group_path, "re");
if (original) {
struct group *gr;
+ r = sync_rights(original, group);
+ if (r < 0)
+ goto finish;
+
errno = 0;
while ((gr = fgetgrent(original))) {
/* Safety checks against name and GID
@@ -418,6 +425,9 @@ static int write_files(void) {
} else if (errno != ENOENT) {
r = -errno;
goto finish;
+ } else if (fchmod(fileno(group), 0644) < 0) {
+ r = -errno;
+ goto finish;
}
HASHMAP_FOREACH(i, todo_gids, iterator) {
@@ -449,15 +459,14 @@ static int write_files(void) {
if (r < 0)
goto finish;
- if (fchmod(fileno(gshadow), 0000) < 0) {
- r = -errno;
- goto finish;
- }
-
original = fopen(gshadow_path, "re");
if (original) {
struct sgrp *sg;
+ r = sync_rights(original, gshadow);
+ if (r < 0)
+ goto finish;
+
errno = 0;
while ((sg = fgetsgent(original))) {
@@ -483,6 +492,9 @@ static int write_files(void) {
} else if (errno != ENOENT) {
r = -errno;
goto finish;
+ } else if (fchmod(fileno(gshadow), 0000) < 0) {
+ r = -errno;
+ goto finish;
}
HASHMAP_FOREACH(i, todo_gids, iterator) {
@@ -513,15 +525,14 @@ static int write_files(void) {
if (r < 0)
goto finish;
- if (fchmod(fileno(passwd), 0644) < 0) {
- r = -errno;
- goto finish;
- }
-
original = fopen(passwd_path, "re");
if (original) {
struct passwd *pw;
+ r = sync_rights(original, passwd);
+ if (r < 0)
+ goto finish;
+
errno = 0;
while ((pw = fgetpwent(original))) {
@@ -552,6 +563,9 @@ static int write_files(void) {
} else if (errno != ENOENT) {
r = -errno;
goto finish;
+ } else if (fchmod(fileno(passwd), 0644) < 0) {
+ r = -errno;
+ goto finish;
}
HASHMAP_FOREACH(i, todo_uids, iterator) {
@@ -596,15 +610,14 @@ static int write_files(void) {
if (r < 0)
goto finish;
- if (fchmod(fileno(shadow), 0000) < 0) {
- r = -errno;
- goto finish;
- }
-
original = fopen(shadow_path, "re");
if (original) {
struct spwd *sp;
+ r = sync_rights(original, shadow);
+ if (r < 0)
+ goto finish;
+
errno = 0;
while ((sp = fgetspent(original))) {
@@ -629,6 +642,9 @@ static int write_files(void) {
} else if (errno != ENOENT) {
r = -errno;
goto finish;
+ } else if (fchmod(fileno(shadow), 0000) < 0) {
+ r = -errno;
+ goto finish;
}
lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
@@ -882,10 +898,8 @@ static int add_user(Item *i) {
i->description = strdup(p->pw_gecos);
return 0;
}
- if (!IN_SET(errno, 0, ENOENT)) {
- log_error("Failed to check if user %s already exists: %m", i->name);
- return -errno;
- }
+ if (!IN_SET(errno, 0, ENOENT))
+ return log_error_errno(errno, "Failed to check if user %s already exists: %m", i->name);
/* And shadow too, just to be sure */
errno = 0;
@@ -894,19 +908,15 @@ static int add_user(Item *i) {
log_error("User %s already exists in shadow database, but not in user database.", i->name);
return -EBADMSG;
}
- if (!IN_SET(errno, 0, ENOENT)) {
- log_error("Failed to check if user %s already exists in shadow database: %m", i->name);
- return -errno;
- }
+ if (!IN_SET(errno, 0, ENOENT))
+ return log_error_errno(errno, "Failed to check if user %s already exists in shadow database: %m", i->name);
}
/* Try to use the suggested numeric uid */
if (i->uid_set) {
r = uid_is_ok(i->uid, i->name);
- if (r < 0) {
- log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
if (r == 0) {
log_debug("Suggested user ID " UID_FMT " for %s already used.", i->uid, i->name);
i->uid_set = false;
@@ -923,10 +933,9 @@ static int add_user(Item *i) {
log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
else {
r = uid_is_ok(c, i->name);
- if (r < 0) {
- log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
- return r;
- } else if (r > 0) {
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
+ else if (r > 0) {
i->uid = c;
i->uid_set = true;
} else
@@ -938,10 +947,8 @@ static int add_user(Item *i) {
/* 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) {
- log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
if (r > 0) {
i->uid = (uid_t) i->gid;
i->uid_set = true;
@@ -958,10 +965,9 @@ static int add_user(Item *i) {
}
r = uid_is_ok(search_uid, i->name);
- if (r < 0) {
- log_error("Failed to verify uid " UID_FMT ": %s", i->uid, strerror(-r));
- return r;
- } else if (r > 0)
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify uid " UID_FMT ": %m", i->uid);
+ else if (r > 0)
break;
}
@@ -1046,19 +1052,15 @@ static int add_group(Item *i) {
i->gid_set = true;
return 0;
}
- if (!IN_SET(errno, 0, ENOENT)) {
- log_error("Failed to check if group %s already exists: %m", i->name);
- return -errno;
- }
+ if (!IN_SET(errno, 0, ENOENT))
+ return log_error_errno(errno, "Failed to check if group %s already exists: %m", i->name);
}
/* Try to use the suggested numeric gid */
if (i->gid_set) {
r = gid_is_ok(i->gid);
- if (r < 0) {
- log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
if (r == 0) {
log_debug("Suggested group ID " GID_FMT " for %s already used.", i->gid, i->name);
i->gid_set = false;
@@ -1068,10 +1070,8 @@ static int add_group(Item *i) {
/* Try to reuse the numeric uid, if there's one */
if (!i->gid_set && i->uid_set) {
r = gid_is_ok((gid_t) i->uid);
- if (r < 0) {
- log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
if (r > 0) {
i->gid = (gid_t) i->uid;
i->gid_set = true;
@@ -1088,10 +1088,9 @@ static int add_group(Item *i) {
log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
else {
r = gid_is_ok(c);
- if (r < 0) {
- log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
- return r;
- } else if (r > 0) {
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
+ else if (r > 0) {
i->gid = c;
i->gid_set = true;
} else
@@ -1111,10 +1110,9 @@ static int add_group(Item *i) {
}
r = gid_is_ok(search_uid);
- if (r < 0) {
- log_error("Failed to verify gid " GID_FMT ": %s", i->gid, strerror(-r));
- return r;
- } else if (r > 0)
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify gid " GID_FMT ": %m", i->gid);
+ else if (r > 0)
break;
}
@@ -1705,8 +1703,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
if (ignore_enoent && r == -ENOENT)
return 0;
- log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
}
f = rf;
@@ -1728,7 +1725,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
}
if (ferror(f)) {
- log_error("Failed to read from file %s: %m", fn);
+ log_error_errno(errno, "Failed to read from file %s: %m", fn);
if (r == 0)
r = -EIO;
}
@@ -1837,7 +1834,7 @@ int main(int argc, char *argv[]) {
r = mac_selinux_init(NULL);
if (r < 0) {
- log_error("SELinux setup failed: %s", strerror(-r));
+ log_error_errno(r, "SELinux setup failed: %m");
goto finish;
}
@@ -1855,7 +1852,7 @@ int main(int argc, char *argv[]) {
r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
if (r < 0) {
- log_error("Failed to enumerate sysusers.d files: %s", strerror(-r));
+ log_error_errno(r, "Failed to enumerate sysusers.d files: %m");
goto finish;
}
@@ -1881,19 +1878,19 @@ int main(int argc, char *argv[]) {
lock = take_password_lock(arg_root);
if (lock < 0) {
- log_error("Failed to take lock: %s", strerror(-lock));
+ log_error_errno(lock, "Failed to take lock: %m");
goto finish;
}
r = load_user_database();
if (r < 0) {
- log_error("Failed to load user database: %s", strerror(-r));
+ log_error_errno(r, "Failed to load user database: %m");
goto finish;
}
r = load_group_database();
if (r < 0) {
- log_error("Failed to read group database: %s", strerror(-r));
+ log_error_errno(r, "Failed to read group database: %m");
goto finish;
}
@@ -1905,7 +1902,7 @@ int main(int argc, char *argv[]) {
r = write_files();
if (r < 0)
- log_error("Failed to write files: %s", strerror(-r));
+ log_error_errno(r, "Failed to write files: %m");
finish:
while ((i = hashmap_steal_first(groups)))
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 6e4cdd694e..45c8b4ea0f 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -143,14 +143,13 @@ static int generate_unit_file(SysvStub *s) {
return log_oom();
f = fopen(unit, "wxe");
- if (!f) {
- log_error("Failed to create unit file %s: %m", unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
fprintf(f,
"# 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);
@@ -175,9 +174,6 @@ static int generate_unit_file(SysvStub *s) {
"RemainAfterExit=%s\n",
yes_no(!s->pid_file));
- if (s->sysv_start_priority > 0)
- fprintf(f, "SysVStartPriority=%d\n", s->sysv_start_priority);
-
if (s->pid_file)
fprintf(f, "PIDFile=%s\n", s->pid_file);
@@ -192,7 +188,7 @@ static int generate_unit_file(SysvStub *s) {
STRV_FOREACH(p, s->wanted_by) {
r = add_symlink(s->name, *p);
if (r < 0)
- log_error_unit(s->name, "Failed to create 'Wants' symlink to %s: %s", *p, strerror(-r));
+ log_unit_error_errno(s->name, r, "Failed to create 'Wants' symlink to %s: %m", *p);
}
return 0;
@@ -320,7 +316,7 @@ static int load_sysv(SysvStub *s) {
if (feof(f))
break;
- log_error_unit(s->name,
+ log_unit_error(s->name,
"Failed to read configuration file '%s': %m",
s->path);
return -errno;
@@ -395,7 +391,7 @@ static int load_sysv(SysvStub *s) {
fn = strstrip(t+8);
if (!path_is_absolute(fn)) {
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] PID file not absolute. Ignoring.",
s->path, line);
continue;
@@ -489,12 +485,12 @@ static int load_sysv(SysvStub *s) {
}
if (r < 0)
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] Failed to add LSB Provides name %s, ignoring: %s",
s->path, line, m, strerror(-r));
}
if (!isempty(state_))
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] Trailing garbage in Provides, ignoring.",
s->path, line);
@@ -517,7 +513,7 @@ static int load_sysv(SysvStub *s) {
r = sysv_translate_facility(n, basename(s->path), &m);
if (r < 0) {
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] Failed to translate LSB dependency %s, ignoring: %s",
s->path, line, n, strerror(-r));
continue;
@@ -551,12 +547,12 @@ static int load_sysv(SysvStub *s) {
}
if (r < 0)
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] Failed to add dependency on %s, ignoring: %s",
s->path, line, m, strerror(-r));
}
if (!isempty(state_))
- log_error_unit(s->name,
+ log_unit_error(s->name,
"[%s:%u] Trailing garbage in %*s, ignoring.",
s->path, line,
(int)(strchr(t, ':') - t), t);
@@ -698,7 +694,7 @@ static int enumerate_sysv(LookupPaths lp, Hashmap *all_services) {
d = opendir(*path);
if (!d) {
if (errno != ENOENT)
- log_warning("opendir(%s) failed: %m", *path);
+ log_warning_errno(errno, "opendir(%s) failed: %m", *path);
continue;
}
@@ -773,7 +769,7 @@ static int set_dependencies_from_rcnd(LookupPaths lp, Hashmap *all_services) {
d = opendir(path);
if (!d) {
if (errno != ENOENT)
- log_warning("opendir(%s) failed: %m", path);
+ log_warning_errno(errno, "opendir(%s) failed: %m", path);
continue;
}
diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c
index 24217ad369..30bdec45e5 100644
--- a/src/test/test-architecture.c
+++ b/src/test/test-architecture.c
@@ -25,9 +25,8 @@
#include "log.h"
int main(int argc, char *argv[]) {
- Architecture a;
- int v;
const char *id = NULL;
+ int a, v;
v = detect_virtualization(&id);
if (v == -EPERM || v == -EACCES)
diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c
index 4ede318e38..06d93af533 100644
--- a/src/test/test-boot-timestamps.c
+++ b/src/test/test-boot-timestamps.c
@@ -37,7 +37,7 @@ static int test_acpi_fpdt(void) {
r = acpi_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
if (r != -ENOENT)
- log_error("Failed to read ACPI FPDT: %s", strerror(-r));
+ log_error_errno(r, "Failed to read ACPI FPDT: %m");
return r;
}
@@ -60,7 +60,7 @@ static int test_efi_loader(void) {
r = efi_loader_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
if (r != -ENOENT)
- log_error("Failed to read EFI loader data: %s", strerror(-r));
+ log_error_errno(r, "Failed to read EFI loader data: %m");
return r;
}
@@ -84,7 +84,7 @@ int main(int argc, char* argv[]) {
r = boot_timestamps(NULL, &fw, &l);
if (r < 0) {
- log_error("Failed to read variables: %s", strerror(-r));
+ log_error_errno(r, "Failed to read variables: %m");
return 1;
}
diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c
new file mode 100644
index 0000000000..dfa9a063c2
--- /dev/null
+++ b/src/test/test-cap-list.c
@@ -0,0 +1,47 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "log.h"
+#include "cap-list.h"
+#include "capability.h"
+
+int main(int argc, char *argv[]) {
+ int i;
+
+ assert_se(!capability_to_name(-1));
+ assert_se(!capability_to_name(cap_last_cap()+1));
+
+ for (i = 0; i <= (int) cap_last_cap(); i++) {
+ const char *n;
+
+ assert_se(n = capability_to_name(i));
+ assert_se(capability_from_name(n) == i);
+ printf("%s = %i\n", n, i);
+ }
+
+ assert_se(capability_from_name("asdfbsd") == -EINVAL);
+ assert_se(capability_from_name("CAP_AUDIT_READ") == CAP_AUDIT_READ);
+ assert_se(capability_from_name("0") == 0);
+ assert_se(capability_from_name("15") == 15);
+ assert_se(capability_from_name("-1") == -EINVAL);
+
+ return 0;
+}
diff --git a/src/test/test-capability.c b/src/test/test-capability.c
index a362fc6c57..43769923b0 100644
--- a/src/test/test-capability.c
+++ b/src/test/test-capability.c
@@ -70,7 +70,7 @@ static int setup_tests(void) {
nobody = getpwnam("nobody");
if (!nobody) {
- log_error("Could not find nobody user: %m");
+ log_error_errno(errno, "Could not find nobody user: %m");
return -EXIT_TEST_SKIP;
}
test_uid = nobody->pw_uid;
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 68c526ae82..58eb744277 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -141,7 +141,7 @@ static void test_proc(void) {
FOREACH_DIRENT(de, d, break) {
_cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
pid_t pid;
- uid_t uid = (uid_t) -1;
+ uid_t uid = UID_INVALID;
if (de->d_type != DT_DIR &&
de->d_type != DT_UNKNOWN)
diff --git a/src/test/test-condition-util.c b/src/test/test-condition-util.c
deleted file mode 100644
index 35ee9167bf..0000000000
--- a/src/test/test-condition-util.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/***
- This file is part of systemd
-
- Copyright 2014 Ronny Chevalier
-
- 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 "condition-util.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "architecture.h"
-#include "systemd/sd-id128.h"
-
-static void test_condition_test_ac_power(void) {
- Condition *condition;
-
- condition = condition_new(CONDITION_AC_POWER, "true", false, false);
- assert_se(condition_test_ac_power(condition) == on_ac_power());
- condition_free(condition);
-
- condition = condition_new(CONDITION_AC_POWER, "false", false, false);
- assert_se(condition_test_ac_power(condition) != on_ac_power());
- condition_free(condition);
-
- condition = condition_new(CONDITION_AC_POWER, "false", false, true);
- assert_se(condition_test_ac_power(condition) == on_ac_power());
- condition_free(condition);
-}
-
-static void test_condition_test_host(void) {
- Condition *condition;
- sd_id128_t id;
- int r;
- char sid[SD_ID128_STRING_MAX];
- _cleanup_free_ char *hostname = NULL;
-
- r = sd_id128_get_machine(&id);
- assert_se(r >= 0);
- assert_se(sd_id128_to_string(id, sid));
-
- condition = condition_new(CONDITION_HOST, sid, false, false);
- assert_se(condition_test_host(condition));
- condition_free(condition);
-
- condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false);
- assert_se(!condition_test_host(condition));
- condition_free(condition);
-
- condition = condition_new(CONDITION_HOST, sid, false, true);
- assert_se(!condition_test_host(condition));
- condition_free(condition);
-
- hostname = gethostname_malloc();
- assert_se(hostname);
-
- condition = condition_new(CONDITION_HOST, hostname, false, false);
- assert_se(condition_test_host(condition));
- condition_free(condition);
-}
-
-static void test_condition_test_architecture(void) {
- Condition *condition;
- Architecture a;
- const char *sa;
-
- a = uname_architecture();
- assert_se(a >= 0);
-
- sa = architecture_to_string(a);
- assert_se(sa);
-
- condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false);
- assert_se(condition_test_architecture(condition));
- condition_free(condition);
-
- condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false);
- assert_se(!condition_test_architecture(condition));
- condition_free(condition);
-
- condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true);
- assert_se(!condition_test_architecture(condition));
- condition_free(condition);
-}
-
-int main(int argc, char *argv[]) {
- log_parse_environment();
- log_open();
-
- test_condition_test_ac_power();
- test_condition_test_host();
- test_condition_test_architecture();
-
- return 0;
-}
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
new file mode 100644
index 0000000000..349c6470c3
--- /dev/null
+++ b/src/test/test-condition.c
@@ -0,0 +1,194 @@
+/***
+ This file is part of systemd
+
+ Copyright 2014 Ronny Chevalier
+
+ 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 "condition.h"
+#include "macro.h"
+#include "util.h"
+#include "log.h"
+#include "architecture.h"
+#include "sd-id128.h"
+
+static void test_condition_test_path_exists(void) {
+ Condition *condition;
+
+ condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_EXISTS, "/bin/s?", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, true);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_IS_DIRECTORY, "/bin", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_DIRECTORY_NOT_EMPTY, "/bin", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_FILE_NOT_EMPTY, "/bin/sh", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/bin/sh", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/etc/passwd", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/proc", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/", false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+}
+
+static void test_condition_test_ac_power(void) {
+ Condition *condition;
+
+ condition = condition_new(CONDITION_AC_POWER, "true", false, false);
+ assert_se(condition_test(condition) == on_ac_power());
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_AC_POWER, "false", false, false);
+ assert_se(condition_test(condition) != on_ac_power());
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_AC_POWER, "false", false, true);
+ assert_se(condition_test(condition) == on_ac_power());
+ condition_free(condition);
+}
+
+static void test_condition_test_host(void) {
+ Condition *condition;
+ sd_id128_t id;
+ int r;
+ char sid[SD_ID128_STRING_MAX];
+ _cleanup_free_ char *hostname = NULL;
+
+ r = sd_id128_get_machine(&id);
+ assert_se(r >= 0);
+ assert_se(sd_id128_to_string(id, sid));
+
+ condition = condition_new(CONDITION_HOST, sid, false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_HOST, sid, false, true);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ hostname = gethostname_malloc();
+ assert_se(hostname);
+
+ condition = condition_new(CONDITION_HOST, hostname, false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+}
+
+static void test_condition_test_architecture(void) {
+ Condition *condition;
+ const char *sa;
+ int a;
+
+ a = uname_architecture();
+ assert_se(a >= 0);
+
+ sa = architecture_to_string(a);
+ assert_se(sa);
+
+ condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false);
+ assert_se(condition_test(condition) < 0);
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+}
+
+static void test_condition_test_kernel_command_line(void) {
+ Condition *condition;
+
+ condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+}
+
+static void test_condition_test_null(void) {
+ Condition *condition;
+
+ condition = condition_new(CONDITION_NULL, NULL, false, false);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_NULL, NULL, false, true);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+}
+
+int main(int argc, char *argv[]) {
+ log_parse_environment();
+ log_open();
+
+ test_condition_test_path_exists();
+ test_condition_test_ac_power();
+ test_condition_test_host();
+ test_condition_test_architecture();
+ test_condition_test_kernel_command_line();
+ test_condition_test_null();
+
+ return 0;
+}
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index e801c5989e..71cfc022dd 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -36,7 +36,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_t) -1, (uid_t) -1, (gid_t) -1, 0) == 0);
+ assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0) == 0);
files = va_arg(ap, const char *);
}
va_end(ap);
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
new file mode 100644
index 0000000000..d2cad08cb6
--- /dev/null
+++ b/src/test/test-copy.c
@@ -0,0 +1,141 @@
+/***
+ This file is part of systemd
+
+ Copyright 2014 Ronny Chevalier
+
+ 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 <unistd.h>
+
+#include "copy.h"
+#include "path-util.h"
+#include "fileio.h"
+#include "mkdir.h"
+#include "strv.h"
+#include "macro.h"
+#include "util.h"
+
+static void test_copy_file(void) {
+ _cleanup_free_ char *buf = NULL;
+ char fn[] = "/tmp/test-copy_file.XXXXXX";
+ char fn_copy[] = "/tmp/test-copy_file.XXXXXX";
+ size_t sz = 0;
+ int fd;
+
+ fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ close(fd);
+
+ fd = mkostemp_safe(fn_copy, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ close(fd);
+
+ assert_se(write_string_file(fn, "foo bar bar bar foo") == 0);
+
+ assert_se(copy_file(fn, fn_copy, 0, 0644) == 0);
+
+ assert_se(read_full_file(fn_copy, &buf, &sz) == 0);
+ assert_se(streq(buf, "foo bar bar bar foo\n"));
+ assert_se(sz == 20);
+
+ unlink(fn);
+ unlink(fn_copy);
+}
+
+static void test_copy_file_fd(void) {
+ char in_fn[] = "/tmp/test-copy-file-fd-XXXXXX";
+ char out_fn[] = "/tmp/test-copy-file-fd-XXXXXX";
+ _cleanup_close_ int in_fd = -1, out_fd = -1;
+ char text[] = "boohoo\nfoo\n\tbar\n";
+ char buf[64] = {0};
+
+ in_fd = mkostemp_safe(in_fn, O_RDWR);
+ assert_se(in_fd >= 0);
+ out_fd = mkostemp_safe(out_fn, O_RDWR);
+ assert_se(out_fd >= 0);
+
+ assert_se(write_string_file(in_fn, text) == 0);
+ assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd) < 0);
+ assert_se(copy_file_fd(in_fn, out_fd) >= 0);
+ assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
+
+ assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1);
+ assert_se(streq(buf, text));
+
+ unlink(in_fn);
+ unlink(out_fn);
+}
+
+static void test_copy_tree(void) {
+ char original_dir[] = "/tmp/test-copy_tree/";
+ char copy_dir[] = "/tmp/test-copy_tree-copy/";
+ char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
+ char **links = STRV_MAKE("link", "file",
+ "link2", "dir1/file");
+ char **p, **link;
+
+ rm_rf_dangerous(copy_dir, false, true, false);
+ rm_rf_dangerous(original_dir, false, true, false);
+
+ STRV_FOREACH(p, files) {
+ char *f = strappenda(original_dir, *p);
+
+ assert_se(mkdir_parents(f, 0755) >= 0);
+ assert_se(write_string_file(f, "file") == 0);
+ }
+
+ STRV_FOREACH_PAIR(link, p, links) {
+ char *f = strappenda(original_dir, *p);
+ char *l = strappenda(original_dir, *link);
+
+ assert_se(mkdir_parents(l, 0755) >= 0);
+ assert_se(symlink(f, l) == 0);
+ }
+
+ assert_se(copy_tree(original_dir, copy_dir, true) == 0);
+
+ STRV_FOREACH(p, files) {
+ _cleanup_free_ char *buf = NULL;
+ size_t sz = 0;
+ char *f = strappenda(copy_dir, *p);
+
+ assert_se(access(f, F_OK) == 0);
+ assert_se(read_full_file(f, &buf, &sz) == 0);
+ assert_se(streq(buf, "file\n"));
+ }
+
+ STRV_FOREACH_PAIR(link, p, links) {
+ _cleanup_free_ char *target = NULL;
+ char *f = strappenda(original_dir, *p);
+ char *l = strappenda(copy_dir, *link);
+
+ assert_se(readlink_and_canonicalize(l, &target) == 0);
+ assert_se(path_equal(f, target));
+ }
+
+ assert_se(copy_tree(original_dir, copy_dir, false) < 0);
+ assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
+
+ rm_rf_dangerous(copy_dir, false, true, false);
+ rm_rf_dangerous(original_dir, false, true, false);
+}
+
+int main(int argc, char *argv[]) {
+ test_copy_file();
+ test_copy_file_fd();
+ test_copy_tree();
+
+ return 0;
+}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index 6acd394c67..456999ca40 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -66,7 +66,7 @@ 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) == -ENOEXEC);
+ assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLOCK);
manager_dump_jobs(m, stdout, "\t");
printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
@@ -82,14 +82,14 @@ 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) == -EEXIST);
+ assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLOCK);
printf("Test6: (Colliding transaction, replace)\n");
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, 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) == -EEXIST);
+ assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLOCK);
printf("Test8: (Mergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0);
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
new file mode 100644
index 0000000000..60466f0d3f
--- /dev/null
+++ b/src/test/test-execute.c
@@ -0,0 +1,178 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Ronny Chevalier
+
+ 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 "unit.h"
+#include "manager.h"
+#include "util.h"
+#include "macro.h"
+#include "strv.h"
+#include "mkdir.h"
+
+typedef void (*test_function_t)(Manager *m);
+
+static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
+ Service *service = NULL;
+ usec_t ts;
+ usec_t timeout = 2 * USEC_PER_SEC;
+
+ assert_se(m);
+ assert_se(unit);
+
+ service = SERVICE(unit);
+ printf("%s\n", unit->id);
+ exec_context_dump(&service->exec_context, stdout, "\t");
+ ts = now(CLOCK_MONOTONIC);
+ while (service->state != SERVICE_DEAD && service->state != SERVICE_FAILED) {
+ int r;
+ usec_t n;
+
+ r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
+ assert_se(r >= 0);
+
+ n = now(CLOCK_MONOTONIC);
+ if (ts + timeout < n) {
+ log_error("Test timeout when testing %s", unit->id);
+ exit(EXIT_FAILURE);
+ }
+ }
+ exec_status_dump(&service->main_exec_status, stdout, "\t");
+ assert_se(service->main_exec_status.status == status_expected);
+ assert_se(service->main_exec_status.code == code_expected);
+}
+
+static void test(Manager *m, const char *unit_name, int status_expected, int code_expected) {
+ Unit *unit;
+
+ assert_se(unit_name);
+
+ assert_se(manager_load_unit(m, unit_name, NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+ check(m, unit, status_expected, code_expected);
+}
+
+static void test_exec_workingdirectory(Manager *m) {
+ assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
+
+ test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
+
+ rm_rf_dangerous("/tmp/test-exec_workingdirectory", false, true, false);
+}
+
+static void test_exec_personality(Manager *m) {
+ test(m, "exec-personality-x86.service", 0, CLD_EXITED);
+
+#if defined(__x86_64__)
+ test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
+#endif
+}
+
+static void test_exec_ignoresigpipe(Manager *m) {
+ test(m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
+ test(m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
+}
+
+static void test_exec_privatetmp(Manager *m) {
+ assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
+
+ test(m, "exec-privatetmp-yes.service", 0, CLD_EXITED);
+ test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
+
+ unlink("/tmp/test-exec_privatetmp");
+}
+
+static void test_exec_privatedevices(Manager *m) {
+ test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED);
+ test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
+}
+
+static void test_exec_systemcallfilter(Manager *m) {
+#ifdef HAVE_SECCOMP
+ test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
+ test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
+ test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
+ test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
+#endif
+}
+
+static void test_exec_systemcallerrornumber(Manager *m) {
+#ifdef HAVE_SECCOMP
+ test(m, "exec-systemcallerrornumber.service", 1, CLD_EXITED);
+#endif
+}
+
+static void test_exec_user(Manager *m) {
+ test(m, "exec-user.service", 0, CLD_EXITED);
+}
+
+static void test_exec_group(Manager *m) {
+ test(m, "exec-group.service", 0, CLD_EXITED);
+}
+
+static void test_exec_environment(Manager *m) {
+ test(m, "exec-environment.service", 0, CLD_EXITED);
+ test(m, "exec-environment-multiple.service", 0, CLD_EXITED);
+ test(m, "exec-environment-empty.service", 0, CLD_EXITED);
+}
+
+int main(int argc, char *argv[]) {
+ test_function_t tests[] = {
+ test_exec_workingdirectory,
+ test_exec_personality,
+ test_exec_ignoresigpipe,
+ test_exec_privatetmp,
+ test_exec_privatedevices,
+ test_exec_systemcallfilter,
+ test_exec_systemcallerrornumber,
+ test_exec_user,
+ test_exec_group,
+ test_exec_environment,
+ NULL,
+ };
+ test_function_t *test = NULL;
+ Manager *m = NULL;
+ int r;
+
+ log_parse_environment();
+ log_open();
+
+ /* It is needed otherwise cgroup creation fails */
+ if (getuid() != 0) {
+ printf("Skipping test: not root\n");
+ return EXIT_TEST_SKIP;
+ }
+
+ assert_se(set_unit_path(TEST_DIR ":") >= 0);
+
+ r = manager_new(SYSTEMD_USER, true, &m);
+ if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
+ printf("Skipping test: manager_new: %s", strerror(-r));
+ return EXIT_TEST_SKIP;
+ }
+ assert_se(r >= 0);
+ assert_se(manager_startup(m, NULL, NULL) >= 0);
+
+ for (test = tests; test && *test; test++)
+ (*test)(m);
+
+ manager_free(m);
+
+ return 0;
+}
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index 7e7b4ac45d..cdf1973ea5 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -331,28 +331,65 @@ static void test_write_string_file(void) {
unlink(fn);
}
-static void test_sendfile_full(void) {
- char in_fn[] = "/tmp/test-sendfile_full-XXXXXX";
- char out_fn[] = "/tmp/test-sendfile_full-XXXXXX";
- _cleanup_close_ int in_fd, out_fd;
- char text[] = "boohoo\nfoo\n\tbar\n";
+static void test_write_string_file_no_create(void) {
+ char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
+ _cleanup_close_ int fd;
char buf[64] = {0};
- in_fd = mkostemp_safe(in_fn, O_RDWR);
- assert_se(in_fd >= 0);
- out_fd = mkostemp_safe(out_fn, O_RDWR);
- assert_se(out_fd >= 0);
+ fd = mkostemp_safe(fn, O_RDWR);
+ assert_se(fd >= 0);
+
+ assert_se(write_string_file_no_create("/a/file/which/does/not/exists/i/guess", "boohoo") < 0);
+ assert_se(write_string_file_no_create(fn, "boohoo") == 0);
+
+ assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n"));
+ assert_se(streq(buf, "boohoo\n"));
+
+ unlink(fn);
+}
+
+static void test_load_env_file_pairs(void) {
+ char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
+ int fd;
+ int r;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_strv_free_ char **l = NULL;
+ char **k, **v;
+
+ fd = mkostemp_safe(fn, O_RDWR);
+ assert_se(fd >= 0);
+
+ r = write_string_file(fn,
+ "NAME=\"Arch Linux\"\n"
+ "ID=arch\n"
+ "PRETTY_NAME=\"Arch Linux\"\n"
+ "ANSI_COLOR=\"0;36\"\n"
+ "HOME_URL=\"https://www.archlinux.org/\"\n"
+ "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
+ "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n"
+ );
+ assert_se(r == 0);
+
+ f = fdopen(fd, "r");
+ assert_se(f);
- assert_se(write_string_file(in_fn, text) == 0);
- assert_se(sendfile_full(out_fd, "/a/file/which/does/not/exist/i/guess") < 0);
- assert_se(sendfile_full(out_fd, in_fn) == sizeof(text) - 1);
- assert_se(lseek(out_fd, SEEK_SET, 0) == 0);
+ r = load_env_file_pairs(f, fn, NULL, &l);
+ assert_se(r >= 0);
- assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1);
- assert_se(streq(buf, text));
+ assert_se(strv_length(l) == 14);
+ STRV_FOREACH_PAIR(k, v, l) {
+ assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
+ printf("%s=%s\n", *k, *v);
+ if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
+ if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
+ if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
+ if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
+ if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
+ if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
+ if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
+ }
- unlink(in_fn);
- unlink(out_fn);
+ unlink(fn);
}
int main(int argc, char *argv[]) {
@@ -366,7 +403,8 @@ int main(int argc, char *argv[]) {
test_capeff();
test_write_string_stream();
test_write_string_file();
- test_sendfile_full();
+ test_write_string_file_no_create();
+ test_load_env_file_pairs();
return 0;
}
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index ce686b650c..6f0910aae7 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -194,8 +194,8 @@ static void test_hashmap_move(void) {
hashmap_put(m, "key 3", val3);
hashmap_put(m, "key 4", val4);
- assert(hashmap_move(n, NULL) == 0);
- assert(hashmap_move(n, m) == 0);
+ assert_se(hashmap_move(n, NULL) == 0);
+ assert_se(hashmap_move(n, m) == 0);
assert_se(hashmap_size(m) == 1);
r = hashmap_get(m, "key 1");
@@ -246,7 +246,7 @@ static void test_hashmap_put(void) {
int valid_hashmap_put;
void *val1 = (void*) "val 1";
- hashmap_ensure_allocated(&m, &string_hash_ops);
+ assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0);
assert_se(m);
valid_hashmap_put = hashmap_put(m, "key 1", val1);
@@ -380,6 +380,7 @@ static void test_hashmap_remove_and_replace(void) {
void *key2 = UINT_TO_PTR(2);
void *key3 = UINT_TO_PTR(3);
void *r;
+ int i, j;
m = hashmap_new(&trivial_hash_ops);
assert_se(m);
@@ -407,6 +408,25 @@ static void test_hashmap_remove_and_replace(void) {
r = hashmap_get(m, key2);
assert_se(r == key2);
assert_se(!hashmap_get(m, key3));
+
+ /* Repeat this test several times to increase the chance of hitting
+ * the less likely case in hashmap_remove_and_replace where it
+ * compensates for the backward shift. */
+ for (i = 0; i < 20; i++) {
+ hashmap_clear(m);
+
+ for (j = 1; j < 7; j++)
+ hashmap_put(m, UINT_TO_PTR(10*i + j), UINT_TO_PTR(10*i + j));
+ valid = hashmap_remove_and_replace(m, UINT_TO_PTR(10*i + 1),
+ UINT_TO_PTR(10*i + 2),
+ UINT_TO_PTR(10*i + 2));
+ assert_se(valid == 0);
+ assert_se(!hashmap_get(m, UINT_TO_PTR(10*i + 1)));
+ for (j = 2; j < 7; j++) {
+ r = hashmap_get(m, UINT_TO_PTR(10*i + j));
+ assert_se(r == UINT_TO_PTR(10*i + j));
+ }
+ }
}
static void test_hashmap_ensure_allocated(void) {
@@ -699,9 +719,9 @@ static void test_hashmap_many(void) {
for (i = 1; i < tests[j].n_entries*3; i++)
assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1));
- log_info("%u <= %u * 0.75 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.75);
+ log_info("%u <= %u * 0.8 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8);
- assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.75);
+ assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8);
assert_se(hashmap_size(h) == tests[j].n_entries);
while (!hashmap_isempty(h)) {
diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c
index ad4f285619..86efa1a3f7 100644
--- a/src/test/test-hostname.c
+++ b/src/test/test-hostname.c
@@ -32,7 +32,7 @@ int main(int argc, char* argv[]) {
r = hostname_setup();
if (r < 0)
- fprintf(stderr, "hostname: %s\n", strerror(-r));
+ log_error_errno(r, "hostname: %m");
return 0;
}
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index a51814df95..293c151d42 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -34,14 +34,6 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-_printf_(6,0)
-static void log_fn(struct udev *udev,
- int priority, const char *file, int line, const char *fn,
- const char *format, va_list args) {
- printf("test-libudev: %s %s:%d ", fn, file, line);
- vprintf(format, args);
-}
-
static void print_device(struct udev_device *device) {
const char *str;
dev_t devnum;
@@ -431,9 +423,6 @@ int main(int argc, char *argv[]) {
printf("no context\n");
return 1;
}
- udev_set_log_fn(udev, log_fn);
- printf("set log: %p\n", log_fn);
-
while ((c = getopt_long(argc, argv, "p:s:dhV", options, NULL)) >= 0)
switch (c) {
@@ -447,8 +436,8 @@ int main(int argc, char *argv[]) {
break;
case 'd':
- if (udev_get_log_priority(udev) < LOG_INFO)
- udev_set_log_priority(udev, LOG_INFO);
+ if (log_get_max_level() < LOG_INFO)
+ log_set_max_level(LOG_INFO);
break;
case 'h':
diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c
new file mode 100644
index 0000000000..1398a3a0b9
--- /dev/null
+++ b/src/test/test-locale-util.c
@@ -0,0 +1,59 @@
+/***
+ This file is part of systemd
+
+ Copyright 2014 Ronny Chevalier
+
+ 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 <unistd.h>
+
+#include "locale-util.h"
+#include "strv.h"
+#include "macro.h"
+
+static void test_get_locales(void) {
+ _cleanup_strv_free_ char **locales = NULL;
+ char **p;
+ int r;
+
+ r = get_locales(&locales);
+ assert_se(r >= 0);
+ assert_se(locales);
+
+ STRV_FOREACH(p, locales) {
+ puts(*p);
+ assert_se(locale_is_valid(*p));
+ }
+}
+
+static void test_locale_is_valid(void) {
+ assert_se(locale_is_valid("en_EN.utf8"));
+ assert_se(locale_is_valid("fr_FR.utf8"));
+ assert_se(locale_is_valid("fr_FR@euro"));
+ assert_se(locale_is_valid("fi_FI"));
+ assert_se(locale_is_valid("POSIX"));
+ assert_se(locale_is_valid("C"));
+
+ assert_se(!locale_is_valid(""));
+ assert_se(!locale_is_valid("/usr/bin/foo"));
+ assert_se(!locale_is_valid("\x01gar\x02 bage\x03"));
+}
+
+int main(int argc, char *argv[]) {
+ test_get_locales();
+ test_locale_is_valid();
+
+ return 0;
+}
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 7714e49ad9..7cd7b77153 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -65,12 +65,12 @@ int main(int argc, char *argv[]) {
PROTECT_SYSTEM_NO,
0);
if (r < 0) {
- log_error("Failed to setup namespace: %s", strerror(-r));
+ log_error_errno(r, "Failed to setup namespace: %m");
return 1;
}
execl("/bin/sh", "/bin/sh", NULL);
- log_error("execl(): %m");
+ log_error_errno(errno, "execl(): %m");
return 1;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 63d64b28b0..58b456a291 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -85,29 +85,32 @@ static void test_path(void) {
}
}
-static void test_find_binary(const char *self) {
+static void test_find_binary(const char *self, bool local) {
char *p;
- assert_se(find_binary("/bin/sh", &p) == 0);
+ assert_se(find_binary("/bin/sh", local, &p) == 0);
puts(p);
assert_se(streq(p, "/bin/sh"));
free(p);
- assert_se(find_binary(self, &p) == 0);
+ assert_se(find_binary(self, local, &p) == 0);
puts(p);
assert_se(endswith(p, "/test-path-util"));
assert_se(path_is_absolute(p));
free(p);
- assert_se(find_binary("sh", &p) == 0);
+ assert_se(find_binary("sh", local, &p) == 0);
puts(p);
assert_se(endswith(p, "/sh"));
assert_se(path_is_absolute(p));
free(p);
- assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
+ assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT);
- assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
+ assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) ==
+ (local ? -ENOENT : 0));
+ if (!local)
+ free(p);
}
static void test_prefixes(void) {
@@ -242,13 +245,35 @@ static void test_strv_resolve(void) {
assert_se(rm_rf_dangerous(tmp_dir, false, true, false) == 0);
}
+static void test_path_startswith(void) {
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo/"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "////"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/"));
+ assert_se(path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo"));
+
+ assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/"));
+ assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa"));
+ assert_se(!path_startswith("/foo/bar/barfoo/", ""));
+ assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo"));
+ assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/"));
+}
+
int main(int argc, char **argv) {
test_path();
- test_find_binary(argv[0]);
+ test_find_binary(argv[0], true);
+ test_find_binary(argv[0], false);
test_prefixes();
test_path_join();
test_fsck_exists();
test_make_relative();
test_strv_resolve();
+ test_path_startswith();
+
return 0;
}
diff --git a/src/test/test-path.c b/src/test/test-path.c
new file mode 100644
index 0000000000..18fcb575e6
--- /dev/null
+++ b/src/test/test-path.c
@@ -0,0 +1,271 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Ronny Chevalier
+
+ 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 <stdbool.h>
+
+#include "unit.h"
+#include "manager.h"
+#include "util.h"
+#include "macro.h"
+#include "strv.h"
+#include "mkdir.h"
+
+typedef void (*test_function_t)(Manager *m);
+
+static int setup_test(Manager **m) {
+ char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
+ "directorynotempty", "makedirectory");
+ char **test_path;
+ Manager *tmp;
+ int r;
+
+ assert_se(m);
+
+ r = manager_new(SYSTEMD_USER, true, &tmp);
+ if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
+ printf("Skipping test: manager_new: %s", strerror(-r));
+ return -EXIT_TEST_SKIP;
+ }
+ assert_se(r >= 0);
+ assert_se(manager_startup(tmp, NULL, NULL) >= 0);
+
+ STRV_FOREACH(test_path, tests_path) {
+ rm_rf_dangerous(strappenda("/tmp/test-path_", *test_path), false, true, false);
+ }
+
+ *m = tmp;
+
+ return 0;
+}
+
+static void shutdown_test(Manager *m) {
+ assert_se(m);
+
+ manager_free(m);
+}
+
+static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, const char *service_name) {
+ _cleanup_free_ char *tmp = NULL;
+ Unit *service_unit = NULL;
+ Service *service = NULL;
+ usec_t ts;
+ usec_t timeout = 2 * USEC_PER_SEC;
+
+ assert_se(m);
+ assert_se(unit);
+ assert_se(test_path);
+
+ if (!service_name) {
+ assert_se(tmp = strreplace(unit->id, ".path", ".service"));
+ service_unit = manager_get_unit(m, tmp);
+ } else
+ service_unit = manager_get_unit(m, service_name);
+ assert_se(service_unit);
+ service = SERVICE(service_unit);
+
+ ts = now(CLOCK_MONOTONIC);
+ /* We proces events until the service related to the path has been successfully started */
+ while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) {
+ usec_t n;
+ int r;
+
+ r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
+ assert_se(r >= 0);
+
+ printf("%s: state = %s; result = %s \n",
+ service_unit->id,
+ service_state_to_string(service->state),
+ service_result_to_string(service->result));
+
+
+ /* But we timeout if the service has not been started in the allocated time */
+ n = now(CLOCK_MONOTONIC);
+ if (ts + timeout < n) {
+ log_error("Test timeout when testing %s", unit->id);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
+ rm_rf_dangerous(test_path, false, true, false);
+}
+
+static void test_path_exists(Manager *m) {
+ const char *test_path = "/tmp/test-path_exists";
+ Unit *unit = NULL;
+
+ assert_se(m);
+
+ assert_se(manager_load_unit(m, "path-exists.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ assert_se(touch(test_path) >= 0);
+
+ check_stop_unlink(m, unit, test_path, NULL);
+}
+
+static void test_path_existsglob(Manager *m) {
+ const char *test_path = "/tmp/test-path_existsglobFOOBAR";
+ Unit *unit = NULL;
+
+ assert_se(m);
+ assert_se(manager_load_unit(m, "path-existsglob.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ assert_se(touch(test_path) >= 0);
+
+ check_stop_unlink(m, unit, test_path, NULL);
+}
+
+static void test_path_changed(Manager *m) {
+ const char *test_path = "/tmp/test-path_changed";
+ FILE *f;
+ Unit *unit = NULL;
+
+ assert_se(m);
+
+ assert_se(touch(test_path) >= 0);
+
+ assert_se(manager_load_unit(m, "path-changed.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ f = fopen(test_path, "w");
+ assert_se(f);
+ fclose(f);
+
+ check_stop_unlink(m, unit, test_path, NULL);
+}
+
+static void test_path_modified(Manager *m) {
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *test_path = "/tmp/test-path_modified";
+ Unit *unit = NULL;
+
+ assert_se(m);
+
+ assert_se(touch(test_path) >= 0);
+
+ assert_se(manager_load_unit(m, "path-modified.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ f = fopen(test_path, "w");
+ assert_se(f);
+ fputs("test", f);
+
+ check_stop_unlink(m, unit, test_path, NULL);
+}
+
+static void test_path_unit(Manager *m) {
+ const char *test_path = "/tmp/test-path_unit";
+ Unit *unit = NULL;
+
+ assert_se(m);
+
+ assert_se(manager_load_unit(m, "path-unit.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ assert_se(touch(test_path) >= 0);
+
+ check_stop_unlink(m, unit, test_path, "path-mycustomunit.service");
+}
+
+static void test_path_directorynotempty(Manager *m) {
+ const char *test_path = "/tmp/test-path_directorynotempty/";
+ Unit *unit = NULL;
+
+ assert_se(m);
+
+ assert_se(access(test_path, F_OK) < 0);
+
+ assert_se(manager_load_unit(m, "path-directorynotempty.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ /* MakeDirectory default to no */
+ assert_se(access(test_path, F_OK) < 0);
+
+ assert_se(mkdir_p(test_path, 0755) >= 0);
+ assert_se(touch(strappenda(test_path, "test_file")) >= 0);
+
+ check_stop_unlink(m, unit, test_path, NULL);
+}
+
+static void test_path_makedirectory_directorymode(Manager *m) {
+ const char *test_path = "/tmp/test-path_makedirectory/";
+ Unit *unit = NULL;
+ struct stat s;
+
+ assert_se(m);
+
+ assert_se(access(test_path, F_OK) < 0);
+
+ assert_se(manager_load_unit(m, "path-makedirectory.path", NULL, NULL, &unit) >= 0);
+ assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
+
+ /* Check if the directory has been created */
+ assert_se(access(test_path, F_OK) >= 0);
+
+ /* Check the mode we specified with DirectoryMode=0744 */
+ assert_se(stat(test_path, &s) >= 0);
+ assert_se((s.st_mode & S_IRWXU) == 0700);
+ assert_se((s.st_mode & S_IRWXG) == 0040);
+ assert_se((s.st_mode & S_IRWXO) == 0004);
+
+ assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
+ rm_rf_dangerous(test_path, false, true, false);
+}
+
+int main(int argc, char *argv[]) {
+ test_function_t tests[] = {
+ test_path_exists,
+ test_path_existsglob,
+ test_path_changed,
+ test_path_modified,
+ test_path_unit,
+ test_path_directorynotempty,
+ test_path_makedirectory_directorymode,
+ NULL,
+ };
+ test_function_t *test = NULL;
+ Manager *m = NULL;
+
+ log_parse_environment();
+ log_open();
+
+ /* It is needed otherwise cgroup creation fails */
+ if (getuid() != 0)
+ return EXIT_TEST_SKIP;
+
+ assert_se(set_unit_path(TEST_DIR ":") >= 0);
+
+ for (test = tests; test && *test; test++) {
+ int r;
+
+ /* We create a clean environment for each test */
+ r = setup_test(&m);
+ if (r < 0)
+ return -r;
+
+ (*test)(m);
+
+ shutdown_test(m);
+ }
+
+ return 0;
+}
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index c2c728bcde..6fb4a40944 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -258,7 +258,7 @@ static void test_nameinfo_pretty(void) {
_cleanup_close_ int sfd = -1, cfd = -1;
r = getnameinfo_pretty(STDIN_FILENO, &stdin_name);
- log_info("No connection remote: %s", strerror(-r));
+ log_info_errno(r, "No connection remote: %m");
assert_se(r < 0);
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index bbfe306d7d..674c1b53fc 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -113,6 +113,22 @@ static void test_strv_find_prefix(void) {
assert_se(!strv_find_prefix((char **)input_table_multiple, "onee"));
}
+static void test_strv_find_startswith(void) {
+ char *r;
+
+ r = strv_find_startswith((char **)input_table_multiple, "o");
+ assert_se(r && streq(r, "ne"));
+
+ r = strv_find_startswith((char **)input_table_multiple, "one");
+ assert_se(r && streq(r, ""));
+
+ r = strv_find_startswith((char **)input_table_multiple, "");
+ assert_se(r && streq(r, "one"));
+
+ assert_se(!strv_find_startswith((char **)input_table_multiple, "xxx"));
+ assert_se(!strv_find_startswith((char **)input_table_multiple, "onee"));
+}
+
static void test_strv_join(void) {
_cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL;
@@ -149,7 +165,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
assert_se(p);
assert_se(streq(p, quoted));
- r = strv_split_quoted(&s, quoted);
+ r = strv_split_quoted(&s, quoted, false);
assert_se(r == 0);
assert_se(s);
STRV_FOREACH(t, s) {
@@ -166,7 +182,7 @@ static void test_strv_unquote(const char *quoted, const char **list) {
char **t;
int r;
- r = strv_split_quoted(&s, quoted);
+ r = strv_split_quoted(&s, quoted, false);
assert_se(r == 0);
assert_se(s);
j = strv_join(s, " | ");
@@ -183,7 +199,7 @@ static void test_invalid_unquote(const char *quoted) {
char **s = NULL;
int r;
- r = strv_split_quoted(&s, quoted);
+ r = strv_split_quoted(&s, quoted, false);
assert_se(s == NULL);
assert_se(r == -EINVAL);
}
@@ -416,6 +432,44 @@ static void test_strv_from_stdarg_alloca(void) {
test_strv_from_stdarg_alloca_one(STRV_MAKE_EMPTY, NULL);
}
+static void test_strv_push_prepend(void) {
+ _cleanup_strv_free_ char **a = NULL;
+
+ a = strv_new("foo", "bar", "three", NULL);
+
+ assert_se(strv_push_prepend(&a, strdup("first")) >= 0);
+ assert_se(streq(a[0], "first"));
+ assert_se(streq(a[1], "foo"));
+ assert_se(streq(a[2], "bar"));
+ assert_se(streq(a[3], "three"));
+ assert_se(!a[4]);
+
+ assert_se(strv_consume_prepend(&a, strdup("first2")) >= 0);
+ assert_se(streq(a[0], "first2"));
+ assert_se(streq(a[1], "first"));
+ assert_se(streq(a[2], "foo"));
+ assert_se(streq(a[3], "bar"));
+ assert_se(streq(a[4], "three"));
+ assert_se(!a[5]);
+}
+
+static void test_strv_push(void) {
+ _cleanup_strv_free_ char **a = NULL;
+ char *i, *j;
+
+ assert_se(i = strdup("foo"));
+ assert_se(strv_push(&a, i) >= 0);
+
+ assert_se(i = strdup("a"));
+ assert_se(j = strdup("b"));
+ assert_se(strv_push_pair(&a, i, j) >= 0);
+
+ assert_se(streq_ptr(a[0], "foo"));
+ assert_se(streq_ptr(a[1], "a"));
+ assert_se(streq_ptr(a[2], "b"));
+ assert_se(streq_ptr(a[3], NULL));
+}
+
int main(int argc, char *argv[]) {
test_specifier_printf();
test_strv_foreach();
@@ -423,6 +477,7 @@ int main(int argc, char *argv[]) {
test_strv_foreach_pair();
test_strv_find();
test_strv_find_prefix();
+ test_strv_find_startswith();
test_strv_join();
test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\"");
@@ -444,12 +499,12 @@ int main(int argc, char *argv[]) {
test_strv_unquote(" \"x'\" ", (const char*[]) { "x'", NULL });
test_strv_unquote("a '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL });
- test_invalid_unquote("a --b='c \"d e\"'");
- test_invalid_unquote("a --b='c \"d e\" '");
+ test_invalid_unquote("a --b='c \"d e\"''");
+ test_invalid_unquote("a --b='c \"d e\" '\"");
test_invalid_unquote("a --b='c \"d e\"garbage");
test_invalid_unquote("'");
test_invalid_unquote("\"");
- test_invalid_unquote("'x'y");
+ test_invalid_unquote("'x'y'g");
test_strv_split();
test_strv_split_newlines();
@@ -462,6 +517,8 @@ int main(int argc, char *argv[]) {
test_strv_extend();
test_strv_extendf();
test_strv_from_stdarg_alloca();
+ test_strv_push_prepend();
+ test_strv_push();
return 0;
}
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 907958e461..97d5609adf 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -48,6 +48,7 @@
#include "link-config.h"
#include "bus-policy.h"
#include "journald-server.h"
+#include "locale-util.h"
#include "test-tables.h"
@@ -60,6 +61,8 @@ int main(int argc, char **argv) {
test_table(busname_state, BUSNAME_STATE);
test_table(cgroup_device_policy, CGROUP_DEVICE_POLICY);
test_table(condition_type, CONDITION_TYPE);
+ test_table(assert_type, CONDITION_TYPE);
+ test_table(condition_result, CONDITION_RESULT);
test_table(device_state, DEVICE_STATE);
test_table(exec_input, EXEC_INPUT);
test_table(exec_output, EXEC_OUTPUT);
@@ -116,6 +119,7 @@ int main(int argc, char **argv) {
test_table(unit_file_state, UNIT_FILE_STATE);
test_table(unit_load_state, UNIT_LOAD_STATE);
test_table(unit_type, UNIT_TYPE);
+ test_table(locale_variable, VARIABLE_LC);
test_table_sparse(object_compressed, OBJECT_COMPRESSED);
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 8a51473419..f2283ec7a7 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -35,10 +35,6 @@
#include "udev.h"
#include "udev-util.h"
-void udev_main_log(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args) {}
-
static int fake_filesystems(void) {
static const struct fakefs {
const char *src;
@@ -153,8 +149,14 @@ int main(int argc, char *argv[]) {
}
}
- udev_event_execute_rules(event, 3 * USEC_PER_SEC, USEC_PER_SEC, rules, &sigmask_orig);
- udev_event_execute_run(event, 3 * USEC_PER_SEC, USEC_PER_SEC, NULL);
+ udev_event_execute_rules(event,
+ 3 * USEC_PER_SEC, USEC_PER_SEC,
+ NULL,
+ rules,
+ &sigmask_orig);
+ udev_event_execute_run(event,
+ 3 * USEC_PER_SEC, USEC_PER_SEC,
+ NULL);
out:
if (event != NULL && event->fd_signal >= 0)
close(event->fd_signal);
diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c
index 06b4d43426..bc5baa2fcb 100644
--- a/src/test/test-uid-range.c
+++ b/src/test/test-uid-range.c
@@ -39,7 +39,7 @@ int main(int argc, char *argv[]) {
assert_se(uid_range_contains(p, n, 999));
assert_se(!uid_range_contains(p, n, 1000));
- search = (uid_t) -1;
+ search = UID_INVALID;
assert_se(uid_range_next_lower(p, n, &search));
assert_se(search == 999);
assert_se(uid_range_next_lower(p, n, &search));
diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c
new file mode 100644
index 0000000000..1754d06b2d
--- /dev/null
+++ b/src/test/test-unaligned.c
@@ -0,0 +1,93 @@
+/***
+ 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 "unaligned.h"
+#include "sparse-endian.h"
+#include "util.h"
+
+static uint8_t data[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+};
+
+int main(int argc, const char *argv[]) {
+ uint8_t scratch[16];
+
+ assert_se(unaligned_read_be16(&data[0]) == 0x0001);
+ assert_se(unaligned_read_be16(&data[1]) == 0x0102);
+
+ assert_se(unaligned_read_be32(&data[0]) == 0x00010203);
+ assert_se(unaligned_read_be32(&data[1]) == 0x01020304);
+ assert_se(unaligned_read_be32(&data[2]) == 0x02030405);
+ assert_se(unaligned_read_be32(&data[3]) == 0x03040506);
+
+ assert_se(unaligned_read_be64(&data[0]) == 0x0001020304050607);
+ assert_se(unaligned_read_be64(&data[1]) == 0x0102030405060708);
+ assert_se(unaligned_read_be64(&data[2]) == 0x0203040506070809);
+ assert_se(unaligned_read_be64(&data[3]) == 0x030405060708090a);
+ assert_se(unaligned_read_be64(&data[4]) == 0x0405060708090a0b);
+ assert_se(unaligned_read_be64(&data[5]) == 0x05060708090a0b0c);
+ assert_se(unaligned_read_be64(&data[6]) == 0x060708090a0b0c0d);
+ assert_se(unaligned_read_be64(&data[7]) == 0x0708090a0b0c0d0e);
+
+ zero(scratch);
+ unaligned_write_be16(&scratch[0], 0x0001);
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint16_t)) == 0);
+ zero(scratch);
+ unaligned_write_be16(&scratch[1], 0x0102);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint16_t)) == 0);
+
+ zero(scratch);
+ unaligned_write_be32(&scratch[0], 0x00010203);
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_be32(&scratch[1], 0x01020304);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_be32(&scratch[2], 0x02030405);
+ assert_se(memcmp(&scratch[2], &data[2], sizeof(uint32_t)) == 0);
+ zero(scratch);
+ unaligned_write_be32(&scratch[3], 0x03040506);
+ assert_se(memcmp(&scratch[3], &data[3], sizeof(uint32_t)) == 0);
+
+ zero(scratch);
+ unaligned_write_be64(&scratch[0], 0x0001020304050607);
+ assert_se(memcmp(&scratch[0], &data[0], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[1], 0x0102030405060708);
+ assert_se(memcmp(&scratch[1], &data[1], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[2], 0x0203040506070809);
+ assert_se(memcmp(&scratch[2], &data[2], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[3], 0x030405060708090a);
+ assert_se(memcmp(&scratch[3], &data[3], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[4], 0x0405060708090a0b);
+ assert_se(memcmp(&scratch[4], &data[4], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[5], 0x05060708090a0b0c);
+ assert_se(memcmp(&scratch[5], &data[5], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[6], 0x060708090a0b0c0d);
+ assert_se(memcmp(&scratch[6], &data[6], sizeof(uint64_t)) == 0);
+ zero(scratch);
+ unaligned_write_be64(&scratch[7], 0x0708090a0b0c0d0e);
+ assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0);
+}
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 03b3e25939..f31a1bbc9b 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -222,6 +222,9 @@ static void test_config_parse_exec(void) {
"MODULE_0=coretemp\n" \
"MODULE_1=f71882fg"
+#define env_file_5 \
+ "a=\n" \
+ "b="
static void test_load_env_file_1(void) {
_cleanup_strv_free_ char **data = NULL;
@@ -300,6 +303,24 @@ static void test_load_env_file_4(void) {
unlink(name);
}
+static void test_load_env_file_5(void) {
+ _cleanup_strv_free_ char **data = NULL;
+ int r;
+
+ char name[] = "/tmp/test-load-env-file.XXXXXX";
+ _cleanup_close_ int fd;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5));
+
+ r = load_env_file(NULL, name, NULL, &data);
+ assert_se(r == 0);
+ assert_se(streq(data[0], "a="));
+ assert_se(streq(data[1], "b="));
+ assert_se(data[2] == NULL);
+ unlink(name);
+}
static void test_install_printf(void) {
char name[] = "name.service",
@@ -387,6 +408,7 @@ int main(int argc, char *argv[]) {
test_load_env_file_2();
test_load_env_file_3();
test_load_env_file_4();
+ test_load_env_file_5();
TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
return r;
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 256e820c22..ab6c488cff 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -135,7 +135,7 @@ static int test_unit_printf(void) {
#define expect(unit, pattern, expected) \
{ \
char *e; \
- _cleanup_free_ char *t; \
+ _cleanup_free_ char *t = NULL; \
assert_se(unit_full_printf(unit, pattern, &t) >= 0); \
printf("result: %s\nexpect: %s\n", t, expected); \
if ((e = endswith(expected, "*"))) \
diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c
index b7d988f22d..3399f2ba9c 100644
--- a/src/test/test-utf8.c
+++ b/src/test/test-utf8.c
@@ -47,7 +47,6 @@ static void test_utf8_encoded_valid_unichar(void) {
assert_se(utf8_encoded_valid_unichar("a") == 1);
assert_se(utf8_encoded_valid_unichar("\341\204") < 0);
assert_se(utf8_encoded_valid_unichar("\341\204\341\204") < 0);
-
}
static void test_utf8_escaping(void) {
@@ -66,12 +65,41 @@ static void test_utf8_escaping(void) {
assert_se(utf8_is_valid(p3));
}
+static void test_utf8_escaping_printable(void) {
+ _cleanup_free_ char *p1, *p2, *p3, *p4, *p5, *p6;
+
+ p1 = utf8_escape_non_printable("goo goo goo");
+ puts(p1);
+ assert_se(utf8_is_valid(p1));
+
+ p2 = utf8_escape_non_printable("\341\204\341\204");
+ puts(p2);
+ assert_se(utf8_is_valid(p2));
+
+ p3 = utf8_escape_non_printable("\341\204");
+ puts(p3);
+ assert_se(utf8_is_valid(p3));
+
+ p4 = utf8_escape_non_printable("ąę\n가너도루\n1234\n\341\204\341\204\n\001 \019\20\a");
+ puts(p4);
+ assert_se(utf8_is_valid(p4));
+
+ p5 = utf8_escape_non_printable("\001 \019\20\a");
+ puts(p5);
+ assert_se(utf8_is_valid(p5));
+
+ p6 = utf8_escape_non_printable("\xef\xbf\x30\x13");
+ puts(p6);
+ assert_se(utf8_is_valid(p6));
+}
+
int main(int argc, char *argv[]) {
test_utf8_is_valid();
test_utf8_is_printable();
test_ascii_is_valid();
test_utf8_encoded_valid_unichar();
test_utf8_escaping();
+ test_utf8_escaping_printable();
return 0;
}
diff --git a/src/test/test-util.c b/src/test/test-util.c
index de6a2a0d89..fe54586eee 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -35,6 +35,7 @@
#include "def.h"
#include "fileio.h"
#include "conf-parser.h"
+#include "virt.h"
static void test_streq_ptr(void) {
assert_se(streq_ptr(NULL, NULL));
@@ -490,13 +491,14 @@ static void test_u64log2(void) {
static void test_get_process_comm(void) {
struct stat st;
- _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL;
- unsigned long long b;
+ _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL;
+ _cleanup_free_ char *env = NULL;
pid_t e;
uid_t u;
gid_t g;
dev_t h;
int r;
+ pid_t me;
if (stat("/proc/1/comm", &st) == 0) {
assert_se(get_process_comm(1, &a) >= 0);
@@ -505,9 +507,6 @@ static void test_get_process_comm(void) {
log_warning("/proc/1/comm does not exist.");
}
- assert_se(get_starttime_of_pid(1, &b) >= 0);
- log_info("pid1 starttime: '%llu'", b);
-
assert_se(get_process_cmdline(1, 0, true, &c) >= 0);
log_info("pid1 cmdline: '%s'", c);
@@ -532,7 +531,22 @@ static void test_get_process_comm(void) {
log_info("pid1 gid: "GID_FMT, g);
assert_se(g == 0);
- assert_se(get_ctty_devnr(1, &h) == -ENOENT);
+ me = getpid();
+
+ r = get_process_cwd(me, &cwd);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 cwd: '%s'", cwd);
+
+ r = get_process_root(me, &root);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("pid1 root: '%s'", root);
+
+ r = get_process_environ(me, &env);
+ assert_se(r >= 0 || r == -EACCES);
+ log_info("self strlen(environ): '%zd'", strlen(env));
+
+ if (!detect_container(NULL))
+ assert_se(get_ctty_devnr(1, &h) == -ENOENT);
getenv_for_pid(1, "PATH", &i);
log_info("pid1 $PATH: '%s'", strna(i));
@@ -1173,51 +1187,61 @@ static void test_unquote_first_word(void) {
char *t;
p = original = "foobar waldo";
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 7);
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 12);
- assert_se(unquote_first_word(&p, &t) == 0);
+ assert_se(unquote_first_word(&p, &t, false) == 0);
assert_se(!t);
assert_se(p == original + 12);
p = original = "\"foobar\" \'waldo\'";
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 9);
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "waldo"));
free(t);
assert_se(p == original + 16);
- assert_se(unquote_first_word(&p, &t) == 0);
+ assert_se(unquote_first_word(&p, &t, false) == 0);
assert_se(!t);
assert_se(p == original + 16);
p = original = "\"";
- assert_se(unquote_first_word(&p, &t) == -EINVAL);
+ assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
assert_se(p == original + 1);
p = original = "\'";
- assert_se(unquote_first_word(&p, &t) == -EINVAL);
+ assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
assert_se(p == original + 1);
+ p = original = "\'fooo";
+ assert_se(unquote_first_word(&p, &t, false) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\'fooo";
+ assert_se(unquote_first_word(&p, &t, true) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(p == original + 5);
+
p = original = "yay\'foo\'bar";
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "yayfoobar"));
free(t);
assert_se(p == original + 11);
p = original = " foobar ";
- assert_se(unquote_first_word(&p, &t) > 0);
+ assert_se(unquote_first_word(&p, &t, false) > 0);
assert_se(streq(t, "foobar"));
free(t);
assert_se(p == original + 12);
@@ -1277,6 +1301,17 @@ static void test_unquote_many_words(void) {
free(a);
}
+static int parse_item(const char *key, const char *value) {
+ assert_se(key);
+
+ log_info("kernel cmdline option <%s> = <%s>", key, strna(value));
+ return 0;
+}
+
+static void test_parse_proc_cmdline(void) {
+ assert_se(parse_proc_cmdline(parse_item) >= 0);
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -1348,6 +1383,7 @@ int main(int argc, char *argv[]) {
test_execute_directory();
test_unquote_first_word();
test_unquote_many_words();
+ test_parse_proc_cmdline();
return 0;
}
diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c
index ccb1854708..f6bb045c3c 100644
--- a/src/test/test-watchdog.c
+++ b/src/test/test-watchdog.c
@@ -35,13 +35,13 @@ int main(int argc, char *argv[]) {
r = watchdog_set_timeout(&t);
if (r < 0)
- log_warning("Failed to open watchdog: %s", strerror(-r));
+ log_warning_errno(r, "Failed to open watchdog: %m");
for (i = 0; i < 5; i++) {
log_info("Pinging...");
r = watchdog_ping();
if (r < 0)
- log_warning("Failed to ping watchdog: %s", strerror(-r));
+ log_warning_errno(r, "Failed to ping watchdog: %m");
usleep(t/2);
}
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 0ba32d31c4..49196ca793 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -232,7 +232,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
map,
&info);
if (r < 0) {
- log_error("Failed to query server: %s", strerror(-r));
+ log_error_errno(r, "Failed to query server: %m");
goto fail;
}
@@ -363,10 +363,8 @@ static int list_timezones(sd_bus *bus, char **args, unsigned n) {
assert(n == 1);
r = get_timezones(&zones);
- if (r < 0) {
- log_error("Failed to read list of time zones: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read list of time zones: %m");
pager_open_if_enabled();
strv_print(zones);
@@ -558,7 +556,7 @@ int main(int argc, char *argv[]) {
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
- log_error("Failed to create bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c
index 8880812b49..bf567a1624 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -38,12 +38,18 @@
#include "fileio-label.h"
#include "label.h"
#include "bus-util.h"
-#include "bus-errors.h"
+#include "bus-error.h"
+#include "bus-common-errors.h"
#include "event-util.h"
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
+static BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map timedated_errors[] = {
+ SD_BUS_ERROR_MAP("org.freedesktop.timedate1.NoNTPSupport", ENOTSUP),
+ SD_BUS_ERROR_MAP_END
+};
+
typedef struct Context {
char *zone;
bool local_rtc;
@@ -70,7 +76,7 @@ static int context_read_data(Context *c) {
if (r == -EINVAL)
log_warning("/etc/localtime should be a symbolic link to a time zone data file in /usr/share/zoneinfo/.");
else
- log_warning("Failed to get target of /etc/localtime: %s", strerror(-r));
+ log_warning_errno(r, "Failed to get target of /etc/localtime: %m");
} else {
const char *e;
@@ -254,10 +260,8 @@ static int context_start_ntp(Context *c, sd_bus *bus, sd_bus_error *error) {
if (r < 0) {
if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND) ||
sd_bus_error_has_name(error, "org.freedesktop.systemd1.LoadFailed") ||
- sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit")) {
- sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
- return -ENOTSUP;
- }
+ sd_bus_error_has_name(error, "org.freedesktop.systemd1.NoSuchUnit"))
+ return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
return r;
}
@@ -298,10 +302,8 @@ static int context_enable_ntp(Context*c, sd_bus *bus, sd_bus_error *error) {
false);
if (r < 0) {
- if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND)) {
- sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
- return -ENOTSUP;
- }
+ if (sd_bus_error_has_name(error, SD_BUS_ERROR_FILE_NOT_FOUND))
+ return sd_bus_error_set_const(error, "org.freedesktop.timedate1.NoNTPSupport", "NTP not supported.");
return r;
}
@@ -411,7 +413,7 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
/* 1. Write new configuration file */
r = context_write_data_timezone(c);
if (r < 0) {
- log_error("Failed to set time zone: %s", strerror(-r));
+ log_error_errno(r, "Failed to set time zone: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set time zone: %s", strerror(-r));
}
@@ -429,9 +431,9 @@ static int method_set_timezone(sd_bus *bus, sd_bus_message *m, void *userdata, s
}
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
+ LOG_MESSAGE_ID(SD_MESSAGE_TIMEZONE_CHANGE),
"TIMEZONE=%s", c->zone,
- "MESSAGE=Changed time zone to '%s'.", c->zone,
+ LOG_MESSAGE("Changed time zone to '%s'.", c->zone),
NULL);
sd_bus_emit_properties_changed(bus, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "Timezone", NULL);
@@ -467,7 +469,7 @@ static int method_set_local_rtc(sd_bus *bus, sd_bus_message *m, void *userdata,
/* 1. Write new configuration file */
r = context_write_data_local_rtc(c);
if (r < 0) {
- log_error("Failed to set RTC to local/UTC: %s", strerror(-r));
+ log_error_errno(r, "Failed to set RTC to local/UTC: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set RTC to local/UTC: %s", strerror(-r));
}
@@ -569,7 +571,7 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
/* Set system clock */
if (clock_settime(CLOCK_REALTIME, &ts) < 0) {
- log_error("Failed to set local time: %m");
+ log_error_errno(errno, "Failed to set local time: %m");
return sd_bus_error_set_errnof(error, errno, "Failed to set local time: %m");
}
@@ -581,9 +583,9 @@ static int method_set_time(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bu
clock_set_hwclock(tm);
log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
+ LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
"REALTIME="USEC_FMT, timespec_load(&ts),
- "MESSAGE=Changed local time to %s", ctime(&ts.tv_sec),
+ LOG_MESSAGE("Changed local time to %s", ctime(&ts.tv_sec)),
NULL);
return sd_bus_reply_method_return(m, NULL);
@@ -649,28 +651,20 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
assert(_bus);
r = sd_bus_default_system(&bus);
- if (r < 0) {
- log_error("Failed to get system bus connection: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get system bus connection: %m");
r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/timedate1", "org.freedesktop.timedate1", timedate_vtable, c);
- if (r < 0) {
- log_error("Failed to register object: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register object: %m");
r = sd_bus_request_name(bus, "org.freedesktop.timedate1", 0);
- if (r < 0) {
- log_error("Failed to register name: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to register name: %m");
r = sd_bus_attach_event(bus, event, 0);
- if (r < 0) {
- log_error("Failed to attach bus to event loop: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach bus to event loop: %m");
*_bus = bus;
bus = NULL;
@@ -698,7 +692,7 @@ int main(int argc, char *argv[]) {
r = sd_event_default(&event);
if (r < 0) {
- log_error("Failed to allocate event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate event loop: %m");
goto finish;
}
@@ -710,19 +704,19 @@ int main(int argc, char *argv[]) {
r = context_read_data(&context);
if (r < 0) {
- log_error("Failed to read time zone data: %s", strerror(-r));
+ log_error_errno(r, "Failed to read time zone data: %m");
goto finish;
}
r = context_read_ntp(&context, bus);
if (r < 0) {
- log_error("Failed to determine whether NTP is enabled: %s", strerror(-r));
+ log_error_errno(r, "Failed to determine whether NTP is enabled: %m");
goto finish;
}
r = bus_event_loop_with_idle(event, bus, "org.freedesktop.timedate1", DEFAULT_EXIT_USEC, NULL, NULL);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index 4c2dcdb62b..be1f4bb151 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -97,8 +97,9 @@ int config_parse_servers(
int manager_parse_config_file(Manager *m) {
assert(m);
- return config_parse(NULL, "/etc/systemd/timesyncd.conf", NULL,
- "Time\0",
- config_item_perf_lookup, timesyncd_gperf_lookup,
- false, false, true, m);
+ return config_parse_many("/etc/systemd/timesyncd.conf",
+ CONF_DIRS_NULSTR("systemd/timesyncd.conf"),
+ "Time\0",
+ config_item_perf_lookup, timesyncd_gperf_lookup,
+ false, m);
}
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index 3ae01eb8fc..ef5854d07e 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -132,6 +132,8 @@ struct ntp_msg {
static int manager_arm_timer(Manager *m, usec_t next);
static int manager_clock_watch_setup(Manager *m);
+static int manager_listen_setup(Manager *m);
+static void manager_listen_stop(Manager *m);
static double ntp_ts_short_to_d(const struct ntp_ts_short *ts) {
return be16toh(ts->sec) + (be16toh(ts->frac) / 65536.0);
@@ -184,6 +186,10 @@ static int manager_send_request(Manager *m) {
m->event_timeout = sd_event_source_unref(m->event_timeout);
+ r = manager_listen_setup(m);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to setup connection socket: %m");
+
/*
* Set transmit timestamp, remember it; the server will send that back
* as the origin timestamp and we have an indication that this is the
@@ -204,7 +210,7 @@ static int manager_send_request(Manager *m) {
m->pending = true;
log_debug("Sent NTP request to %s (%s).", strna(pretty), m->current_server_name->string);
} else {
- log_debug("Sending NTP request to %s (%s) failed: %m", strna(pretty), m->current_server_name->string);
+ log_debug_errno(errno, "Sending NTP request to %s (%s) failed: %m", strna(pretty), m->current_server_name->string);
return manager_connect(m);
}
@@ -216,10 +222,8 @@ static int manager_send_request(Manager *m) {
m->retry_interval = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC;
r = manager_arm_timer(m, m->retry_interval);
- if (r < 0) {
- log_error("Failed to rearm timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to rearm timer: %m");
m->missed_replies++;
if (m->missed_replies > NTP_MAX_MISSED_REPLIES) {
@@ -229,10 +233,8 @@ static int manager_send_request(Manager *m) {
clock_boottime_or_monotonic(),
now(clock_boottime_or_monotonic()) + TIMEOUT_USEC, 0,
manager_timeout, m);
- if (r < 0) {
- log_error("Failed to arm timeout timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to arm timeout timer: %m");
}
return 0;
@@ -250,7 +252,6 @@ static int manager_arm_timer(Manager *m, usec_t next) {
int r;
assert(m);
- assert(m->event_receive);
if (next == 0) {
m->event_timer = sd_event_source_unref(m->event_timer);
@@ -309,21 +310,15 @@ static int manager_clock_watch_setup(Manager *m) {
safe_close(m->clock_watch_fd);
m->clock_watch_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
- if (m->clock_watch_fd < 0) {
- log_error("Failed to create timerfd: %m");
- return -errno;
- }
+ if (m->clock_watch_fd < 0)
+ return log_error_errno(errno, "Failed to create timerfd: %m");
- if (timerfd_settime(m->clock_watch_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0) {
- log_error("Failed to set up timerfd: %m");
- return -errno;
- }
+ if (timerfd_settime(m->clock_watch_fd, TFD_TIMER_ABSTIME|TFD_TIMER_CANCEL_ON_SET, &its, NULL) < 0)
+ return log_error_errno(errno, "Failed to set up timerfd: %m");
r = sd_event_add_io(m->event, &m->event_clock_watch, m->clock_watch_fd, EPOLLIN, manager_clock_watch, m);
- if (r < 0) {
- log_error("Failed to create clock watch event source: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create clock watch event source: %m");
return 0;
}
@@ -345,7 +340,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
tmx.constant = log2i(m->poll_interval_usec / USEC_PER_SEC) - 4;
tmx.maxerror = 0;
tmx.esterror = 0;
- log_debug(" adjust (slew): %+.3f sec\n", offset);
+ log_debug(" adjust (slew): %+.3f sec", offset);
} else {
tmx.modes = ADJ_STATUS | ADJ_NANO | ADJ_SETOFFSET;
@@ -360,7 +355,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
}
m->jumped = true;
- log_debug(" adjust (jump): %+.3f sec\n", offset);
+ log_debug(" adjust (jump): %+.3f sec", offset);
}
/*
@@ -610,6 +605,9 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->pending = false;
m->retry_interval = 0;
+ /* Stop listening */
+ manager_listen_stop(m);
+
/* announce leap seconds */
if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC)
leap_sec = 1;
@@ -678,7 +676,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("Failed to call clock_adjtime(): %m");
+ log_error_errno(errno, "Failed to call clock_adjtime(): %m");
}
log_info("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s",
@@ -686,10 +684,8 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
spike ? " (ignored)" : "");
r = manager_arm_timer(m, m->poll_interval_usec);
- if (r < 0) {
- log_error("Failed to rearm timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to rearm timer: %m");
return 0;
}
@@ -702,7 +698,9 @@ static int manager_listen_setup(Manager *m) {
assert(m);
- assert(m->server_socket < 0);
+ if (m->server_socket >= 0)
+ return 0;
+
assert(!m->event_receive);
assert(m->current_server_address);
@@ -725,6 +723,13 @@ static int manager_listen_setup(Manager *m) {
return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m);
}
+static void manager_listen_stop(Manager *m) {
+ assert(m);
+
+ m->event_receive = sd_event_source_unref(m->event_receive);
+ m->server_socket = safe_close(m->server_socket);
+}
+
static int manager_begin(Manager *m) {
_cleanup_free_ char *pretty = NULL;
int r;
@@ -741,12 +746,6 @@ static int manager_begin(Manager *m) {
log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string);
sd_notifyf(false, "STATUS=Using Time Server %s (%s).", strna(pretty), m->current_server_name->string);
- r = manager_listen_setup(m);
- if (r < 0) {
- log_warning("Failed to setup connection socket: %s", strerror(-r));
- return r;
- }
-
r = manager_clock_watch_setup(m);
if (r < 0)
return r;
@@ -820,10 +819,8 @@ static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct ad
}
r = server_address_new(m->current_server_name, &a, (const union sockaddr_union*) ai->ai_addr, ai->ai_addrlen);
- if (r < 0) {
- log_error("Failed to add server address: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add server address: %m");
server_address_pretty(a, &pretty);
log_debug("Resolved address %s for %s.", pretty, m->current_server_name->string);
@@ -861,10 +858,8 @@ int manager_connect(Manager *m) {
log_debug("Slowing down attempts to contact servers.");
r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + RETRY_USEC, 0, manager_retry_connect, m);
- if (r < 0) {
- log_error("Failed to create retry timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create retry timer: %m");
return 0;
}
@@ -917,10 +912,8 @@ int manager_connect(Manager *m) {
if (restart && !m->exhausted_servers && m->poll_interval_usec) {
log_debug("Waiting after exhausting servers.");
r = sd_event_add_time(m->event, &m->event_retry, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()) + m->poll_interval_usec, 0, manager_retry_connect, m);
- if (r < 0) {
- log_error("Failed to create retry timer: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create retry timer: %m");
m->exhausted_servers = true;
@@ -946,10 +939,8 @@ int manager_connect(Manager *m) {
log_debug("Resolving %s...", m->current_server_name->string);
r = sd_resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, m);
- if (r < 0) {
- log_error("Failed to create resolver: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create resolver: %m");
return 1;
}
@@ -968,8 +959,7 @@ void manager_disconnect(Manager *m) {
m->event_timer = sd_event_source_unref(m->event_timer);
- m->event_receive = sd_event_source_unref(m->event_receive);
- m->server_socket = safe_close(m->server_socket);
+ manager_listen_stop(m);
m->event_clock_watch = sd_event_source_unref(m->event_clock_watch);
m->clock_watch_fd = safe_close(m->clock_watch_fd);
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index ee3bc99ae0..f7e089fc0c 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -73,7 +73,7 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
format_timestamp(date, sizeof(date), min));
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, min)) < 0)
- log_error("Failed to restore system clock: %m");
+ log_error_errno(errno, "Failed to restore system clock: %m");
}
return 0;
@@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
if (r < 0) {
- log_error("Cannot resolve user name %s: %s", user, strerror(-r));
+ log_error_errno(r, "Cannot resolve user name %s: %m", user);
goto finish;
}
@@ -117,7 +117,7 @@ int main(int argc, char *argv[]) {
r = manager_new(&m);
if (r < 0) {
- log_error("Failed to allocate manager: %s", strerror(-r));
+ log_error_errno(r, "Failed to allocate manager: %m");
goto finish;
}
@@ -129,7 +129,7 @@ int main(int argc, char *argv[]) {
r = manager_parse_config_file(m);
if (r < 0)
- log_warning("Failed to parse configuration file: %s", strerror(-r));
+ log_warning_errno(r, "Failed to parse configuration file: %m");
log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid());
sd_notify(false,
@@ -144,7 +144,7 @@ int main(int argc, char *argv[]) {
r = sd_event_loop(m->event);
if (r < 0) {
- log_error("Failed to run event loop: %s", strerror(-r));
+ log_error_errno(r, "Failed to run event loop: %m");
goto finish;
}
diff --git a/src/timesync/timesyncd.conf.in b/src/timesync/timesyncd.conf.in
index 674a51dbd7..fc3c6c49cf 100644
--- a/src/timesync/timesyncd.conf.in
+++ b/src/timesync/timesyncd.conf.in
@@ -5,6 +5,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
+# You can override the directives in this file by creating files in
+# /etc/systemd/timesyncd.conf.d/*.conf.
+#
# See timesyncd.conf(5) for details
[Time]
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 1e4675f87e..d40bd96f1b 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -39,6 +39,7 @@
#include <glob.h>
#include <fnmatch.h>
#include <sys/capability.h>
+#include <sys/xattr.h>
#include "log.h"
#include "util.h"
@@ -71,6 +72,7 @@ typedef enum ItemType {
CREATE_CHAR_DEVICE = 'c',
CREATE_BLOCK_DEVICE = 'b',
COPY_FILES = 'C',
+ SET_XATTR = 't',
/* These ones take globs */
WRITE_FILE = 'w',
@@ -88,6 +90,7 @@ typedef struct Item {
char *path;
char *argument;
+ char **xattrs;
uid_t uid;
gid_t gid;
mode_t mode;
@@ -117,15 +120,7 @@ static char **arg_include_prefixes = NULL;
static char **arg_exclude_prefixes = NULL;
static char *arg_root = NULL;
-static const char conf_file_dirs[] =
- "/etc/tmpfiles.d\0"
- "/run/tmpfiles.d\0"
- "/usr/local/lib/tmpfiles.d\0"
- "/usr/lib/tmpfiles.d\0"
-#ifdef HAVE_SPLIT_USR
- "/lib/tmpfiles.d\0"
-#endif
- ;
+static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles");
#define MAX_DEPTH 256
@@ -299,9 +294,9 @@ static int dir_cleanup(
/* FUSE, NFS mounts, SELinux might return EACCES */
if (errno == EACCES)
- log_debug("stat(%s/%s) failed: %m", p, dent->d_name);
+ log_debug_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
else
- log_error("stat(%s/%s) failed: %m", p, dent->d_name);
+ log_error_errno(errno, "stat(%s/%s) failed: %m", p, dent->d_name);
r = -errno;
continue;
}
@@ -349,7 +344,7 @@ static int dir_cleanup(
sub_dir = xopendirat(dirfd(d), dent->d_name, O_NOFOLLOW|O_NOATIME);
if (!sub_dir) {
if (errno != ENOENT) {
- log_error("opendir(%s/%s) failed: %m", p, dent->d_name);
+ log_error_errno(errno, "opendir(%s/%s) failed: %m", p, dent->d_name);
r = -errno;
}
@@ -382,7 +377,7 @@ static int dir_cleanup(
if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0) {
if (errno != ENOENT && errno != ENOTEMPTY) {
- log_error("rmdir(%s): %m", sub_path);
+ log_error_errno(errno, "rmdir(%s): %m", sub_path);
r = -errno;
}
}
@@ -430,7 +425,7 @@ static int dir_cleanup(
if (unlinkat(dirfd(d), dent->d_name, 0) < 0) {
if (errno != ENOENT) {
- log_error("unlink(%s): %m", sub_path);
+ log_error_errno(errno, "unlink(%s): %m", sub_path);
r = -errno;
}
}
@@ -446,7 +441,7 @@ finish:
times[1] = ds->st_mtim;
if (futimens(dirfd(d), times) < 0)
- log_error("utimensat(%s): %m", p);
+ log_error_errno(errno, "utimensat(%s): %m", p);
}
return r;
@@ -477,26 +472,85 @@ static int item_set_perms(Item *i, const char *path) {
}
if (!st_valid || m != (st.st_mode & 07777)) {
- if (chmod(path, m) < 0) {
- log_error("chmod(%s) failed: %m", path);
- return -errno;
- }
+ if (chmod(path, m) < 0)
+ return log_error_errno(errno, "chmod(%s) failed: %m", path);
}
}
if ((!st_valid || (i->uid != st.st_uid || i->gid != st.st_gid)) &&
(i->uid_set || i->gid_set))
if (chown(path,
- i->uid_set ? i->uid : (uid_t) -1,
- i->gid_set ? i->gid : (gid_t) -1) < 0) {
+ i->uid_set ? i->uid : UID_INVALID,
+ i->gid_set ? i->gid : GID_INVALID) < 0) {
- log_error("chown(%s) failed: %m", path);
+ log_error_errno(errno, "chown(%s) failed: %m", path);
return -errno;
}
return label_fix(path, false, false);
}
+static int get_xattrs_from_arg(Item *i) {
+ char *xattr;
+ const char *p;
+ int r;
+
+ assert(i);
+
+ if (!i->argument) {
+ log_error("%s: Argument can't be empty!", i->path);
+ return -EBADMSG;
+ }
+ p = i->argument;
+
+ while ((r = unquote_first_word(&p, &xattr, false)) > 0) {
+ _cleanup_free_ char *tmp = NULL, *name = NULL, *value = NULL;
+ r = split_pair(xattr, "=", &name, &value);
+ if (r < 0) {
+ log_warning("Illegal xattr found: \"%s\" - ignoring.", xattr);
+ free(xattr);
+ continue;
+ }
+ free(xattr);
+ if (streq(name, "") || streq(value, "")) {
+ log_warning("Malformed xattr found: \"%s=%s\" - ignoring.", name, value);
+ continue;
+ }
+ tmp = unquote(value, "\"");
+ if (!tmp)
+ return log_oom();
+ free(value);
+ value = cunescape(tmp);
+ if (!value)
+ return log_oom();
+ if (strv_consume_pair(&i->xattrs, name, value) < 0)
+ return log_oom();
+ name = value = NULL;
+ }
+
+ return r;
+}
+
+static int item_set_xattrs(Item *i, const char *path) {
+ char **name, **value;
+
+ assert(i);
+ assert(path);
+
+ if (strv_isempty(i->xattrs))
+ return 0;
+
+ STRV_FOREACH_PAIR(name, value, i->xattrs) {
+ int n;
+ n = strlen(*value);
+ if (lsetxattr(path, *name, *value, n, 0) < 0) {
+ log_error("Setting extended attribute %s=%s on %s failed: %m", *name, *value, path);
+ return -errno;
+ }
+ }
+ return 0;
+}
+
static int write_one_file(Item *i, const char *path) {
_cleanup_close_ int fd = -1;
int flags, r = 0;
@@ -518,7 +572,7 @@ static int write_one_file(Item *i, const char *path) {
if (i->type == WRITE_FILE && errno == ENOENT)
return 0;
- log_error("Failed to create file %s: %m", path);
+ log_error_errno(errno, "Failed to create file %s: %m", path);
return -errno;
}
@@ -542,10 +596,8 @@ static int write_one_file(Item *i, const char *path) {
fd = safe_close(fd);
- if (stat(path, &st) < 0) {
- log_error("stat(%s) failed: %m", path);
- return -errno;
- }
+ if (stat(path, &st) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", path);
if (!S_ISREG(st.st_mode)) {
log_error("%s is not a file.", path);
@@ -556,6 +608,10 @@ static int write_one_file(Item *i, const char *path) {
if (r < 0)
return r;
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
+
return 0;
}
@@ -636,7 +692,7 @@ static int glob_item(Item *i, int (*action)(Item *, const char *)) {
if (errno == 0)
errno = EIO;
- log_error("glob(%s) failed: %m", i->path);
+ log_error_errno(errno, "glob(%s) failed: %m", i->path);
return -errno;
}
@@ -675,20 +731,14 @@ static int create_item(Item *i) {
if (r < 0) {
struct stat a, b;
- if (r != -EEXIST) {
- log_error("Failed to copy files to %s: %s", i->path, strerror(-r));
- return -r;
- }
+ if (r != -EEXIST)
+ return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
- if (stat(i->argument, &a) < 0) {
- log_error("stat(%s) failed: %m", i->argument);
- return -errno;
- }
+ if (stat(i->argument, &a) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
- if (stat(i->path, &b) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &b) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if ((a.st_mode ^ b.st_mode) & S_IFMT) {
log_debug("Can't copy to %s, file exists already and is of different type", i->path);
@@ -718,15 +768,11 @@ static int create_item(Item *i) {
}
if (r < 0) {
- if (r != -EEXIST) {
- log_error("Failed to create directory %s: %s", i->path, strerror(-r));
- return r;
- }
+ if (r != -EEXIST)
+ return log_error_errno(r, "Failed to create directory %s: %m", i->path);
- if (stat(i->path, &st) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &st) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if (!S_ISDIR(st.st_mode)) {
log_debug("%s already exists and is not a directory.", i->path);
@@ -738,6 +784,10 @@ static int create_item(Item *i) {
if (r < 0)
return r;
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
+
break;
case CREATE_FIFO:
@@ -749,15 +799,11 @@ static int create_item(Item *i) {
}
if (r < 0) {
- if (errno != EEXIST) {
- log_error("Failed to create fifo %s: %m", i->path);
- return -errno;
- }
+ if (errno != EEXIST)
+ return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
- if (stat(i->path, &st) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &st) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if (!S_ISFIFO(st.st_mode)) {
@@ -769,10 +815,8 @@ static int create_item(Item *i) {
mac_selinux_create_file_clear();
}
- if (r < 0) {
- log_error("Failed to create fifo %s: %s", i->path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
} else {
log_debug("%s is not a fifo.", i->path);
return 0;
@@ -784,6 +828,10 @@ static int create_item(Item *i) {
if (r < 0)
return r;
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
+
break;
case CREATE_SYMLINK:
@@ -795,10 +843,8 @@ static int create_item(Item *i) {
if (r < 0) {
_cleanup_free_ char *x = NULL;
- if (errno != EEXIST) {
- log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
- return -errno;
- }
+ if (errno != EEXIST)
+ return log_error_errno(errno, "symlink(%s, %s) failed: %m", i->argument, i->path);
r = readlink_malloc(i->path, &x);
if (r < 0 || !streq(i->argument, x)) {
@@ -808,10 +854,8 @@ static int create_item(Item *i) {
r = symlink_atomic(i->argument, i->path);
mac_selinux_create_file_clear();
- if (r < 0) {
- log_error("symlink(%s, %s) failed: %s", i->argument, i->path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "symlink(%s, %s) failed: %m", i->argument, i->path);
} else {
log_debug("%s is not a symlink or does not point to the correct path.", i->path);
return 0;
@@ -819,6 +863,10 @@ static int create_item(Item *i) {
}
}
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
+
break;
case CREATE_BLOCK_DEVICE:
@@ -850,15 +898,11 @@ static int create_item(Item *i) {
return 0;
}
- if (errno != EEXIST) {
- log_error("Failed to create device node %s: %m", i->path);
- return -errno;
- }
+ if (errno != EEXIST)
+ return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
- if (stat(i->path, &st) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (stat(i->path, &st) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if ((st.st_mode & S_IFMT) != file_type) {
@@ -870,10 +914,8 @@ static int create_item(Item *i) {
mac_selinux_create_file_clear();
}
- if (r < 0) {
- log_error("Failed to create device node %s: %s", i->path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create device node %s: %m", i->path);
} else {
log_debug("%s is not a device node.", i->path);
return 0;
@@ -885,6 +927,10 @@ static int create_item(Item *i) {
if (r < 0)
return r;
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
+
break;
}
@@ -901,7 +947,12 @@ static int create_item(Item *i) {
r = glob_item(i, item_set_perms_recursive);
if (r < 0)
return r;
+ break;
+ case SET_XATTR:
+ r = item_set_xattrs(i, i->path);
+ if (r < 0)
+ return r;
break;
}
@@ -931,13 +982,12 @@ static int remove_item_instance(Item *i, const char *instance) {
case RECURSIVE_RELABEL_PATH:
case WRITE_FILE:
case COPY_FILES:
+ case SET_XATTR:
break;
case REMOVE_PATH:
- if (remove(instance) < 0 && errno != ENOENT) {
- log_error("remove(%s): %m", instance);
- return -errno;
- }
+ if (remove(instance) < 0 && errno != ENOENT)
+ return log_error_errno(errno, "remove(%s): %m", instance);
break;
@@ -946,10 +996,8 @@ static int remove_item_instance(Item *i, const char *instance) {
/* FIXME: we probably should use dir_cleanup() here
* instead of rm_rf() so that 'x' is honoured. */
r = rm_rf_dangerous(instance, false, i->type == RECURSIVE_REMOVE_PATH, false);
- if (r < 0 && r != -ENOENT) {
- log_error("rm_rf(%s): %s", instance, strerror(-r));
- return r;
- }
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "rm_rf(%s): %m", instance);
break;
}
@@ -978,6 +1026,7 @@ static int remove_item(Item *i) {
case RECURSIVE_RELABEL_PATH:
case WRITE_FILE:
case COPY_FILES:
+ case SET_XATTR:
break;
case REMOVE_PATH:
@@ -1013,24 +1062,20 @@ static int clean_item_instance(Item *i, const char* instance) {
if (errno == ENOENT || errno == ENOTDIR)
return 0;
- log_error("Failed to open directory %s: %m", i->path);
+ log_error_errno(errno, "Failed to open directory %s: %m", i->path);
return -errno;
}
- if (fstat(dirfd(d), &s) < 0) {
- log_error("stat(%s) failed: %m", i->path);
- return -errno;
- }
+ if (fstat(dirfd(d), &s) < 0)
+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
if (!S_ISDIR(s.st_mode)) {
log_error("%s is not a directory.", i->path);
return -ENOTDIR;
}
- if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) {
- log_error("stat(%s/..) failed: %m", i->path);
- return -errno;
- }
+ 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);
@@ -1105,6 +1150,7 @@ static void item_free(Item *i) {
free(i->path);
free(i->argument);
+ strv_free(i->xattrs);
free(i);
}
@@ -1303,6 +1349,16 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
break;
}
+ case SET_XATTR:
+ if (!i->argument) {
+ log_error("[%s:%u] Set extended attribute requires argument.", fname, line);
+ return -EBADMSG;
+ }
+ r = get_xattrs_from_arg(i);
+ if (r < 0)
+ return r;
+ break;
+
default:
log_error("[%s:%u] Unknown command type '%c'.", fname, line, type);
return -EBADMSG;
@@ -1396,18 +1452,33 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
existing = hashmap_get(h, i->path);
if (existing) {
-
- /* Two identical items are fine */
- if (!item_equal(existing, i))
- log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
-
- return 0;
- }
-
- r = hashmap_put(h, i->path, i);
- if (r < 0) {
- log_error("Failed to insert item %s: %s", i->path, strerror(-r));
- return r;
+ if (i->type == SET_XATTR) {
+ r = strv_extend_strv(&existing->xattrs, i->xattrs);
+ if (r < 0)
+ return log_oom();
+ return 0;
+ } else if (existing->type == SET_XATTR) {
+ r = strv_extend_strv(&i->xattrs, existing->xattrs);
+ if (r < 0)
+ return log_oom();
+ r = hashmap_replace(h, i->path, i);
+ if (r < 0) {
+ log_error("Failed to replace item for %s.", i->path);
+ return r;
+ }
+ item_free(existing);
+ } else {
+ /* Two identical items are fine */
+ if (!item_equal(existing, i))
+ log_warning("Two or more conflicting lines for %s configured, ignoring.", i->path);
+ return 0;
+ }
+ } else {
+ r = hashmap_put(h, i->path, i);
+ if (r < 0) {
+ log_error("Failed to insert item %s: %s", i->path, strerror(-r));
+ return r;
+ }
}
i = NULL; /* avoid cleanup */
@@ -1539,8 +1610,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
if (ignore_enoent && r == -ENOENT)
return 0;
- log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
- return r;
+ return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
}
FOREACH_LINE(line, f, break) {
@@ -1587,7 +1657,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
}
if (ferror(f)) {
- log_error("Failed to read from file %s: %m", fn);
+ log_error_errno(errno, "Failed to read from file %s: %m", fn);
if (r == 0)
r = -EIO;
}
@@ -1637,7 +1707,7 @@ int main(int argc, char *argv[]) {
r = conf_files_list_nulstr(&files, ".conf", arg_root, conf_file_dirs);
if (r < 0) {
- log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
+ log_error_errno(r, "Failed to enumerate tmpfiles.d files: %m");
goto finish;
}
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index e6dc84b440..5fc27f9ae5 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -90,10 +90,8 @@ static int ask_password_plymouth(
return -errno;
r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
- if (r < 0) {
- log_error("Failed to connect to Plymouth: %m");
- return -errno;
- }
+ if (r < 0)
+ return log_error_errno(errno, "Failed to connect to Plymouth: %m");
if (accept_cached) {
packet = strdup("c");
@@ -105,9 +103,9 @@ static int ask_password_plymouth(
if (!packet)
return log_oom();
- k = loop_write(fd, packet, n + 1, true);
- if (k != n + 1)
- return k < 0 ? (int) k : -EIO;
+ r = loop_write(fd, packet, n + 1, true);
+ if (r < 0)
+ return r;
pollfd[POLL_SOCKET].fd = fd;
pollfd[POLL_SOCKET].events = POLLIN;
@@ -167,9 +165,9 @@ static int ask_password_plymouth(
if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
return -ENOMEM;
- k = loop_write(fd, packet, n+1, true);
- if (k != n + 1)
- return k < 0 ? (int) k : -EIO;
+ r = loop_write(fd, packet, n+1, true);
+ if (r < 0)
+ return r;
accept_cached = false;
p = 0;
@@ -338,16 +336,12 @@ static int parse_password(const char *filename, char **wall) {
/* If the query went away, that's OK */
return 0;
- if (r < 0) {
- log_error("Failed to query password: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query password: %m");
socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (socket_fd < 0) {
- log_error("socket(): %m");
- return -errno;
- }
+ if (socket_fd < 0)
+ return log_error_errno(errno, "socket(): %m");
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
@@ -355,7 +349,7 @@ static int parse_password(const char *filename, char **wall) {
r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa,
offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
if (r < 0) {
- log_error("Failed to send: %m");
+ log_error_errno(errno, "Failed to send: %m");
return r;
}
}
@@ -430,7 +424,7 @@ static int show_passwords(void) {
if (errno == ENOENT)
return 0;
- log_error("opendir(/run/systemd/ask-password): %m");
+ log_error_errno(errno, "opendir(/run/systemd/ask-password): %m");
return -errno;
}
@@ -504,7 +498,7 @@ static int watch_passwords(void) {
for (;;) {
r = show_passwords();
if (r < 0)
- log_error("Failed to show password: %s", strerror(-r));
+ log_error_errno(r, "Failed to show password: %m");
if (poll(pollfd, _FD_MAX, -1) < 0) {
if (errno == EINTR)
@@ -642,7 +636,7 @@ int main(int argc, char *argv[]) {
r = show_passwords();
if (r < 0)
- log_error("Error: %s", strerror(-r));
+ log_error_errno(r, "Error: %m");
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/udev/accelerometer/accelerometer.c b/src/udev/accelerometer/accelerometer.c
index 4513bc63c2..dd4b7dc8a2 100644
--- a/src/udev/accelerometer/accelerometer.c
+++ b/src/udev/accelerometer/accelerometer.c
@@ -69,14 +69,6 @@
#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
-_printf_(6,0)
-static void log_fn(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args)
-{
- log_metav(priority, file, line, fn, format, args);
-}
-
typedef enum {
ORIENTATION_UNDEFINED,
ORIENTATION_NORMAL,
@@ -233,8 +225,6 @@ int main (int argc, char** argv)
if (udev == NULL)
return 1;
- udev_set_log_fn(udev, log_fn);
-
/* CLI argument parsing */
while (1) {
int option;
@@ -247,7 +237,6 @@ int main (int argc, char** argv)
case 'd':
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(LOG_DEBUG);
- udev_set_log_priority(udev, LOG_DEBUG);
log_open();
break;
case 'h':
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index bfde57223a..89628c929d 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -405,14 +405,6 @@ out:
return ret;
}
-_printf_(6,0)
-static void log_fn(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args)
-{
- log_metav(priority, file, line, fn, format, args);
-}
-
int main(int argc, char *argv[])
{
struct udev *udev;
@@ -442,8 +434,6 @@ int main(int argc, char *argv[])
if (udev == NULL)
goto exit;
- udev_set_log_fn(udev, log_fn);
-
while (1) {
int option;
@@ -504,7 +494,7 @@ int main(int argc, char *argv[])
} else {
/* If this fails, then try HDIO_GET_IDENTITY */
if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) {
- log_debug("HDIO_GET_IDENTITY failed for '%s': %m", node);
+ log_debug_errno(errno, "HDIO_GET_IDENTITY failed for '%s': %m", node);
rc = 2;
goto close;
}
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 7a4b98726c..48ceb657e0 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -37,14 +37,6 @@
#include "libudev.h"
#include "libudev-private.h"
-_printf_(6,0)
-static void log_fn(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args)
-{
- log_metav(priority, file, line, fn, format, args);
-}
-
/* device info */
static unsigned int cd_cd_rom;
static unsigned int cd_cd_r;
@@ -875,8 +867,6 @@ int main(int argc, char *argv[])
if (udev == NULL)
goto exit;
- udev_set_log_fn(udev, log_fn);
-
while (1) {
int option;
@@ -897,7 +887,6 @@ int main(int argc, char *argv[])
case 'd':
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(LOG_DEBUG);
- udev_set_log_priority(udev, LOG_DEBUG);
log_open();
break;
case 'h':
@@ -922,7 +911,7 @@ int main(int argc, char *argv[])
goto exit;
}
- srand((unsigned int)getpid());
+ initialize_srand();
for (cnt = 20; cnt > 0; cnt--) {
struct timespec duration;
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
index 4ecb6b0d19..90df360eb2 100644
--- a/src/udev/collect/collect.c
+++ b/src/udev/collect/collect.c
@@ -86,12 +86,12 @@ static void usage(void)
*/
static int prepare(char *dir, char *filename)
{
- struct stat statbuf;
char buf[512];
- int fd;
+ int r, fd;
- if (stat(dir, &statbuf) < 0)
- mkdir(dir, 0700);
+ r = mkdir(dir, 0700);
+ if (r < 0 && errno != EEXIST)
+ return -errno;
snprintf(buf, sizeof(buf), "%s/%s", dir, filename);
@@ -254,7 +254,7 @@ static void reject(char *us)
* kickout
*
* Remove all IDs in the internal list which are not part
- * of the list passed via the commandline.
+ * of the list passed via the command line.
*/
static void kickout(void)
{
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index 54cb928091..ec67126b21 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -75,10 +75,8 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
if (*fd < 0) {
r = ethtool_connect(fd);
- if (r < 0) {
- log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@@ -111,10 +109,8 @@ int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex du
if (*fd < 0) {
r = ethtool_connect(fd);
- if (r < 0) {
- log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@@ -171,10 +167,8 @@ int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
if (*fd < 0) {
r = ethtool_connect(fd);
- if (r < 0) {
- log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index f562498f6d..191ab68fa1 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -17,6 +17,7 @@ struct ConfigPerfItem;
%includes
%%
Match.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, match_mac)
+Match.OriginalName, config_parse_ifname, 0, offsetof(link_config, match_name)
Match.Path, config_parse_string, 0, offsetof(link_config, match_path)
Match.Driver, config_parse_string, 0, offsetof(link_config, match_driver)
Match.Type, config_parse_string, 0, offsetof(link_config, match_type)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 25e3cc8dfb..bf24f6a7f7 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -20,6 +20,7 @@
***/
#include <netinet/ether.h>
+#include <linux/netdevice.h>
#include "sd-id128.h"
@@ -95,6 +96,7 @@ static void link_configs_free(link_config_ctx *ctx) {
LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
free(link->filename);
+ free(link->name);
free(link->match_path);
free(link->match_driver);
free(link->match_type);
@@ -174,11 +176,10 @@ static bool enable_name_policy(void) {
size_t l;
r = proc_cmdline(&line);
- if (r < 0)
- log_warning("Failed to read /proc/cmdline, ignoring: %s",
- strerror(-r));
- if (r <= 0)
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
return true;
+ }
FOREACH_WORD_QUOTED(word, l, line, state)
if (strneq(word, "net.ifnames=0", l))
@@ -196,17 +197,15 @@ int link_config_load(link_config_ctx *ctx) {
if (!enable_name_policy()) {
ctx->enable_name_policy = false;
- log_info("Network interface NamePolicy= disabled on kernel commandline, ignoring.");
+ log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
}
/* update timestamp */
paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
- if (r < 0) {
- log_error("failed to enumerate link files: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "failed to enumerate link files: %m");
STRV_FOREACH_BACKWARDS(f, files) {
r = load_link(ctx, *f);
@@ -226,21 +225,45 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
link_config *link;
LIST_FOREACH(links, link, ctx->links) {
- const char* attr_value = udev_device_get_sysattr_value(device, "address");
+ const char* attr_value;
+
+ attr_value = udev_device_get_sysattr_value(device, "address");
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
- link->match_type, NULL, link->match_host,
+ link->match_type, link->match_name, link->match_host,
link->match_virt, link->match_kernel, link->match_arch,
attr_value ? ether_aton(attr_value) : NULL,
udev_device_get_property_value(device, "ID_PATH"),
udev_device_get_driver(udev_device_get_parent(device)),
udev_device_get_property_value(device, "ID_NET_DRIVER"),
udev_device_get_devtype(device),
- NULL)) {
+ udev_device_get_sysname(device))) {
+ if (link->match_name) {
+ unsigned char name_assign_type = NET_NAME_UNKNOWN;
+
+ attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
+ if (attr_value)
+ (void)safe_atou8(attr_value, &name_assign_type);
+
+ if (name_assign_type == NET_NAME_ENUM) {
+ log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
+ link->filename, udev_device_get_sysname(device));
+ *ret = link;
+
+ return 0;
+ } else if (name_assign_type == NET_NAME_RENAMED) {
+ log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
+ link->filename, udev_device_get_sysname(device));
+
+ continue;
+ }
+ }
+
log_debug("Config file %s applies to device %s",
- link->filename,
- udev_device_get_sysname(device));
+ link->filename, udev_device_get_sysname(device));
+
*ret = link;
+
return 0;
}
}
@@ -343,14 +366,14 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024,
config->duplex);
if (r < 0)
- log_warning("Could not set speed or duplex of %s to %u Mbps (%s): %s",
- old_name, config->speed / 1024,
- duplex_to_string(config->duplex), strerror(-r));
+ log_warning_errno(r, "Could not set speed or duplex of %s to %u Mbps (%s): %m",
+ old_name, config->speed / 1024,
+ duplex_to_string(config->duplex));
r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
if (r < 0)
- log_warning("Could not set WakeOnLan of %s to %s: %s",
- old_name, wol_to_string(config->wol), strerror(-r));
+ log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
+ old_name, wol_to_string(config->wol));
ifindex = udev_device_get_ifindex(device);
if (ifindex <= 0) {
@@ -422,11 +445,8 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac,
config->mtu);
- if (r < 0) {
- log_warning("Could not set Alias, MACAddress or MTU on %s: %s",
- old_name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name);
*name = new_name;
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 5f3d4ad142..688f836144 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -22,11 +22,10 @@
#pragma once
#include "ethtool-util.h"
-
-#include "condition-util.h"
-#include "libudev.h"
+#include "condition.h"
#include "util.h"
#include "list.h"
+#include "libudev.h"
typedef struct link_config_ctx link_config_ctx;
typedef struct link_config link_config;
@@ -56,6 +55,7 @@ struct link_config {
char *match_path;
char *match_driver;
char *match_type;
+ char *match_name;
Condition *match_host;
Condition *match_virt;
Condition *match_kernel;
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
index 4d9378a5c0..27adb09d15 100644
--- a/src/udev/scsi_id/scsi_id.c
+++ b/src/udev/scsi_id/scsi_id.c
@@ -63,14 +63,6 @@ static char model_enc_str[256];
static char revision_str[16];
static char type_str[16];
-_printf_(6,0)
-static void log_fn(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args)
-{
- log_metav(priority, file, line, fn, format, args);
-}
-
static void set_type(const char *from, char *to, size_t len)
{
int type_num;
@@ -182,7 +174,7 @@ static int get_file_options(struct udev *udev,
if (errno == ENOENT)
return 1;
else {
- log_error("can't open %s: %m", config_file);
+ log_error_errno(errno, "can't open %s: %m", config_file);
return -1;
}
}
@@ -317,8 +309,8 @@ static void help(void) {
" -f,--config= location of config file\n"
" -p,--page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n"
" -s,--sg-version=3|4 use SGv3 or SGv4\n"
- " -b,--blacklisted threat device as blacklisted\n"
- " -g,--whitelisted threat device as whitelisted\n"
+ " -b,--blacklisted treat device as blacklisted\n"
+ " -g,--whitelisted treat device as whitelisted\n"
" -u,--replace-whitespace replace all whitespace by underscores\n"
" -v,--verbose verbose logging\n"
" --version print version\n"
@@ -390,7 +382,6 @@ static int set_options(struct udev *udev,
case 'v':
log_set_target(LOG_TARGET_CONSOLE);
log_set_max_level(LOG_DEBUG);
- udev_set_log_priority(udev, LOG_DEBUG);
log_open();
break;
@@ -591,8 +582,6 @@ int main(int argc, char **argv)
if (udev == NULL)
goto exit;
- udev_set_log_fn(udev, log_fn);
-
/*
* Get config file options.
*/
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index b3d20a3c2d..dcfff1d4ea 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -361,7 +361,7 @@ resend:
dev_scsi->use_sg = 3;
goto resend;
}
- log_debug("%s: ioctl failed: %m", dev_scsi->kernel);
+ log_debug_errno(errno, "%s: ioctl failed: %m", dev_scsi->kernel);
goto error;
}
@@ -819,12 +819,12 @@ int scsi_std_inquiry(struct udev *udev,
fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
- log_debug("scsi_id: cannot open %s: %m", devname);
+ log_debug_errno(errno, "scsi_id: cannot open %s: %m", devname);
return 1;
}
if (fstat(fd, &statbuf) < 0) {
- log_debug("scsi_id: cannot stat %s: %m", devname);
+ log_debug_errno(errno, "scsi_id: cannot stat %s: %m", devname);
err = 2;
goto out;
}
@@ -861,7 +861,7 @@ int scsi_get_serial(struct udev *udev,
int retval;
memzero(dev_scsi->serial, len);
- srand((unsigned int)getpid());
+ initialize_srand();
for (cnt = 20; cnt > 0; cnt--) {
struct timespec duration;
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index d6b7dbbac0..273b27ddcb 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -62,7 +62,7 @@ static int install_force_release(struct udev_device *dev, const unsigned int *re
log_debug("keyboard: updating force-release list with '%s'", codes);
ret = udev_device_set_sysattr_value(atkbd, "force_release", codes);
if (ret < 0)
- log_error("Error writing force-release attribute: %s", strerror(-ret));
+ log_error_errno(ret, "Error writing force-release attribute: %m");
return ret;
}
@@ -140,7 +140,7 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo
fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0) {
- log_error("Error, opening device '%s': %m", node);
+ log_error_errno(errno, "Error, opening device '%s': %m", node);
return EXIT_FAILURE;
}
@@ -149,7 +149,7 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo
log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
map[i].scan, map[i].scan, map[i].key, map[i].key);
if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0)
- log_error("Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key);
+ log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key);
}
/* install list of force-release codes */
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index 454ee2edff..0949d9fad1 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -31,7 +31,7 @@
#include "udev.h"
-static struct kmod_ctx *ctx;
+static struct kmod_ctx *ctx = NULL;
static int load_module(struct udev *udev, const char *alias) {
struct kmod_list *list = NULL;
@@ -43,18 +43,18 @@ static int load_module(struct udev *udev, const char *alias) {
return err;
if (list == NULL)
- log_debug("no module matches '%s'", alias);
+ log_debug("No module matches '%s'", alias);
kmod_list_foreach(l, list) {
struct kmod_module *mod = kmod_module_get_module(l);
err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
if (err == KMOD_PROBE_APPLY_BLACKLIST)
- log_debug("module '%s' is blacklisted", kmod_module_get_name(mod));
+ log_debug("Module '%s' is blacklisted", kmod_module_get_name(mod));
else if (err == 0)
- log_debug("inserted '%s'", kmod_module_get_name(mod));
+ log_debug("Inserted '%s'", kmod_module_get_name(mod));
else
- log_debug("failed to insert '%s'", kmod_module_get_name(mod));
+ log_debug("Failed to insert '%s'", kmod_module_get_name(mod));
kmod_module_unref(mod);
}
@@ -63,10 +63,8 @@ static int load_module(struct udev *udev, const char *alias) {
return err;
}
-_printf_(6,0)
-static void udev_kmod_log(void *data, int priority, const char *file, int line,
- const char *fn, const char *format, va_list args) {
- udev_main_log(data, priority, file, line, fn, format, args);
+_printf_(6,0) static void udev_kmod_log(void *data, int priority, const char *file, int line, const char *fn, const char *format, va_list args) {
+ log_internalv(priority, 0, file, line, fn, format, args);
}
static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool test) {
@@ -82,7 +80,7 @@ static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool te
}
for (i = 2; argv[i]; i++) {
- log_debug("execute '%s' '%s'", argv[1], argv[i]);
+ log_debug("Execute '%s' '%s'", argv[1], argv[i]);
load_module(udev, argv[i]);
}
@@ -98,7 +96,7 @@ static int builtin_kmod_init(struct udev *udev) {
if (!ctx)
return -ENOMEM;
- log_debug("load module index");
+ log_debug("Load module index");
kmod_set_log_fn(ctx, udev_kmod_log, udev);
kmod_load_resources(ctx);
return 0;
@@ -106,13 +104,13 @@ static int builtin_kmod_init(struct udev *udev) {
/* called on udev shutdown and reload request */
static void builtin_kmod_exit(struct udev *udev) {
- log_debug("unload module index");
+ log_debug("Unload module index");
ctx = kmod_unref(ctx);
}
/* called every couple of seconds during event activity; 'true' if config has changed */
static bool builtin_kmod_validate(struct udev *udev) {
- log_debug("validate module index");
+ log_debug("Validate module index");
if (!ctx)
return false;
return (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK);
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index 14351de6a6..87d10bf78f 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -46,14 +46,14 @@ static int builtin_net_setup_link(struct udev_device *dev, int argc, char **argv
log_debug("No matching link configuration found.");
return EXIT_SUCCESS;
} else {
- log_error("Could not get link config: %s", strerror(-r));
+ log_error_errno(r, "Could not get link config: %m");
return EXIT_FAILURE;
}
}
r = link_config_apply(ctx, link, dev, &name);
if (r < 0) {
- log_error("Could not apply link config to %s: %s", udev_device_get_sysname(dev), strerror(-r));
+ log_error_errno(r, "Could not apply link config to %s: %m", udev_device_get_sysname(dev));
return EXIT_FAILURE;
}
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 0d247f6b5a..d540ba8392 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -118,7 +118,7 @@ out:
return parent;
}
-static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) {
+static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent, char **path) {
struct udev *udev = udev_device_get_udev(parent);
struct udev_device *targetdev;
struct udev_device *target_parent;
@@ -154,6 +154,100 @@ out:
return parent;
}
+static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path)
+{
+ struct udev *udev = udev_device_get_udev(parent);
+ struct udev_device *targetdev;
+ struct udev_device *target_parent;
+ struct udev_device *port;
+ struct udev_device *expander;
+ struct udev_device *target_sasdev = NULL;
+ struct udev_device *expander_sasdev = NULL;
+ struct udev_device *port_sasdev = NULL;
+ const char *sas_address = NULL;
+ const char *phy_id;
+ const char *phy_count;
+ char *lun = NULL;
+
+ targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
+ if (targetdev == NULL)
+ return NULL;
+
+ target_parent = udev_device_get_parent(targetdev);
+ if (target_parent == NULL)
+ return NULL;
+
+ /* Get sas device */
+ target_sasdev = udev_device_new_from_subsystem_sysname(udev,
+ "sas_device", udev_device_get_sysname(target_parent));
+ if (target_sasdev == NULL)
+ return NULL;
+
+ /* The next parent is sas port */
+ port = udev_device_get_parent(target_parent);
+ if (port == NULL) {
+ parent = NULL;
+ goto out;
+ }
+
+ /* Get port device */
+ port_sasdev = udev_device_new_from_subsystem_sysname(udev,
+ "sas_port", udev_device_get_sysname(port));
+
+ phy_count = udev_device_get_sysattr_value(port_sasdev, "num_phys");
+ if (phy_count == NULL) {
+ parent = NULL;
+ goto out;
+ }
+
+ /* Check if we are simple disk */
+ if (strncmp(phy_count, "1", 2) != 0) {
+ parent = handle_scsi_sas_wide_port(parent, path);
+ goto out;
+ }
+
+ /* Get connected phy */
+ phy_id = udev_device_get_sysattr_value(target_sasdev, "phy_identifier");
+ if (phy_id == NULL) {
+ parent = NULL;
+ goto out;
+ }
+
+ /* The port's parent is either hba or expander */
+ expander = udev_device_get_parent(port);
+ if (expander == NULL) {
+ parent = NULL;
+ goto out;
+ }
+
+ /* Get expander device */
+ expander_sasdev = udev_device_new_from_subsystem_sysname(udev,
+ "sas_device", udev_device_get_sysname(expander));
+ if (expander_sasdev != NULL) {
+ /* Get expander's address */
+ sas_address = udev_device_get_sysattr_value(expander_sasdev,
+ "sas_address");
+ if (sas_address == NULL) {
+ parent = NULL;
+ goto out;
+ }
+ }
+
+ format_lun_number(parent, &lun);
+ if (sas_address)
+ path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun);
+ else
+ path_prepend(path, "sas-phy%s-%s", phy_id, lun);
+
+ if (lun)
+ free(lun);
+out:
+ udev_device_unref(target_sasdev);
+ udev_device_unref(expander_sasdev);
+ udev_device_unref(port_sasdev);
+ return parent;
+}
+
static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) {
struct udev *udev = udev_device_get_udev(parent);
struct udev_device *transportdev;
@@ -548,9 +642,9 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
}
/*
- * Do return devices with have an unknown type of parent device, they
- * might produce conflicting IDs below multiple independent parent
- * devices.
+ * Do not return devices with an unknown parent device type. They
+ * might produce conflicting IDs if the parent does not provide a
+ * unique and predictable name.
*/
if (!supported_parent) {
free(path);
@@ -558,9 +652,9 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
}
/*
- * Do not return a have-only a single-parent block devices, some
- * have entire hidden buses behind it, and not create predictable
- * IDs that way.
+ * Do not return block devices without a well-known transport. Some
+ * devices do not expose their buses and do not provide a unique
+ * and predictable name that way.
*/
if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) {
free(path);
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 6964fb5529..591915435a 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -63,7 +63,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_error("Failed to apply ACL on %s: %s", path, strerror(-r));
+ log_error_errno(r, "Failed to apply ACL on %s: %m", path);
goto finish;
}
@@ -77,7 +77,7 @@ finish:
/* Better be safe than sorry and reset ACL */
k = devnode_acl(path, true, false, 0, false, 0);
if (k < 0) {
- log_error("Failed to apply ACL on %s: %s", path, strerror(-k));
+ log_error_errno(k, "Failed to apply ACL on %s: %m", path);
if (r >= 0)
r = k;
}
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 98fd3a9acf..9cece4a85d 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -84,7 +84,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
if (fd < 0) {
uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
if (uctrl->sock < 0) {
- log_error("error getting socket: %m");
+ log_error_errno(errno, "error getting socket: %m");
udev_ctrl_unref(uctrl);
return NULL;
}
@@ -94,7 +94,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
}
r = setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (r < 0)
- log_warning("could not set SO_PASSCRED: %m");
+ log_warning_errno(errno, "could not set SO_PASSCRED: %m");
uctrl->saddr.sun_family = AF_LOCAL;
strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control");
@@ -118,14 +118,14 @@ int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
if (err < 0) {
err = -errno;
- log_error("bind failed: %m");
+ log_error_errno(errno, "bind failed: %m");
return err;
}
err = listen(uctrl->sock, 0);
if (err < 0) {
err = -errno;
- log_error("listen failed: %m");
+ log_error_errno(errno, "listen failed: %m");
return err;
}
@@ -187,14 +187,14 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
if (conn->sock < 0) {
if (errno != EINTR)
- log_error("unable to receive ctrl connection: %m");
+ log_error_errno(errno, "unable to receive ctrl connection: %m");
goto err;
}
/* check peer credential of connection */
r = getpeercred(conn->sock, &ucred);
if (r < 0) {
- log_error("unable to receive credentials of ctrl connection: %s", strerror(-r));
+ log_error_errno(r, "unable to receive credentials of ctrl connection: %m");
goto err;
}
if (ucred.uid > 0) {
@@ -205,7 +205,7 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
/* enable receiving of the sender credentials in the messages */
r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if (r < 0)
- log_warning("could not set SO_PASSCRED: %m");
+ log_warning_errno(errno, "could not set SO_PASSCRED: %m");
udev_ctrl_ref(uctrl);
return conn;
@@ -361,7 +361,7 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
goto err;
} else {
if (!(pfd[0].revents & POLLIN)) {
- log_error("ctrl connection error: %m");
+ log_error_errno(errno, "ctrl connection error: %m");
goto err;
}
}
@@ -374,7 +374,7 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
size = recvmsg(conn->sock, &smsg, 0);
if (size < 0) {
- log_error("unable to receive ctrl message: %m");
+ log_error_errno(errno, "unable to receive ctrl message: %m");
goto err;
}
cmsg = CMSG_FIRSTHDR(&smsg);
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 30a6708901..6b184303d8 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -387,7 +387,7 @@ static int spawn_exec(struct udev_event *event,
if (fd_stderr < 0)
dup2(fd, STDERR_FILENO);
} else
- log_error("open /dev/null failed: %m");
+ log_error_errno(errno, "open /dev/null failed: %m");
/* connect pipes to std{out,err} */
if (fd_stdout >= 0) {
@@ -409,7 +409,7 @@ static int spawn_exec(struct udev_event *event,
execve(argv[0], argv, envp);
/* exec failed */
- log_error("failed to execute '%s' '%s': %m", argv[0], cmd);
+ log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
return -errno;
}
@@ -437,14 +437,14 @@ static void spawn_read(struct udev_event *event,
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
- log_error("error creating epoll fd: %m");
+ log_error_errno(errno, "error creating epoll fd: %m");
return;
}
if (fd_stdout >= 0) {
r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe);
if (r < 0) {
- log_error("fail to add stdout fd to epoll: %m");
+ log_error_errno(errno, "fail to add stdout fd to epoll: %m");
return;
}
}
@@ -452,7 +452,7 @@ static void spawn_read(struct udev_event *event,
if (fd_stderr >= 0) {
r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe);
if (r < 0) {
- log_error("fail to add stderr fd to epoll: %m");
+ log_error_errno(errno, "fail to add stderr fd to epoll: %m");
return;
}
}
@@ -481,7 +481,7 @@ static void spawn_read(struct udev_event *event,
if (fdcount < 0) {
if (errno == EINTR)
continue;
- log_error("failed to poll: %m");
+ log_error_errno(errno, "failed to poll: %m");
return;
} else if (fdcount == 0) {
log_error("timeout '%s'", cmd);
@@ -527,7 +527,7 @@ static void spawn_read(struct udev_event *event,
} else if (ev[i].events & EPOLLHUP) {
r = epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL);
if (r < 0) {
- log_error("failed to remove fd from epoll: %m");
+ log_error_errno(errno, "failed to remove fd from epoll: %m");
return;
}
*fd = -1;
@@ -576,7 +576,7 @@ static int spawn_wait(struct udev_event *event,
if (errno == EINTR)
continue;
err = -errno;
- log_error("failed to poll: %m");
+ log_error_errno(errno, "failed to poll: %m");
goto out;
}
if (fdcount == 0) {
@@ -587,7 +587,7 @@ static int spawn_wait(struct udev_event *event,
if (errno == EINTR)
continue;
err = -errno;
- log_error("failed to poll: %m");
+ log_error_errno(errno, "failed to poll: %m");
goto out;
}
if (fdcount == 0) {
@@ -676,7 +676,6 @@ int udev_event_spawn(struct udev_event *event,
usec_t timeout_warn_usec,
const char *cmd, char **envp, const sigset_t *sigmask,
char *result, size_t ressize) {
- struct udev *udev = event->udev;
int outpipe[2] = {-1, -1};
int errpipe[2] = {-1, -1};
pid_t pid;
@@ -689,17 +688,17 @@ int udev_event_spawn(struct udev_event *event,
udev_build_argv(event->udev, arg, NULL, argv);
/* pipes from child to parent */
- if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) {
+ if (result != NULL || log_get_max_level() >= LOG_INFO) {
if (pipe2(outpipe, O_NONBLOCK) != 0) {
err = -errno;
- log_error("pipe failed: %m");
+ log_error_errno(errno, "pipe failed: %m");
goto out;
}
}
- if (udev_get_log_priority(udev) >= LOG_INFO) {
+ if (log_get_max_level() >= LOG_INFO) {
if (pipe2(errpipe, O_NONBLOCK) != 0) {
err = -errno;
- log_error("pipe failed: %m");
+ log_error_errno(errno, "pipe failed: %m");
goto out;
}
}
@@ -730,7 +729,7 @@ int udev_event_spawn(struct udev_event *event,
_exit(2 );
case -1:
- log_error("fork of '%s' failed: %m", cmd);
+ log_error_errno(errno, "fork of '%s' failed: %m", cmd);
err = -1;
goto out;
default:
@@ -776,21 +775,19 @@ static int rename_netif(struct udev_event *event) {
strscpy(name, IFNAMSIZ, event->name);
r = rtnl_set_link_name(&event->rtnl, udev_device_get_ifindex(dev), name);
- if (r < 0) {
- log_error("error changing net interface name '%s' to '%s': %s",
- oldname, name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Error changing net interface name '%s' to '%s': %m", oldname, name);
- log_debug("renamed network interface '%s' to '%s'\n", oldname, name);
+ log_debug("renamed network interface '%s' to '%s'", oldname, name);
return 0;
}
void udev_event_execute_rules(struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- struct udev_rules *rules, const sigset_t *sigmask) {
+ usec_t timeout_usec, usec_t timeout_warn_usec,
+ struct udev_list *properties_list,
+ struct udev_rules *rules,
+ const sigset_t *sigmask) {
struct udev_device *dev = event->dev;
if (udev_device_get_subsystem(dev) == NULL)
@@ -804,7 +801,10 @@ void udev_event_execute_rules(struct udev_event *event,
if (major(udev_device_get_devnum(dev)) != 0)
udev_watch_end(event->udev, dev);
- udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, sigmask);
+ udev_rules_apply_to_event(rules, event,
+ timeout_usec, timeout_warn_usec,
+ properties_list,
+ sigmask);
if (major(udev_device_get_devnum(dev)) != 0)
udev_node_remove(dev);
@@ -838,7 +838,10 @@ void udev_event_execute_rules(struct udev_event *event,
}
}
- udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, sigmask);
+ udev_rules_apply_to_event(rules, event,
+ timeout_usec, timeout_warn_usec,
+ properties_list,
+ sigmask);
/* rename a new network interface, if needed */
if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index 030e459198..c30a428ea1 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -112,12 +112,12 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s
mac_selinux_create_file_clear();
} while (err == -ENOENT);
if (err != 0) {
- log_error("symlink '%s' '%s' failed: %m", target, slink_tmp);
+ log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp);
goto exit;
}
err = rename(slink_tmp, slink);
if (err != 0) {
- log_error("rename '%s' '%s' failed: %m", slink_tmp, slink);
+ log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink);
unlink(slink_tmp);
}
exit:
@@ -264,7 +264,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
if (lstat(devnode, &stats) != 0) {
err = -errno;
- log_debug("can not stat() node '%s' (%m)", devnode);
+ log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
goto out;
}
@@ -283,10 +283,10 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid);
err = chmod(devnode, mode);
if (err < 0)
- log_warning("setting mode of %s to %#o failed: %m", devnode, mode);
+ log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode);
err = chown(devnode, uid, gid);
if (err < 0)
- log_warning("setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid);
+ log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid);
} else {
log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid);
}
@@ -304,7 +304,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
r = mac_selinux_apply(devnode, label);
if (r < 0)
- log_error("SECLABEL: failed to set SELinux label '%s': %s", label, strerror(-r));
+ log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label);
else
log_debug("SECLABEL: set SELinux label '%s'", label);
@@ -313,7 +313,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
r = mac_smack_apply(devnode, label);
if (r < 0)
- log_error("SECLABEL: failed to set SMACK label '%s': %s", label, strerror(-r));
+ log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label);
else
log_debug("SECLABEL: set SMACK label '%s'", label);
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 3bc25f7c26..c9a0197534 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -474,9 +474,9 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) {
r = get_user_creds(&owner, &uid, NULL, NULL, NULL);
if (r < 0) {
if (r == -ENOENT || r == -ESRCH)
- udev_err(rules->udev, "specified user '%s' unknown\n", owner);
+ log_error("specified user '%s' unknown", owner);
else
- udev_err(rules->udev, "error resolving user '%s': %s\n", owner, strerror(-r));
+ log_error_errno(r, "error resolving user '%s': %m", owner);
}
/* grow buffer if needed */
@@ -521,9 +521,9 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) {
r = get_group_creds(&group, &gid);
if (r < 0) {
if (r == -ENOENT || r == -ESRCH)
- udev_err(rules->udev, "specified group '%s' unknown\n", group);
+ log_error("specified group '%s' unknown", group);
else
- udev_err(rules->udev, "error resolving group '%s': %s\n", group, strerror(-r));
+ log_error_errno(r, "error resolving group '%s': %m", group);
}
/* grow buffer if needed */
@@ -1042,11 +1042,11 @@ static int add_rule(struct udev_rules *rules, char *line,
const char *filename, unsigned int filename_off, unsigned int lineno) {
char *linepos;
const char *attr;
- struct rule_tmp rule_tmp;
+ struct rule_tmp rule_tmp = {
+ .rules = rules,
+ .rule.type = TK_RULE,
+ };
- memzero(&rule_tmp, sizeof(struct rule_tmp));
- rule_tmp.rules = rules;
- rule_tmp.rule.type = TK_RULE;
/* the offset in the rule is limited to unsigned short */
if (filename_off < USHRT_MAX)
rule_tmp.rule.rule.filename_off = filename_off;
@@ -1067,14 +1067,14 @@ static int add_rule(struct udev_rules *rules, char *line,
/* If we aren't at the end of the line, this is a parsing error.
* Make a best effort to describe where the problem is. */
- if (*linepos != '\n') {
- char buf[2] = {linepos[1]};
+ if (!strchr(NEWLINE, *linepos)) {
+ char buf[2] = {*linepos};
_cleanup_free_ char *tmp;
tmp = cescape(buf);
- log_error("invalid key/value pair in file %s on line %u, starting at character %tu ('%s')\n",
+ log_error("invalid key/value pair in file %s on line %u, starting at character %tu ('%s')",
filename, lineno, linepos - line + 1, tmp);
- if (linepos[1] == '#')
+ if (*linepos == '#')
log_error("hint: comments can only start at beginning of line");
}
break;
@@ -1685,7 +1685,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) {
r = conf_files_list_strv(&files, ".rules", NULL, rules_dirs);
if (r < 0) {
- log_error("failed to enumerate rules files: %s", strerror(-r));
+ log_error_errno(r, "failed to enumerate rules files: %m");
return udev_rules_unref(rules);
}
@@ -1876,6 +1876,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
struct udev_event *event,
usec_t timeout_usec,
usec_t timeout_warn_usec,
+ struct udev_list *properties_list,
const sigset_t *sigmask) {
struct token *cur;
struct token *rule;
@@ -1941,7 +1942,18 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
const char *value;
value = udev_device_get_property_value(event->dev, key_name);
- if (value == NULL)
+
+ /* check global properties */
+ if (!value && properties_list) {
+ struct udev_list_entry *list_entry;
+
+ list_entry = udev_list_get_entry(properties_list);
+ list_entry = udev_list_entry_get_by_name(list_entry, key_name);
+ if (list_entry != NULL)
+ value = udev_list_entry_get_value(list_entry);
+ }
+
+ if (!value)
value = "";
if (match_key(rules, cur, value))
goto nomatch;
@@ -2265,9 +2277,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL);
if (r < 0) {
if (r == -ENOENT || r == -ESRCH)
- udev_err(event->udev, "specified user '%s' unknown\n", owner);
+ log_error("specified user '%s' unknown", owner);
else
- udev_err(event->udev, "error resolving user '%s': %s\n", owner, strerror(-r));
+ log_error_errno(r, "error resolving user '%s': %m", owner);
event->uid = 0;
}
@@ -2291,9 +2303,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
r = get_group_creds(&gr, &event->gid);
if (r < 0) {
if (r == -ENOENT || r == -ESRCH)
- udev_err(event->udev, "specified group '%s' unknown\n", group);
+ log_error("specified group '%s' unknown", group);
else
- udev_err(event->udev, "error resolving group '%s': %s\n", group, strerror(-r));
+ log_error_errno(r, "error resolving group '%s': %m", group);
event->gid = 0;
}
@@ -2523,10 +2535,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
f = fopen(attr, "we");
if (f != NULL) {
if (fprintf(f, "%s", value) <= 0)
- log_error("error writing ATTR{%s}: %m", attr);
+ log_error_errno(errno, "error writing ATTR{%s}: %m", attr);
fclose(f);
} else {
- log_error("error opening ATTR{%s} for writing: %m", attr);
+ log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr);
}
break;
}
@@ -2640,19 +2652,17 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) {
strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL);
r = mkdir_p(tags_dir, 0755);
- if (r < 0) {
- log_error("failed to create %s: %s", tags_dir, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "failed to create %s: %m", tags_dir);
unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/.");
strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL);
r = symlink(device_node, tag_symlink);
- if (r < 0 && errno != EEXIST) {
- log_error("failed to create symlink %s -> %s: %m", tag_symlink, device_node);
- return -errno;
- } else
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "failed to create symlink %s -> %s: %m",
+ tag_symlink, device_node);
+ else
r = 0;
}
}
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
index 061bd05875..6ba8674d77 100644
--- a/src/udev/udev-watch.c
+++ b/src/udev/udev-watch.c
@@ -39,7 +39,7 @@ static int inotify_fd = -1;
int udev_watch_init(struct udev *udev) {
inotify_fd = inotify_init1(IN_CLOEXEC);
if (inotify_fd < 0)
- log_error("inotify_init failed: %m");
+ log_error_errno(errno, "inotify_init failed: %m");
return inotify_fd;
}
@@ -56,7 +56,7 @@ void udev_watch_restore(struct udev *udev) {
dir = opendir("/run/udev/watch.old");
if (dir == NULL) {
- log_error("unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m");
+ log_error_errno(errno, "unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m");
return;
}
@@ -88,7 +88,7 @@ unlink:
rmdir("/run/udev/watch.old");
} else if (errno != ENOENT) {
- log_error("unable to move watches dir /run/udev/watch; old watches will not be restored: %m");
+ log_error_errno(errno, "unable to move watches dir /run/udev/watch; old watches will not be restored: %m");
}
}
@@ -103,7 +103,7 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev) {
log_debug("adding watch on '%s'", udev_device_get_devnode(dev));
wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
if (wd < 0) {
- log_error("inotify_add_watch(%d, %s, %o) failed: %m",
+ log_error_errno(errno, "inotify_add_watch(%d, %s, %o) failed: %m",
inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
return;
}
@@ -113,7 +113,7 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev) {
unlink(filename);
r = symlink(udev_device_get_id_filename(dev), filename);
if (r < 0)
- log_error("Failed to create symlink %s: %m", filename);
+ log_error_errno(errno, "Failed to create symlink %s: %m", filename);
udev_device_set_watch_handle(dev, wd);
}
diff --git a/src/udev/udev.h b/src/udev/udev.h
index 765ba9e86d..dece6eccab 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -73,7 +73,9 @@ struct udev_rules;
struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names);
struct udev_rules *udev_rules_unref(struct udev_rules *rules);
bool udev_rules_check_timestamp(struct udev_rules *rules);
-int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec,
+int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
+ usec_t timeout_usec, usec_t timeout_warn_usec,
+ struct udev_list *properties_list,
const sigset_t *sigmask);
int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
@@ -88,8 +90,11 @@ int udev_event_spawn(struct udev_event *event,
usec_t timeout_warn_usec,
const char *cmd, char **envp, const sigset_t *sigmask,
char *result, size_t ressize);
-void udev_event_execute_rules(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_rules *rules, const sigset_t *sigset);
+void udev_event_execute_rules(struct udev_event *event,
+ usec_t timeout_usec, usec_t timeout_warn_usec,
+ struct udev_list *properties_list,
+ struct udev_rules *rules,
+ const sigset_t *sigset);
void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigset);
int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
@@ -197,11 +202,6 @@ int udev_builtin_add_property(struct udev_device *dev, bool test, const char *ke
int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const char *modalias,
const char *filter, bool test);
-/* udev logging */
-void udev_main_log(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args) _printf_(6, 0);
-
/* udevadm commands */
struct udevadm_cmd {
const char *name;
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
index 3ca755e2ed..a5870d1cee 100644
--- a/src/udev/udevadm-hwdb.c
+++ b/src/udev/udevadm-hwdb.c
@@ -428,6 +428,10 @@ static int insert_data(struct trie *trie, struct udev_list *match_list,
value[0] = '\0';
value++;
+ /* libudev requires properties to start with a space */
+ while (isblank(line[0]) && isblank(line[1]))
+ line++;
+
if (line[0] == '\0' || value[0] == '\0') {
log_error("Error, empty key or value '%s' in '%s':", line, filename);
return -EINVAL;
@@ -618,7 +622,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
if (err < 0) {
- log_error("failed to enumerate hwdb files: %s", strerror(-err));
+ log_error_errno(err, "failed to enumerate hwdb files: %m");
rc = EXIT_FAILURE;
goto out;
}
@@ -652,7 +656,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
mkdir_parents(hwdb_bin, 0755);
err = trie_store(trie, hwdb_bin);
if (err < 0) {
- log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err));
+ log_error_errno(err, "Failure writing database %s: %m", hwdb_bin);
rc = EXIT_FAILURE;
}
}
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index 22d0826011..a56f159543 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -31,6 +31,7 @@
#include "udev.h"
#include "udev-util.h"
+#include "udevadm-util.h"
static bool skip_attribute(const char *name) {
static const char* const skip[] = {
@@ -257,35 +258,6 @@ static void cleanup_db(struct udev *udev) {
}
}
-static struct udev_device *find_device(struct udev *udev, const char *id, const char *prefix) {
- char name[UTIL_PATH_SIZE];
-
- if (prefix && !startswith(id, prefix)) {
- strscpyl(name, sizeof(name), prefix, id, NULL);
- id = name;
- }
-
- if (startswith(id, "/dev/")) {
- struct stat statbuf;
- char type;
-
- if (stat(id, &statbuf) < 0)
- return NULL;
-
- if (S_ISBLK(statbuf.st_mode))
- type = 'b';
- else if (S_ISCHR(statbuf.st_mode))
- type = 'c';
- else
- return NULL;
-
- return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
- } else if (startswith(id, "/sys/"))
- return udev_device_new_from_syspath(udev, id);
- else
- return NULL;
-}
-
static int uinfo(struct udev *udev, int argc, char *argv[]) {
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
bool root = 0;
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index e776fb99dc..1a5f516ddc 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -155,7 +155,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
- log_error("error creating epoll fd: %m");
+ log_error_errno(errno, "error creating epoll fd: %m");
return 1;
}
@@ -195,7 +195,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
ep_udev.events = EPOLLIN;
ep_udev.data.fd = fd_udev;
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
- log_error("fail to add fd to epoll: %m");
+ log_error_errno(errno, "fail to add fd to epoll: %m");
return 2;
}
@@ -229,7 +229,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
ep_kernel.events = EPOLLIN;
ep_kernel.data.fd = fd_kernel;
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_kernel, &ep_kernel) < 0) {
- log_error("fail to add fd to epoll: %m");
+ log_error_errno(errno, "fail to add fd to epoll: %m");
return 5;
}
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index 4738b611c3..d9d61b42d5 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -136,7 +136,11 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
goto out;
}
- udev_event_execute_rules(event, 60 * USEC_PER_SEC, 20 * USEC_PER_SEC, rules, &sigmask_orig);
+ udev_event_execute_rules(event,
+ 60 * USEC_PER_SEC, 20 * USEC_PER_SEC,
+ NULL,
+ rules,
+ &sigmask_orig);
udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev))
printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index a52d1b5ad5..4308466b84 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -32,6 +32,7 @@
#include "udev.h"
#include "udev-util.h"
+#include "udevadm-util.h"
#include "util.h"
static int verbose;
@@ -53,7 +54,7 @@ static void exec_list(struct udev_enumerate *udev_enumerate, const char *action)
if (fd < 0)
continue;
if (write(fd, action, strlen(action)) < 0)
- log_debug("error writing '%s' to '%s': %m", action, filename);
+ log_debug_errno(errno, "error writing '%s' to '%s': %m", action, filename);
close(fd);
}
}
@@ -85,26 +86,32 @@ static void help(void) {
" -A,--attr-nomatch=<file[=<value>]> exclude devices with a matching attribute\n"
" -p,--property-match=<key>=<value> trigger devices with a matching property\n"
" -g,--tag-match=<key>=<value> trigger devices with a matching property\n"
- " -y,--sysname-match=<name> trigger devices with a matching name\n"
+ " -y,--sysname-match=<name> trigger devices with this /sys path\n"
+ " --name-match=<name> trigger devices with this /dev name\n"
" -b,--parent-match=<name> trigger devices with that parent device\n"
" -h,--help\n\n");
}
static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
+ enum {
+ ARG_NAME = 0x100,
+ };
+
static const struct option options[] = {
- { "verbose", no_argument, NULL, 'v' },
- { "dry-run", no_argument, NULL, 'n' },
- { "type", required_argument, NULL, 't' },
- { "action", required_argument, NULL, 'c' },
- { "subsystem-match", required_argument, NULL, 's' },
- { "subsystem-nomatch", required_argument, NULL, 'S' },
- { "attr-match", required_argument, NULL, 'a' },
- { "attr-nomatch", required_argument, NULL, 'A' },
- { "property-match", required_argument, NULL, 'p' },
- { "tag-match", required_argument, NULL, 'g' },
- { "sysname-match", required_argument, NULL, 'y' },
- { "parent-match", required_argument, NULL, 'b' },
- { "help", no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "dry-run", no_argument, NULL, 'n' },
+ { "type", required_argument, NULL, 't' },
+ { "action", required_argument, NULL, 'c' },
+ { "subsystem-match", required_argument, NULL, 's' },
+ { "subsystem-nomatch", required_argument, NULL, 'S' },
+ { "attr-match", required_argument, NULL, 'a' },
+ { "attr-nomatch", required_argument, NULL, 'A' },
+ { "property-match", required_argument, NULL, 'p' },
+ { "tag-match", required_argument, NULL, 'g' },
+ { "sysname-match", required_argument, NULL, 'y' },
+ { "name-match", required_argument, NULL, ARG_NAME },
+ { "parent-match", required_argument, NULL, 'b' },
+ { "help", no_argument, NULL, 'h' },
{}
};
enum {
@@ -174,25 +181,31 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
udev_enumerate_add_match_sysname(udev_enumerate, optarg);
break;
case 'b': {
- char path[UTIL_PATH_SIZE];
- struct udev_device *dev;
-
- /* add sys dir if needed */
- if (!startswith(optarg, "/sys"))
- strscpyl(path, sizeof(path), "/sys", optarg, NULL);
- else
- strscpy(path, sizeof(path), optarg);
- util_remove_trailing_chars(path, '/');
- dev = udev_device_new_from_syspath(udev, path);
+ _cleanup_udev_device_unref_ struct udev_device *dev;
+
+ dev = find_device(udev, optarg, "/sys");
+ if (dev == NULL) {
+ log_error("unable to open the device '%s'", optarg);
+ return 2;
+ }
+
+ udev_enumerate_add_match_parent(udev_enumerate, dev);
+ break;
+ }
+
+ case ARG_NAME: {
+ _cleanup_udev_device_unref_ struct udev_device *dev;
+
+ dev = find_device(udev, optarg, "/dev/");
if (dev == NULL) {
log_error("unable to open the device '%s'", optarg);
return 2;
}
+
udev_enumerate_add_match_parent(udev_enumerate, dev);
- /* drop reference immediately, enumerate pins the device as long as needed */
- udev_device_unref(dev);
break;
}
+
case 'h':
help();
return 0;
@@ -203,9 +216,16 @@ static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
}
}
- if (optind < argc) {
- fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]);
- return 1;
+ for (; optind < argc; optind++) {
+ _cleanup_udev_device_unref_ struct udev_device *dev;
+
+ dev = find_device(udev, argv[optind], NULL);
+ if (dev == NULL) {
+ log_error("unable to open the device '%s'", argv[optind]);
+ return 2;
+ }
+
+ udev_enumerate_add_match_parent(udev_enumerate, dev);
}
switch (device_type) {
diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c
new file mode 100644
index 0000000000..37e80c31df
--- /dev/null
+++ b/src/udev/udevadm-util.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "udevadm-util.h"
+
+struct udev_device *find_device(struct udev *udev,
+ const char *id,
+ const char *prefix) {
+
+ assert(udev);
+ assert(id);
+
+ if (prefix && !startswith(id, prefix))
+ id = strappenda(prefix, id);
+
+ if (startswith(id, "/dev/")) {
+ struct stat statbuf;
+ char type;
+
+ if (stat(id, &statbuf) < 0)
+ return NULL;
+
+ if (S_ISBLK(statbuf.st_mode))
+ type = 'b';
+ else if (S_ISCHR(statbuf.st_mode))
+ type = 'c';
+ else
+ return NULL;
+
+ return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
+ } else if (startswith(id, "/sys/"))
+ return udev_device_new_from_syspath(udev, id);
+ else
+ return NULL;
+}
diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h
new file mode 100644
index 0000000000..dba651fddb
--- /dev/null
+++ b/src/udev/udevadm-util.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "udev.h"
+
+struct udev_device *find_device(struct udev *udev,
+ const char *id,
+ const char *prefix);
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index 7026c50d2b..d9bd69742c 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -26,12 +26,6 @@
#include "udev.h"
-void udev_main_log(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args) {
- log_metav(priority, file, line, fn, format, args);
-}
-
static int adm_version(struct udev *udev, int argc, char *argv[]) {
printf("%s\n", VERSION);
return 0;
@@ -98,7 +92,6 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- udev_set_log_fn(udev, udev_main_log);
mac_selinux_init("/dev");
while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
@@ -106,7 +99,6 @@ int main(int argc, char *argv[]) {
case 'd':
log_set_max_level(LOG_DEBUG);
- udev_set_log_priority(udev, LOG_DEBUG);
break;
case 'h':
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 2e6c71352f..8bec03e77f 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -54,12 +54,6 @@
#include "dev-setup.h"
#include "fileio.h"
-void udev_main_log(struct udev *udev, int priority,
- const char *file, int line, const char *fn,
- const char *format, va_list args) {
- log_metav(priority, file, line, fn, format, args);
-}
-
static struct udev_rules *rules;
static struct udev_ctrl *udev_ctrl;
static struct udev_monitor *monitor;
@@ -81,6 +75,7 @@ static sigset_t sigmask_orig;
static UDEV_LIST(event_list);
static UDEV_LIST(worker_list);
static char *udev_cgroup;
+static struct udev_list properties_list;
static bool udev_exit;
enum event_state {
@@ -225,14 +220,14 @@ static void worker_new(struct event *event) {
sigfillset(&mask);
fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (fd_signal < 0) {
- log_error("error creating signalfd %m");
+ log_error_errno(errno, "error creating signalfd %m");
rc = 2;
goto out;
}
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
- log_error("error creating epoll fd: %m");
+ log_error_errno(errno, "error creating epoll fd: %m");
rc = 3;
goto out;
}
@@ -248,7 +243,7 @@ static void worker_new(struct event *event) {
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
- log_error("fail to add fds to epoll: %m");
+ log_error_errno(errno, "fail to add fds to epoll: %m");
rc = 4;
goto out;
}
@@ -298,7 +293,7 @@ static void worker_new(struct event *event) {
if (d) {
fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
- log_debug("Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
+ log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
err = -EWOULDBLOCK;
fd_lock = safe_close(fd_lock);
goto skip;
@@ -310,12 +305,19 @@ static void worker_new(struct event *event) {
udev_event->rtnl = rtnl;
/* apply rules, create node, symlinks */
- udev_event_execute_rules(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec, rules, &sigmask_orig);
+ udev_event_execute_rules(udev_event,
+ arg_event_timeout_usec, arg_event_timeout_warn_usec,
+ &properties_list,
+ rules,
+ &sigmask_orig);
- udev_event_execute_run(udev_event, arg_event_timeout_usec, arg_event_timeout_warn_usec, &sigmask_orig);
+ udev_event_execute_run(udev_event,
+ arg_event_timeout_usec, arg_event_timeout_warn_usec,
+ &sigmask_orig);
- /* in case rtnl was initialized */
- rtnl = sd_rtnl_ref(udev_event->rtnl);
+ if (udev_event->rtnl)
+ /* in case rtnl was initialized */
+ rtnl = sd_rtnl_ref(udev_event->rtnl);
/* apply/restore inotify watch */
if (udev_event->inotify_watch) {
@@ -357,7 +359,7 @@ skip:
if (fdcount < 0) {
if (errno == EINTR)
continue;
- log_error("failed to poll: %m");
+ log_error_errno(errno, "failed to poll: %m");
goto out;
}
@@ -397,7 +399,7 @@ out:
udev_monitor_unref(worker_monitor);
event->state = EVENT_QUEUED;
free(worker);
- log_error("fork of child failed: %m");
+ log_error_errno(errno, "fork of child failed: %m");
break;
default:
/* close monitor, but keep address around */
@@ -428,7 +430,7 @@ static void event_run(struct event *event) {
count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
if (count < 0) {
- log_error("worker [%u] did not accept message %zi (%m), kill it", worker->pid, count);
+ log_error_errno(errno, "worker [%u] did not accept message %zi (%m), kill it", worker->pid, count);
kill(worker->pid, SIGKILL);
worker->state = WORKER_KILLED;
continue;
@@ -644,7 +646,6 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
if (i >= 0) {
log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
log_set_max_level(i);
- udev_set_log_priority(udev, i);
worker_kill(udev);
}
@@ -677,10 +678,10 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) {
val = &val[1];
if (val[0] == '\0') {
log_debug("udevd message (ENV) received, unset '%s'", key);
- udev_add_property(udev, key, NULL);
+ udev_list_entry_add(&properties_list, key, NULL);
} else {
log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
- udev_add_property(udev, key, val);
+ udev_list_entry_add(&properties_list, key, val);
}
} else {
log_error("wrong key format '%s'", key);
@@ -815,41 +816,34 @@ static int synthesize_change(struct udev_device *dev) {
}
static int handle_inotify(struct udev *udev) {
- int nbytes, pos;
- char *buf;
- struct inotify_event *ev;
- int r;
+ uint8_t buffer[INOTIFY_EVENT_MAX] _alignas_(struct inotify_event);
+ struct inotify_event *e;
+ ssize_t l;
- r = ioctl(fd_inotify, FIONREAD, &nbytes);
- if (r < 0 || nbytes <= 0)
- return -errno;
+ l = read(fd_inotify, buffer, sizeof(buffer));
+ if (l < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
- buf = malloc(nbytes);
- if (!buf) {
- log_error("error getting buffer for inotify");
- return -ENOMEM;
+ return log_error_errno(errno, "Failed to read inotify fd: %m");
}
- nbytes = read(fd_inotify, buf, nbytes);
-
- for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) {
+ FOREACH_INOTIFY_EVENT(e, buffer, l) {
struct udev_device *dev;
- ev = (struct inotify_event *)(buf + pos);
- dev = udev_watch_lookup(udev, ev->wd);
+ dev = udev_watch_lookup(udev, e->wd);
if (!dev)
continue;
- log_debug("inotify event: %x for %s", ev->mask, udev_device_get_devnode(dev));
- if (ev->mask & IN_CLOSE_WRITE)
+ log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev));
+ if (e->mask & IN_CLOSE_WRITE)
synthesize_change(dev);
- else if (ev->mask & IN_IGNORED)
+ else if (e->mask & IN_IGNORED)
udev_watch_end(udev, dev);
udev_device_unref(dev);
}
- free(buf);
return 0;
}
@@ -949,7 +943,7 @@ static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) {
}
/*
- * read the kernel commandline, in case we need to get into debug mode
+ * read the kernel command line, in case we need to get into debug mode
* udev.log-priority=<level> syslog priority
* udev.children-max=<number of workers> events are fully serialized if set to 1
* udev.exec-delay=<number of seconds> delay execution of every executed program
@@ -961,13 +955,13 @@ static void kernel_cmdline_options(struct udev *udev) {
int r;
r = proc_cmdline(&line);
- if (r < 0)
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- if (r <= 0)
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m");
return;
+ }
FOREACH_WORD_QUOTED(word, l, line, state) {
- char *s, *opt;
+ char *s, *opt, *value;
s = strndup(word, l);
if (!s)
@@ -979,24 +973,23 @@ static void kernel_cmdline_options(struct udev *udev) {
else
opt = s;
- if (startswith(opt, "udev.log-priority=")) {
+ if ((value = startswith(opt, "udev.log-priority="))) {
int prio;
- prio = util_log_priority(opt + 18);
+ prio = util_log_priority(value);
log_set_max_level(prio);
- udev_set_log_priority(udev, prio);
- } else if (startswith(opt, "udev.children-max=")) {
- r = safe_atoi(opt + 18, &arg_children_max);
+ } else if ((value = startswith(opt, "udev.children-max="))) {
+ r = safe_atoi(value, &arg_children_max);
if (r < 0)
- log_warning("Invalid udev.children-max ignored: %s", opt + 18);
- } else if (startswith(opt, "udev.exec-delay=")) {
- r = safe_atoi(opt + 16, &arg_exec_delay);
+ log_warning("Invalid udev.children-max ignored: %s", value);
+ } else if ((value = startswith(opt, "udev.exec-delay="))) {
+ r = safe_atoi(value, &arg_exec_delay);
if (r < 0)
- log_warning("Invalid udev.exec-delay ignored: %s", opt + 16);
- } else if (startswith(opt, "udev.event-timeout=")) {
- r = safe_atou64(opt + 16, &arg_event_timeout_usec);
+ log_warning("Invalid udev.exec-delay ignored: %s", value);
+ } else if ((value = startswith(opt, "udev.event-timeout="))) {
+ r = safe_atou64(value, &arg_event_timeout_usec);
if (r < 0) {
- log_warning("Invalid udev.event-timeout ignored: %s", opt + 16);
+ log_warning("Invalid udev.event-timeout ignored: %s", value);
break;
}
arg_event_timeout_usec *= USEC_PER_SEC;
@@ -1120,19 +1113,14 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- udev_set_log_fn(udev, udev_main_log);
- log_set_max_level(udev_get_log_priority(udev));
-
r = parse_argv(argc, argv);
if (r <= 0)
goto exit;
kernel_cmdline_options(udev);
- if (arg_debug) {
+ if (arg_debug)
log_set_max_level(LOG_DEBUG);
- udev_set_log_priority(udev, LOG_DEBUG);
- }
if (getuid() != 0) {
log_error("root privileges required");
@@ -1141,22 +1129,24 @@ int main(int argc, char *argv[]) {
r = mac_selinux_init("/dev");
if (r < 0) {
- log_error("could not initialize labelling: %s", strerror(-r));
+ log_error_errno(r, "could not initialize labelling: %m");
goto exit;
}
/* set umask before creating any file/directory */
r = chdir("/");
if (r < 0) {
- log_error("could not change dir to /: %m");
+ log_error_errno(errno, "could not change dir to /: %m");
goto exit;
}
umask(022);
+ udev_list_init(udev, &properties_list, true);
+
r = mkdir("/run/udev", 0755);
if (r < 0 && errno != EEXIST) {
- log_error("could not create /run/udev: %m");
+ log_error_errno(errno, "could not create /run/udev: %m");
goto exit;
}
@@ -1215,6 +1205,8 @@ int main(int argc, char *argv[]) {
goto exit;
}
fd_netlink = udev_monitor_get_fd(monitor);
+
+ udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
}
if (udev_monitor_enable_receiving(monitor) < 0) {
@@ -1229,9 +1221,7 @@ int main(int argc, char *argv[]) {
goto exit;
}
- udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
-
- log_info("starting version " VERSION "\n");
+ log_info("starting version " VERSION);
udev_builtin_init(udev);
@@ -1243,7 +1233,7 @@ int main(int argc, char *argv[]) {
rc = udev_rules_apply_static_dev_perms(rules);
if (rc < 0)
- log_error("failed to apply permissions on static device nodes - %s", strerror(-rc));
+ log_error_errno(rc, "failed to apply permissions on static device nodes - %m");
if (arg_daemonize) {
pid_t pid;
@@ -1253,7 +1243,7 @@ int main(int argc, char *argv[]) {
case 0:
break;
case -1:
- log_error("fork of daemon failed: %m");
+ log_error_errno(errno, "fork of daemon failed: %m");
rc = 4;
goto exit;
default:
@@ -1316,7 +1306,7 @@ int main(int argc, char *argv[]) {
fd_ep = epoll_create1(EPOLL_CLOEXEC);
if (fd_ep < 0) {
- log_error("error creating epoll fd: %m");
+ log_error_errno(errno, "error creating epoll fd: %m");
goto exit;
}
if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 ||
@@ -1324,7 +1314,7 @@ int main(int argc, char *argv[]) {
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 ||
epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) {
- log_error("fail to add fds to epoll: %m");
+ log_error_errno(errno, "fail to add fds to epoll: %m");
goto exit;
}
@@ -1542,6 +1532,7 @@ exit_daemonize:
udev_monitor_unref(monitor);
udev_ctrl_connection_unref(ctrl_conn);
udev_ctrl_unref(udev_ctrl);
+ udev_list_cleanup(&properties_list);
mac_selinux_finish();
udev_unref(udev);
log_close();
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c
index 1437c30d14..a910808d04 100644
--- a/src/update-done/update-done.c
+++ b/src/update-done/update-done.c
@@ -46,13 +46,10 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
if (utimensat(AT_FDCWD, path, twice, AT_SYMLINK_NOFOLLOW) < 0) {
- if (errno == EROFS) {
- log_debug("Can't update timestamp file %s, file system is read-only.", path);
- return 0;
- }
+ if (errno == EROFS)
+ return log_debug("Can't update timestamp file %s, file system is read-only.", path);
- log_error("Failed to update timestamp on %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
}
} else if (errno == ENOENT) {
@@ -62,24 +59,17 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
/* The timestamp file doesn't exist yet? Then let's create it. */
r = mac_selinux_create_file_prepare(path, S_IFREG);
- if (r < 0) {
- log_error("Failed to set SELinux context for %s: %s",
- path, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set SELinux context for %s: %m", path);
fd = open(path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0644);
mac_selinux_create_file_clear();
if (fd < 0) {
+ if (errno == EROFS)
+ return log_debug("Can't create timestamp file %s, file system is read-only.", path);
- if (errno == EROFS) {
- log_debug("Can't create timestamp file %s, file system is read-only.", path);
- return 0;
- }
-
- log_error("Failed to create timestamp file %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to create timestamp file %s: %m", path);
}
(void) loop_write(fd, MESSAGE, strlen(MESSAGE), false);
@@ -87,14 +77,10 @@ static int apply_timestamp(const char *path, struct timespec *ts) {
twice[0] = *ts;
twice[1] = *ts;
- if (futimens(fd, twice) < 0) {
- log_error("Failed to update timestamp on %s: %m", path);
- return -errno;
- }
- } else {
- log_error("Failed to stat() timestamp file %s: %m", path);
- return -errno;
- }
+ if (futimens(fd, twice) < 0)
+ return log_error_errno(errno, "Failed to update timestamp on %s: %m", path);
+ } else
+ log_error_errno(errno, "Failed to stat() timestamp file %s: %m", path);
return 0;
}
@@ -108,13 +94,13 @@ int main(int argc, char *argv[]) {
log_open();
if (stat("/usr", &st) < 0) {
- log_error("Failed to stat /usr: %m");
+ log_error_errno(errno, "Failed to stat /usr: %m");
return EXIT_FAILURE;
}
r = mac_selinux_init(NULL);
if (r < 0) {
- log_error("SELinux setup failed: %s", strerror(-r));
+ log_error_errno(r, "SELinux setup failed: %m");
goto finish;
}
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index 31cae70950..15da83193b 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -131,9 +131,9 @@ static int on_reboot(Context *c) {
#ifdef HAVE_AUDIT
if (c->audit_fd >= 0)
- if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "init", NULL, NULL, NULL, 1) < 0 &&
+ if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- log_error("Failed to send audit message: %m");
+ log_error_errno(errno, "Failed to send audit message: %m");
r = -errno;
}
#endif
@@ -144,7 +144,7 @@ static int on_reboot(Context *c) {
q = utmp_put_reboot(t);
if (q < 0) {
- log_error("Failed to write utmp record: %s", strerror(-q));
+ log_error_errno(q, "Failed to write utmp record: %m");
r = q;
}
@@ -161,16 +161,16 @@ static int on_shutdown(Context *c) {
#ifdef HAVE_AUDIT
if (c->audit_fd >= 0)
- if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "init", NULL, NULL, NULL, 1) < 0 &&
+ if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- log_error("Failed to send audit message: %m");
+ log_error_errno(errno, "Failed to send audit message: %m");
r = -errno;
}
#endif
q = utmp_put_shutdown();
if (q < 0) {
- log_error("Failed to write utmp record: %s", strerror(-q));
+ log_error_errno(q, "Failed to write utmp record: %m");
r = q;
}
@@ -189,10 +189,8 @@ static int on_runlevel(Context *c) {
q = utmp_get_runlevel(&previous, NULL);
if (q < 0) {
- if (q != -ESRCH && q != -ENOENT) {
- log_error("Failed to get current runlevel: %s", strerror(-q));
- return q;
- }
+ if (q != -ESRCH && q != -ENOENT)
+ return log_error_errno(q, "Failed to get current runlevel: %m");
previous = 0;
}
@@ -215,9 +213,9 @@ static int on_runlevel(Context *c) {
runlevel > 0 ? runlevel : 'N') < 0)
return log_oom();
- if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0 &&
+ if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- log_error("Failed to send audit message: %m");
+ log_error_errno(errno, "Failed to send audit message: %m");
r = -errno;
}
}
@@ -225,7 +223,7 @@ static int on_runlevel(Context *c) {
q = utmp_put_runlevel(runlevel, previous);
if (q < 0 && q != -ESRCH && q != -ENOENT) {
- log_error("Failed to write utmp record: %s", strerror(-q));
+ log_error_errno(q, "Failed to write utmp record: %m");
r = q;
}
@@ -261,11 +259,11 @@ int main(int argc, char *argv[]) {
* don't worry about it. */
c.audit_fd = audit_open();
if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
- log_error("Failed to connect to audit log: %m");
+ log_error_errno(errno, "Failed to connect to audit log: %m");
#endif
r = bus_open_system_systemd(&c.bus);
if (r < 0) {
- log_error("Failed to get D-Bus connection: %s", strerror(-r));
+ log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
goto finish;
}
diff --git a/src/vconsole/90-vconsole.rules.in b/src/vconsole/90-vconsole.rules.in
new file mode 100644
index 0000000000..062009640c
--- /dev/null
+++ b/src/vconsole/90-vconsole.rules.in
@@ -0,0 +1,11 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# Kernel resets vconsole state when changing console drivers so run
+# systemd-vconsole-setup when fbcon loads
+
+ACTION=="add", SUBSYSTEM=="graphics", KERNEL=="fbcon", RUN+="@rootlibexecdir@/systemd-vconsole-setup"
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 0db97f88bc..28371711b6 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -54,15 +54,16 @@ static int disable_utf8(int fd) {
if (ioctl(fd, KDSKBMODE, K_XLATE) < 0)
r = -errno;
- if (loop_write(fd, "\033%@", 3, false) < 0)
- r = -errno;
+ k = loop_write(fd, "\033%@", 3, false);
+ if (k < 0)
+ r = k;
k = write_string_file("/sys/module/vt/parameters/default_utf8", "0");
if (k < 0)
r = k;
if (r < 0)
- log_warning("Failed to disable UTF-8: %s", strerror(-r));
+ log_warning_errno(r, "Failed to disable UTF-8: %m");
return r;
}
@@ -86,15 +87,16 @@ static int enable_utf8(int fd) {
r = -errno;
}
- if (loop_write(fd, "\033%G", 3, false) < 0)
- r = -errno;
+ k = loop_write(fd, "\033%G", 3, false);
+ if (k < 0)
+ r = k;
k = write_string_file("/sys/module/vt/parameters/default_utf8", "1");
if (k < 0)
r = k;
if (r < 0)
- log_warning("Failed to enable UTF-8: %s", strerror(-r));
+ log_warning_errno(r, "Failed to enable UTF-8: %m");
return r;
}
@@ -122,10 +124,9 @@ static int keymap_load(const char *vc, const char *map, const char *map_toggle,
args[i++] = NULL;
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork: %m");
- return -errno;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
+ else if (pid == 0) {
execv(args[0], (char **) args);
_exit(EXIT_FAILURE);
}
@@ -160,10 +161,9 @@ static int font_load(const char *vc, const char *font, const char *map, const ch
args[i++] = NULL;
pid = fork();
- if (pid < 0) {
- log_error("Failed to fork: %m");
- return -errno;
- } else if (pid == 0) {
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
+ else if (pid == 0) {
execv(args[0], (char **) args);
_exit(EXIT_FAILURE);
}
@@ -262,7 +262,7 @@ int main(int argc, char **argv) {
fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
if (fd < 0) {
- log_error("Failed to open %s: %m", vc);
+ log_error_errno(errno, "Failed to open %s: %m", vc);
return EXIT_FAILURE;
}
@@ -282,7 +282,7 @@ int main(int argc, char **argv) {
NULL);
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read /etc/vconsole.conf: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read /etc/vconsole.conf: %m");
/* Let the kernel command line override /etc/vconsole.conf */
if (detect_container(NULL) <= 0) {
@@ -295,7 +295,7 @@ int main(int argc, char **argv) {
NULL);
if (r < 0 && r != -ENOENT)
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+ log_warning_errno(r, "Failed to read /proc/cmdline: %m");
}
if (utf8)
@@ -305,21 +305,21 @@ int main(int argc, char **argv) {
r = font_load(vc, vc_font, vc_font_map, vc_font_unimap, &font_pid);
if (r < 0) {
- log_error("Failed to start " KBD_SETFONT ": %s", strerror(-r));
+ log_error_errno(r, "Failed to start " KBD_SETFONT ": %m");
return EXIT_FAILURE;
}
if (font_pid > 0)
- wait_for_terminate_and_warn(KBD_SETFONT, font_pid);
+ wait_for_terminate_and_warn(KBD_SETFONT, font_pid, true);
r = keymap_load(vc, vc_keymap, vc_keymap_toggle, utf8, &keymap_pid);
if (r < 0) {
- log_error("Failed to start " KBD_LOADKEYS ": %s", strerror(-r));
+ log_error_errno(r, "Failed to start " KBD_LOADKEYS ": %m");
return EXIT_FAILURE;
}
if (keymap_pid > 0)
- wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid);
+ wait_for_terminate_and_warn(KBD_LOADKEYS, keymap_pid, true);
/* Only copy the font when we started setfont successfully */
if (font_copy && font_pid > 0)