summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/activate/activate.c82
-rw-r--r--src/analyze/analyze-verify.c8
-rw-r--r--src/analyze/analyze.c126
-rw-r--r--src/ask-password/ask-password.c91
-rw-r--r--src/backlight/backlight.c16
-rw-r--r--src/basic/alloc-util.c81
-rw-r--r--src/basic/alloc-util.h108
-rw-r--r--src/basic/async.c1
-rw-r--r--src/basic/audit-util.c (renamed from src/basic/audit.c)10
-rw-r--r--src/basic/audit-util.h (renamed from src/basic/audit.h)0
-rw-r--r--src/basic/barrier.c1
-rw-r--r--src/basic/bitmap.c4
-rw-r--r--src/basic/btrfs-util.c971
-rw-r--r--src/basic/btrfs-util.h72
-rw-r--r--src/basic/bus-label.c7
-rw-r--r--src/basic/calendarspec.c41
-rw-r--r--src/basic/calendarspec.h1
-rw-r--r--src/basic/cap-list.c3
-rw-r--r--src/basic/capability-util.c (renamed from src/basic/capability.c)18
-rw-r--r--src/basic/capability-util.h (renamed from src/basic/capability.h)0
-rw-r--r--src/basic/cgroup-util.c37
-rw-r--r--src/basic/chattr-util.c107
-rw-r--r--src/basic/chattr-util.h28
-rw-r--r--src/basic/clock-util.c8
-rw-r--r--src/basic/clock-util.h1
-rw-r--r--src/basic/conf-files.c19
-rw-r--r--src/basic/copy.c14
-rw-r--r--src/basic/cpu-set-util.c111
-rw-r--r--src/basic/cpu-set-util.h34
-rw-r--r--src/basic/def.h24
-rw-r--r--src/basic/device-nodes.h2
-rw-r--r--src/basic/dirent-util.c81
-rw-r--r--src/basic/dirent-util.h51
-rw-r--r--src/basic/env-util.c19
-rw-r--r--src/basic/env-util.h2
-rw-r--r--src/basic/escape.c482
-rw-r--r--src/basic/escape.h48
-rw-r--r--src/basic/ether-addr-util.c44
-rw-r--r--src/basic/ether-addr-util.h4
-rw-r--r--src/basic/extract-word.c286
-rw-r--r--src/basic/extract-word.h36
-rw-r--r--src/basic/fd-util.c351
-rw-r--r--src/basic/fd-util.h71
-rw-r--r--src/basic/fdset.c12
-rw-r--r--src/basic/fdset.h2
-rw-r--r--src/basic/fileio.c354
-rw-r--r--src/basic/fileio.h30
-rw-r--r--src/basic/formats-util.h (renamed from src/shared/formats-util.h)0
-rw-r--r--src/basic/fs-util.c480
-rw-r--r--src/basic/fs-util.h74
-rw-r--r--src/basic/glob-util.c72
-rw-r--r--src/basic/glob-util.h37
-rw-r--r--src/basic/hashmap.c47
-rw-r--r--src/basic/hashmap.h11
-rw-r--r--src/basic/hexdecoct.c698
-rw-r--r--src/basic/hexdecoct.h54
-rw-r--r--src/basic/hostname-util.c7
-rw-r--r--src/basic/in-addr-util.c1
-rw-r--r--src/basic/io-util.c261
-rw-r--r--src/basic/io-util.h76
-rw-r--r--src/basic/json.c8
-rw-r--r--src/basic/locale-util.c96
-rw-r--r--src/basic/locale-util.h21
-rw-r--r--src/basic/lockfile-util.c8
-rw-r--r--src/basic/log.c44
-rw-r--r--src/basic/log.h19
-rw-r--r--src/basic/login-util.c3
-rw-r--r--src/basic/login-util.h5
-rw-r--r--src/basic/macro.h137
-rw-r--r--src/basic/memfd-util.c16
-rw-r--r--src/basic/memfd-util.h3
-rw-r--r--src/basic/missing.h70
-rw-r--r--src/basic/mkdir.c7
-rw-r--r--src/basic/mount-util.c529
-rw-r--r--src/basic/mount-util.h52
-rw-r--r--src/basic/parse-util.c460
-rw-r--r--src/basic/parse-util.h92
-rw-r--r--src/basic/path-util.c644
-rw-r--r--src/basic/path-util.h29
-rw-r--r--src/basic/prioq.c15
-rw-r--r--src/basic/proc-cmdline.c174
-rw-r--r--src/basic/proc-cmdline.h29
-rw-r--r--src/basic/process-util.c210
-rw-r--r--src/basic/process-util.h36
-rw-r--r--src/basic/random-util.c14
-rw-r--r--src/basic/replace-var.c5
-rw-r--r--src/basic/rlimit-util.c70
-rw-r--r--src/basic/rlimit-util.h33
-rw-r--r--src/basic/rm-rf.c12
-rw-r--r--src/basic/selinux-util.c105
-rw-r--r--src/basic/selinux-util.h6
-rw-r--r--src/basic/signal-util.c9
-rw-r--r--src/basic/signal-util.h2
-rw-r--r--src/basic/siphash24.c245
-rw-r--r--src/basic/siphash24.h13
-rw-r--r--src/basic/smack-util.c12
-rw-r--r--src/basic/smack-util.h3
-rw-r--r--src/basic/socket-label.c19
-rw-r--r--src/basic/socket-util.c216
-rw-r--r--src/basic/socket-util.h15
-rw-r--r--src/basic/stat-util.c216
-rw-r--r--src/basic/stat-util.h70
-rw-r--r--src/basic/stdio-util.h78
-rw-r--r--src/basic/strbuf.c3
-rw-r--r--src/basic/string-table.c35
-rw-r--r--src/basic/string-table.h88
-rw-r--r--src/basic/string-util.c800
-rw-r--r--src/basic/string-util.h184
-rw-r--r--src/basic/strv.c176
-rw-r--r--src/basic/strv.h16
-rw-r--r--src/basic/syslog-util.c115
-rw-r--r--src/basic/syslog-util.h34
-rw-r--r--src/basic/terminal-util.c280
-rw-r--r--src/basic/terminal-util.h9
-rw-r--r--src/basic/time-util.c186
-rw-r--r--src/basic/time-util.h8
-rw-r--r--src/basic/umask-util.h48
-rw-r--r--src/basic/unit-name.c176
-rw-r--r--src/basic/unit-name.h227
-rw-r--r--src/basic/user-util.c472
-rw-r--r--src/basic/user-util.h67
-rw-r--r--src/basic/utf8.c2
-rw-r--r--src/basic/util.c6148
-rw-r--r--src/basic/util.h795
-rw-r--r--src/basic/verbs.c1
-rw-r--r--src/basic/virt.c48
-rw-r--r--src/basic/virt.h3
-rw-r--r--src/basic/web-util.c78
-rw-r--r--src/basic/web-util.h32
-rw-r--r--src/basic/xattr-util.c195
-rw-r--r--src/basic/xattr-util.h38
-rw-r--r--src/basic/xml.c1
-rw-r--r--src/binfmt/binfmt.c26
-rw-r--r--src/boot/bootctl.c37
-rw-r--r--src/bootchart/bootchart.c35
-rw-r--r--src/bootchart/store.c21
-rw-r--r--src/bootchart/svg.c22
-rw-r--r--src/bus-proxyd/bus-proxyd.c49
-rw-r--r--src/bus-proxyd/bus-xml-policy.c26
-rw-r--r--src/bus-proxyd/driver.c12
-rw-r--r--src/bus-proxyd/proxy.c62
-rw-r--r--src/bus-proxyd/proxy.h1
-rw-r--r--src/bus-proxyd/stdio-bridge.c22
-rw-r--r--src/bus-proxyd/synthesize.c5
-rw-r--r--src/bus-proxyd/synthesize.h1
-rw-r--r--src/bus-proxyd/test-bus-xml-policy.c11
-rw-r--r--src/cgls/cgls.c27
-rw-r--r--src/cgroups-agent/cgroups-agent.c5
-rw-r--r--src/cgtop/cgtop.c37
-rw-r--r--src/core/audit-fd.c1
-rw-r--r--src/core/automount.c103
-rw-r--r--src/core/automount.h12
-rw-r--r--src/core/bus-endpoint.c5
-rw-r--r--src/core/bus-policy.c7
-rw-r--r--src/core/busname.c59
-rw-r--r--src/core/busname.h17
-rw-r--r--src/core/cgroup.c12
-rw-r--r--src/core/dbus-automount.c3
-rw-r--r--src/core/dbus-busname.c5
-rw-r--r--src/core/dbus-cgroup.c17
-rw-r--r--src/core/dbus-cgroup.h1
-rw-r--r--src/core/dbus-execute.c550
-rw-r--r--src/core/dbus-execute.h1
-rw-r--r--src/core/dbus-job.c9
-rw-r--r--src/core/dbus-job.h1
-rw-r--r--src/core/dbus-kill.h1
-rw-r--r--src/core/dbus-manager.c94
-rw-r--r--src/core/dbus-mount.c10
-rw-r--r--src/core/dbus-mount.h1
-rw-r--r--src/core/dbus-path.c5
-rw-r--r--src/core/dbus-scope.c15
-rw-r--r--src/core/dbus-service.c55
-rw-r--r--src/core/dbus-socket.c31
-rw-r--r--src/core/dbus-swap.c9
-rw-r--r--src/core/dbus-target.h1
-rw-r--r--src/core/dbus-timer.c7
-rw-r--r--src/core/dbus-unit.c20
-rw-r--r--src/core/dbus.c39
-rw-r--r--src/core/device.c23
-rw-r--r--src/core/device.h13
-rw-r--r--src/core/execute.c304
-rw-r--r--src/core/execute.h29
-rw-r--r--src/core/failure-action.c5
-rw-r--r--src/core/hostname-setup.c15
-rw-r--r--src/core/ima-setup.c4
-rw-r--r--src/core/job.c23
-rw-r--r--src/core/job.h6
-rw-r--r--src/core/kill.c5
-rw-r--r--src/core/killall.c14
-rw-r--r--src/core/kmod-setup.c2
-rw-r--r--src/core/load-fragment-gperf.gperf.m421
-rw-r--r--src/core/load-fragment.c736
-rw-r--r--src/core/load-fragment.h3
-rw-r--r--src/core/locale-setup.c13
-rw-r--r--src/core/loopback-setup.c5
-rw-r--r--src/core/machine-id-setup.c26
-rw-r--r--src/core/main.c568
-rw-r--r--src/core/manager.c282
-rw-r--r--src/core/manager.h8
-rw-r--r--src/core/mount-setup.c23
-rw-r--r--src/core/mount.c122
-rw-r--r--src/core/mount.h22
-rw-r--r--src/core/namespace.c74
-rw-r--r--src/core/path.c33
-rw-r--r--src/core/path.h12
-rw-r--r--src/core/scope.c25
-rw-r--r--src/core/scope.h14
-rw-r--r--src/core/selinux-access.c20
-rw-r--r--src/core/selinux-access.h2
-rw-r--r--src/core/selinux-setup.c17
-rw-r--r--src/core/service.c452
-rw-r--r--src/core/service.h29
-rw-r--r--src/core/show-status.c84
-rw-r--r--src/core/show-status.h7
-rw-r--r--src/core/shutdown.c34
-rw-r--r--src/core/slice.c16
-rw-r--r--src/core/slice.h11
-rw-r--r--src/core/smack-setup.c25
-rw-r--r--src/core/snapshot.c17
-rw-r--r--src/core/snapshot.h11
-rw-r--r--src/core/socket.c348
-rw-r--r--src/core/socket.h32
-rw-r--r--src/core/swap.c66
-rw-r--r--src/core/swap.h21
-rw-r--r--src/core/system.conf6
-rw-r--r--src/core/target.c15
-rw-r--r--src/core/target.h11
-rw-r--r--src/core/timer.c39
-rw-r--r--src/core/timer.h13
-rw-r--r--src/core/transaction.c3
-rw-r--r--src/core/umount.c41
-rw-r--r--src/core/unit-printf.c20
-rw-r--r--src/core/unit.c242
-rw-r--r--src/core/unit.h30
-rw-r--r--src/cryptsetup/cryptsetup-generator.c8
-rw-r--r--src/cryptsetup/cryptsetup.c78
-rw-r--r--src/dbus1-generator/dbus1-generator.c20
-rw-r--r--src/debug-generator/debug-generator.c36
-rw-r--r--src/delta/delta.c28
-rw-r--r--src/detect-virt/detect-virt.c42
-rw-r--r--src/escape/escape.c11
-rw-r--r--src/firstboot/firstboot.c77
-rw-r--r--src/fsck/fsck.c38
-rw-r--r--src/fstab-generator/fstab-generator.c24
-rw-r--r--src/getty-generator/getty-generator.c15
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c45
-rw-r--r--src/hibernate-resume/hibernate-resume-generator.c10
-rw-r--r--src/hibernate-resume/hibernate-resume.c3
-rw-r--r--src/hostname/hostnamectl.c21
-rw-r--r--src/hostname/hostnamed.c16
-rw-r--r--src/hwdb/hwdb.c25
-rw-r--r--src/import/aufs-util.c3
-rw-r--r--src/import/curl-util.c3
-rw-r--r--src/import/curl-util.h3
-rw-r--r--src/import/export-raw.c11
-rw-r--r--src/import/export-tar.c17
-rw-r--r--src/import/export.c20
-rw-r--r--src/import/import-common.c8
-rw-r--r--src/import/import-compress.c3
-rw-r--r--src/import/import-raw.c30
-rw-r--r--src/import/import-tar.c29
-rw-r--r--src/import/import.c20
-rw-r--r--src/import/importd.c32
-rw-r--r--src/import/pull-common.c71
-rw-r--r--src/import/pull-dkr.c53
-rw-r--r--src/import/pull-job.c9
-rw-r--r--src/import/pull-raw.c49
-rw-r--r--src/import/pull-tar.c37
-rw-r--r--src/import/pull.c20
-rw-r--r--src/import/qcow2-util.c7
-rw-r--r--src/import/test-qcow2.c4
-rw-r--r--src/initctl/initctl.c21
-rw-r--r--src/journal-remote/journal-gatewayd.c48
-rw-r--r--src/journal-remote/journal-remote-parse.c4
-rw-r--r--src/journal-remote/journal-remote-write.c1
-rw-r--r--src/journal-remote/journal-remote.c71
-rw-r--r--src/journal-remote/journal-upload-journal.c26
-rw-r--r--src/journal-remote/journal-upload.c26
-rwxr-xr-xsrc/journal-remote/log-generator.py10
-rw-r--r--src/journal-remote/microhttpd-util.c14
-rw-r--r--src/journal/cat.c45
-rw-r--r--src/journal/catalog.c88
-rw-r--r--src/journal/compress.c243
-rw-r--r--src/journal/coredump-vacuum.c12
-rw-r--r--src/journal/coredump.c49
-rw-r--r--src/journal/coredumpctl.c60
-rw-r--r--src/journal/fsprg.h1
-rw-r--r--src/journal/journal-authenticate.c6
-rw-r--r--src/journal/journal-def.h5
-rw-r--r--src/journal/journal-file.c130
-rw-r--r--src/journal/journal-file.h20
-rw-r--r--src/journal/journal-internal.h10
-rw-r--r--src/journal/journal-qrcode.h3
-rw-r--r--src/journal/journal-send.c45
-rw-r--r--src/journal/journal-vacuum.c136
-rw-r--r--src/journal/journal-vacuum.h6
-rw-r--r--src/journal/journal-verify.c19
-rw-r--r--src/journal/journalctl.c198
-rw-r--r--src/journal/journald-audit.c9
-rw-r--r--src/journal/journald-console.c11
-rw-r--r--src/journal/journald-gperf.gperf2
-rw-r--r--src/journal/journald-kmsg.c27
-rw-r--r--src/journal/journald-native.c24
-rw-r--r--src/journal/journald-rate-limit.c24
-rw-r--r--src/journal/journald-server.c609
-rw-r--r--src/journal/journald-server.h37
-rw-r--r--src/journal/journald-stream.c102
-rw-r--r--src/journal/journald-stream.h6
-rw-r--r--src/journal/journald-syslog.c21
-rw-r--r--src/journal/journald-wall.c8
-rw-r--r--src/journal/journald.c16
-rw-r--r--src/journal/journald.conf2
-rw-r--r--src/journal/mmap-cache.c1
-rw-r--r--src/journal/sd-journal.c350
-rw-r--r--src/journal/stacktrace.c7
-rw-r--r--src/journal/test-catalog.c11
-rw-r--r--src/journal/test-compress-benchmark.c112
-rw-r--r--src/journal/test-compress.c14
-rw-r--r--src/journal/test-journal-enum.c3
-rw-r--r--src/journal/test-journal-flush.c5
-rw-r--r--src/journal/test-journal-init.c5
-rw-r--r--src/journal/test-journal-interleaving.c9
-rw-r--r--src/journal/test-journal-match.c6
-rw-r--r--src/journal/test-journal-send.c3
-rw-r--r--src/journal/test-journal-stream.c11
-rw-r--r--src/journal/test-journal-syslog.c2
-rw-r--r--src/journal/test-journal-verify.c7
-rw-r--r--src/journal/test-journal.c4
-rw-r--r--src/journal/test-mmap-cache.c6
-rw-r--r--src/libsystemd-network/arp-util.c3
-rw-r--r--src/libsystemd-network/dhcp-identifier.c15
-rw-r--r--src/libsystemd-network/dhcp-identifier.h2
-rw-r--r--src/libsystemd-network/dhcp-internal.h8
-rw-r--r--src/libsystemd-network/dhcp-network.c12
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h2
-rw-r--r--src/libsystemd-network/dhcp6-internal.h6
-rw-r--r--src/libsystemd-network/dhcp6-network.c113
-rw-r--r--src/libsystemd-network/dhcp6-option.c12
-rw-r--r--src/libsystemd-network/icmp6-util.c129
-rw-r--r--src/libsystemd-network/icmp6-util.h27
-rw-r--r--src/libsystemd-network/lldp-internal.c253
-rw-r--r--src/libsystemd-network/lldp-internal.h13
-rw-r--r--src/libsystemd-network/lldp-network.c34
-rw-r--r--src/libsystemd-network/lldp-network.h1
-rw-r--r--src/libsystemd-network/lldp-port.c10
-rw-r--r--src/libsystemd-network/lldp-tlv.c345
-rw-r--r--src/libsystemd-network/lldp-tlv.h26
-rw-r--r--src/libsystemd-network/lldp.h13
-rw-r--r--src/libsystemd-network/network-internal.c37
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c33
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c44
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c29
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c33
-rw-r--r--src/libsystemd-network/sd-dhcp6-lease.c6
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c12
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c54
-rw-r--r--src/libsystemd-network/sd-lldp.c70
-rw-r--r--src/libsystemd-network/sd-ndisc.c (renamed from src/libsystemd-network/sd-icmp6-nd.c)399
-rw-r--r--src/libsystemd-network/sd-pppoe.c810
-rw-r--r--src/libsystemd-network/test-dhcp-client.c10
-rw-r--r--src/libsystemd-network/test-dhcp-option.c8
-rw-r--r--src/libsystemd-network/test-dhcp-server.c21
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c19
-rw-r--r--src/libsystemd-network/test-icmp6-rs.c357
-rw-r--r--src/libsystemd-network/test-ipv4ll-manual.c14
-rw-r--r--src/libsystemd-network/test-ipv4ll.c24
-rw-r--r--src/libsystemd-network/test-lldp.c260
-rw-r--r--src/libsystemd-network/test-ndisc-rs.c171
-rw-r--r--src/libsystemd-network/test-pppoe.c176
-rw-r--r--src/libsystemd/libsystemd.sym3
-rw-r--r--src/libsystemd/sd-bus/bus-container.c18
-rw-r--r--src/libsystemd/sd-bus/bus-control.c13
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c3
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c28
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c21
-rw-r--r--src/libsystemd/sd-bus/bus-error.c14
-rw-r--r--src/libsystemd/sd-bus/bus-internal.c5
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h18
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.c9
-rw-r--r--src/libsystemd/sd-bus/bus-kernel.c36
-rw-r--r--src/libsystemd/sd-bus/bus-match.c7
-rw-r--r--src/libsystemd/sd-bus/bus-match.h4
-rw-r--r--src/libsystemd/sd-bus/bus-message.c22
-rw-r--r--src/libsystemd/sd-bus/bus-message.h7
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c31
-rw-r--r--src/libsystemd/sd-bus/bus-slot.c3
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c24
-rw-r--r--src/libsystemd/sd-bus/bus-track.c4
-rw-r--r--src/libsystemd/sd-bus/bus-type.h3
-rw-r--r--src/libsystemd/sd-bus/busctl-introspect.c8
-rw-r--r--src/libsystemd/sd-bus/busctl.c45
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c202
-rw-r--r--src/libsystemd/sd-bus/test-bus-benchmark.c12
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c14
-rw-r--r--src/libsystemd/sd-bus/test-bus-cleanup.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-gvariant.c10
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel-bloom.c8
-rw-r--r--src/libsystemd/sd-bus/test-bus-kernel.c10
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c44
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c13
-rw-r--r--src/libsystemd/sd-bus/test-bus-proxy.c9
-rw-r--r--src/libsystemd/sd-bus/test-bus-server.c10
-rw-r--r--src/libsystemd/sd-bus/test-bus-signature.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-zero-copy.c15
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c135
l---------src/libsystemd/sd-device/Makefile (renamed from src/machine-id-commit/Makefile)0
-rw-r--r--src/libsystemd/sd-device/device-enumerator.c21
-rw-r--r--src/libsystemd/sd-device/device-private.c40
-rw-r--r--src/libsystemd/sd-device/device-private.h6
-rw-r--r--src/libsystemd/sd-device/sd-device.c73
-rw-r--r--src/libsystemd/sd-event/event-util.h3
-rw-r--r--src/libsystemd/sd-event/sd-event.c53
-rw-r--r--src/libsystemd/sd-event/test-event.c4
-rw-r--r--src/libsystemd/sd-hwdb/hwdb-internal.h1
-rw-r--r--src/libsystemd/sd-hwdb/hwdb-util.h4
-rw-r--r--src/libsystemd/sd-hwdb/sd-hwdb.c14
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c8
-rw-r--r--src/libsystemd/sd-login/sd-login.c32
-rw-r--r--src/libsystemd/sd-login/test-login.c9
-rw-r--r--src/libsystemd/sd-netlink/local-addresses.c2
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h13
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c22
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c168
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c18
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c1
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h2
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c72
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c80
-rw-r--r--src/libsystemd/sd-netlink/test-local-addresses.c1
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c13
-rw-r--r--src/libsystemd/sd-network/network-util.c4
-rw-r--r--src/libsystemd/sd-network/sd-network.c16
-rw-r--r--src/libsystemd/sd-path/sd-path.c12
-rw-r--r--src/libsystemd/sd-resolve/resolve-util.h3
-rw-r--r--src/libsystemd/sd-resolve/sd-resolve.c32
-rw-r--r--src/libsystemd/sd-resolve/test-resolve.c15
-rw-r--r--src/libsystemd/sd-utf8/sd-utf8.c3
-rw-r--r--src/libudev/libudev-device-internal.h3
-rw-r--r--src/libudev/libudev-device-private.c4
-rw-r--r--src/libudev/libudev-device.c30
-rw-r--r--src/libudev/libudev-enumerate.c17
-rw-r--r--src/libudev/libudev-hwdb.c4
-rw-r--r--src/libudev/libudev-list.c5
-rw-r--r--src/libudev/libudev-monitor.c28
-rw-r--r--src/libudev/libudev-private.h5
-rw-r--r--src/libudev/libudev-queue.c3
-rw-r--r--src/libudev/libudev-util.c60
-rw-r--r--src/libudev/libudev.c10
-rw-r--r--src/locale/localectl.c29
-rw-r--r--src/locale/localed.c28
-rw-r--r--src/login/inhibit.c19
-rw-r--r--src/login/loginctl.c35
-rw-r--r--src/login/logind-acl.c11
-rw-r--r--src/login/logind-acl.h3
-rw-r--r--src/login/logind-action.c14
-rw-r--r--src/login/logind-action.h1
-rw-r--r--src/login/logind-button.c8
-rw-r--r--src/login/logind-core.c11
-rw-r--r--src/login/logind-dbus.c55
-rw-r--r--src/login/logind-device.c3
-rw-r--r--src/login/logind-inhibit.c13
-rw-r--r--src/login/logind-seat-dbus.c10
-rw-r--r--src/login/logind-seat.c14
-rw-r--r--src/login/logind-session-dbus.c13
-rw-r--r--src/login/logind-session-device.c9
-rw-r--r--src/login/logind-session.c43
-rw-r--r--src/login/logind-user-dbus.c8
-rw-r--r--src/login/logind-user.c40
-rw-r--r--src/login/logind-utmp.c19
-rw-r--r--src/login/logind.c35
-rw-r--r--src/login/logind.h11
-rw-r--r--src/login/pam_systemd.c27
-rw-r--r--src/login/sysfs-show.c14
-rw-r--r--src/login/test-inhibit.c6
-rw-r--r--src/machine-id-commit/machine-id-commit.c107
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c46
-rw-r--r--src/machine/image-dbus.c6
-rw-r--r--src/machine/machine-dbus.c46
-rw-r--r--src/machine/machine-dbus.h2
-rw-r--r--src/machine/machine.c69
-rw-r--r--src/machine/machine.h1
-rw-r--r--src/machine/machinectl.c83
-rw-r--r--src/machine/machined-dbus.c29
-rw-r--r--src/machine/machined.c15
-rw-r--r--src/machine/machined.h7
-rw-r--r--src/modules-load/modules-load.c25
-rw-r--r--src/network/networkctl.c37
-rw-r--r--src/network/networkd-address-pool.c8
-rw-r--r--src/network/networkd-address.c462
-rw-r--r--src/network/networkd-address.h20
-rw-r--r--src/network/networkd-dhcp4.c83
-rw-r--r--src/network/networkd-dhcp6.c189
-rw-r--r--src/network/networkd-fdb.c8
-rw-r--r--src/network/networkd-ipv4ll.c44
-rw-r--r--src/network/networkd-link-bus.c6
-rw-r--r--src/network/networkd-link.c728
-rw-r--r--src/network/networkd-link.h24
-rw-r--r--src/network/networkd-manager-bus.c2
-rw-r--r--src/network/networkd-manager.c807
-rw-r--r--src/network/networkd-ndisc.c88
-rw-r--r--src/network/networkd-netdev-bond.c31
-rw-r--r--src/network/networkd-netdev-bridge.c87
-rw-r--r--src/network/networkd-netdev-bridge.h4
-rw-r--r--src/network/networkd-netdev-gperf.gperf3
-rw-r--r--src/network/networkd-netdev-ipvlan.c15
-rw-r--r--src/network/networkd-netdev-macvlan.c3
-rw-r--r--src/network/networkd-netdev-tunnel.c34
-rw-r--r--src/network/networkd-netdev-tuntap.c3
-rw-r--r--src/network/networkd-netdev-veth.c19
-rw-r--r--src/network/networkd-netdev-vlan.c14
-rw-r--r--src/network/networkd-netdev-vxlan.c19
-rw-r--r--src/network/networkd-netdev.c13
-rw-r--r--src/network/networkd-netdev.h3
-rw-r--r--src/network/networkd-network-bus.c5
-rw-r--r--src/network/networkd-network-gperf.gperf2
-rw-r--r--src/network/networkd-network.c72
-rw-r--r--src/network/networkd-network.h1
-rw-r--r--src/network/networkd-route.c434
-rw-r--r--src/network/networkd-route.h30
-rw-r--r--src/network/networkd-util.c10
-rw-r--r--src/network/networkd-wait-online-link.c3
-rw-r--r--src/network/networkd-wait-online-manager.c5
-rw-r--r--src/network/networkd-wait-online.c10
-rw-r--r--src/network/networkd.c12
-rw-r--r--src/network/networkd.h11
-rw-r--r--src/network/test-network.c14
-rw-r--r--src/notify/notify.c8
-rw-r--r--src/nspawn/nspawn-cgroup.c12
-rw-r--r--src/nspawn/nspawn-expose-ports.c14
-rw-r--r--src/nspawn/nspawn-mount.c129
-rw-r--r--src/nspawn/nspawn-mount.h3
-rw-r--r--src/nspawn/nspawn-network.c9
-rw-r--r--src/nspawn/nspawn-register.c15
-rw-r--r--src/nspawn/nspawn-register.h2
-rw-r--r--src/nspawn/nspawn-settings.c31
-rw-r--r--src/nspawn/nspawn-settings.h3
-rw-r--r--src/nspawn/nspawn-setuid.c13
-rw-r--r--src/nspawn/nspawn.c259
-rw-r--r--src/nss-myhostname/nss-myhostname.c10
-rw-r--r--src/nss-mymachines/nss-mymachines.c16
-rw-r--r--src/nss-resolve/nss-resolve.c14
-rw-r--r--src/path/path.c14
-rw-r--r--src/quotacheck/quotacheck.c10
-rw-r--r--src/random-seed/random-seed.c10
-rw-r--r--src/rc-local-generator/rc-local-generator.c7
-rw-r--r--src/remount-fs/remount-fs.c7
-rw-r--r--src/reply-password/reply-password.c27
-rw-r--r--src/resolve-host/resolve-host.c20
-rw-r--r--src/resolve/resolved-bus.c2
-rw-r--r--src/resolve/resolved-conf.c31
-rw-r--r--src/resolve/resolved-dns-answer.c4
-rw-r--r--src/resolve/resolved-dns-cache.c1
-rw-r--r--src/resolve/resolved-dns-packet.c10
-rw-r--r--src/resolve/resolved-dns-query.c4
-rw-r--r--src/resolve/resolved-dns-question.c3
-rw-r--r--src/resolve/resolved-dns-rr.c21
-rw-r--r--src/resolve/resolved-dns-scope.c14
-rw-r--r--src/resolve/resolved-dns-server.c13
-rw-r--r--src/resolve/resolved-dns-stream.c3
-rw-r--r--src/resolve/resolved-dns-transaction.c10
-rw-r--r--src/resolve/resolved-dns-zone.c7
-rw-r--r--src/resolve/resolved-link.c6
-rw-r--r--src/resolve/resolved-llmnr.c3
-rw-r--r--src/resolve/resolved-manager.c27
-rw-r--r--src/resolve/resolved.c11
-rw-r--r--src/rfkill/rfkill.c440
-rw-r--r--src/run/run.c65
-rw-r--r--src/shared/acl-util.c5
-rw-r--r--src/shared/acpi-fpdt.c14
-rw-r--r--src/shared/apparmor-util.c7
-rw-r--r--src/shared/architecture.c2
-rw-r--r--src/shared/architecture.h16
-rw-r--r--src/shared/ask-password-api.c387
-rw-r--r--src/shared/ask-password-api.h25
-rw-r--r--src/shared/base-filesystem.c19
-rw-r--r--src/shared/bus-util.c263
-rw-r--r--src/shared/bus-util.h14
-rw-r--r--src/shared/cgroup-show.c16
-rw-r--r--src/shared/clean-ipc.c45
-rw-r--r--src/shared/condition.c33
-rw-r--r--src/shared/conf-parser.c139
-rw-r--r--src/shared/conf-parser.h7
-rw-r--r--src/shared/dev-setup.c6
-rw-r--r--src/shared/dns-domain.c15
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/dropin.c18
-rw-r--r--src/shared/efivars.c10
-rw-r--r--src/shared/firewall-util.c3
-rw-r--r--src/shared/fstab-util.c78
-rw-r--r--src/shared/fstab-util.h8
-rw-r--r--src/shared/generator.c35
-rw-r--r--src/shared/import-util.c33
-rw-r--r--src/shared/import-util.h2
-rw-r--r--src/shared/install-printf.c6
-rw-r--r--src/shared/install.c56
-rw-r--r--src/shared/logs-show.c27
-rw-r--r--src/shared/machine-image.c52
-rw-r--r--src/shared/machine-pool.c67
-rw-r--r--src/shared/pager.c40
-rw-r--r--src/shared/path-lookup.c37
-rw-r--r--src/shared/ptyfwd.c54
-rw-r--r--src/shared/ptyfwd.h12
-rw-r--r--src/shared/seccomp-util.c1
-rw-r--r--src/shared/sleep-config.c9
-rw-r--r--src/shared/spawn-ask-password-agent.c12
-rw-r--r--src/shared/spawn-polkit-agent.c10
-rw-r--r--src/shared/specifier.c6
-rw-r--r--src/shared/switch-root.c17
-rw-r--r--src/shared/sysctl-util.c14
-rw-r--r--src/shared/uid-range.c3
-rw-r--r--src/shared/utmp-wtmp.c12
-rw-r--r--src/shared/watchdog.c1
-rw-r--r--src/sleep/sleep.c18
-rw-r--r--src/socket-proxy/socket-proxyd.c17
-rw-r--r--src/sysctl/sysctl.c31
-rw-r--r--src/system-update-generator/system-update-generator.c2
-rw-r--r--src/systemctl/systemctl.c1810
-rw-r--r--src/systemd/sd-bus.h2
-rw-r--r--src/systemd/sd-daemon.h2
-rw-r--r--src/systemd/sd-device.h2
-rw-r--r--src/systemd/sd-dhcp-client.h10
-rw-r--r--src/systemd/sd-dhcp-lease.h10
-rw-r--r--src/systemd/sd-dhcp-server.h9
-rw-r--r--src/systemd/sd-dhcp6-client.h15
-rw-r--r--src/systemd/sd-dhcp6-lease.h7
-rw-r--r--src/systemd/sd-hwdb.h4
-rw-r--r--src/systemd/sd-icmp6-nd.h79
-rw-r--r--src/systemd/sd-ipv4acd.h8
-rw-r--r--src/systemd/sd-ipv4ll.h9
-rw-r--r--src/systemd/sd-lldp.h42
-rw-r--r--src/systemd/sd-ndisc.h77
-rw-r--r--src/systemd/sd-netlink.h5
-rw-r--r--src/systemd/sd-path.h6
-rw-r--r--src/systemd/sd-pppoe.h53
-rw-r--r--src/systemd/sd-resolve.h7
-rw-r--r--src/sysusers/sysusers.c81
-rw-r--r--src/sysv-generator/sysv-generator.c495
-rw-r--r--src/test/test-af-list.c7
-rw-r--r--src/test/test-arphrd-list.c5
-rw-r--r--src/test/test-async.c3
-rw-r--r--src/test/test-btrfs.c75
-rw-r--r--src/test/test-calendarspec.c49
-rw-r--r--src/test/test-cap-list.c11
-rw-r--r--src/test/test-capability.c14
-rw-r--r--src/test/test-cgroup-util.c11
-rw-r--r--src/test/test-cgroup.c3
-rw-r--r--src/test/test-condition.c18
-rw-r--r--src/test/test-conf-files.c8
-rw-r--r--src/test/test-conf-parser.c5
-rw-r--r--src/test/test-copy.c10
-rw-r--r--src/test/test-daemon.c17
-rw-r--r--src/test/test-date.c50
-rw-r--r--src/test/test-device-nodes.c2
-rw-r--r--src/test/test-dns-domain.c4
-rw-r--r--src/test/test-ellipsize.c6
-rw-r--r--src/test/test-env-replace.c11
-rw-r--r--src/test/test-execute.c95
-rw-r--r--src/test/test-extract-word.c546
-rw-r--r--src/test/test-fdset.c4
-rw-r--r--src/test/test-fileio.c22
-rw-r--r--src/test/test-fstab-util.c4
-rw-r--r--src/test/test-hashmap-plain.c10
-rw-r--r--src/test/test-hostname-util.c4
-rw-r--r--src/test/test-id128.c8
-rw-r--r--src/test/test-ipcrm.c3
-rw-r--r--src/test/test-json.c4
-rw-r--r--src/test/test-libudev.c6
-rw-r--r--src/test/test-namespace.c5
-rw-r--r--src/test/test-netlink-manual.c9
-rw-r--r--src/test/test-parse-util.c452
-rw-r--r--src/test/test-path-lookup.c26
-rw-r--r--src/test/test-path-util.c52
-rw-r--r--src/test/test-path.c16
-rw-r--r--src/test/test-prioq.c12
-rw-r--r--src/test/test-process-util.c12
-rw-r--r--src/test/test-replace-var.c3
-rw-r--r--src/test/test-sigbus.c3
-rw-r--r--src/test/test-siphash24.c70
-rw-r--r--src/test/test-socket-util.c11
-rw-r--r--src/test/test-strbuf.c1
-rw-r--r--src/test/test-string-util.c61
-rw-r--r--src/test/test-strip-tab-ansi.c3
-rw-r--r--src/test/test-strv.c90
-rw-r--r--src/test/test-strxcpyx.c3
-rw-r--r--src/test/test-tables.c13
-rw-r--r--src/test/test-terminal-util.c6
-rw-r--r--src/test/test-tmpfiles.c10
-rw-r--r--src/test/test-udev.c14
-rw-r--r--src/test/test-uid-range.c4
-rw-r--r--src/test/test-unit-file.c74
-rw-r--r--src/test/test-unit-name.c16
-rw-r--r--src/test/test-user-util.c54
-rw-r--r--src/test/test-utf8.c2
-rw-r--r--src/test/test-util.c900
-rw-r--r--src/test/test-xml.c4
-rw-r--r--src/timedate/timedatectl.c19
-rw-r--r--src/timedate/timedated.c23
-rw-r--r--src/timesync/timesyncd-conf.c26
-rw-r--r--src/timesync/timesyncd-manager.c33
-rw-r--r--src/timesync/timesyncd-server.c1
-rw-r--r--src/timesync/timesyncd.c19
-rw-r--r--src/tmpfiles/tmpfiles.c123
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c247
-rw-r--r--src/udev/.gitignore1
-rw-r--r--src/udev/ata_id/ata_id.c24
-rw-r--r--src/udev/cdrom_id/cdrom_id.c23
-rw-r--r--src/udev/collect/collect.c6
-rw-r--r--src/udev/net/ethtool-util.c8
-rw-r--r--src/udev/net/link-config.c28
-rw-r--r--src/udev/net/link-config.h6
-rw-r--r--src/udev/scsi_id/scsi_id.c19
-rw-r--r--src/udev/scsi_id/scsi_serial.c24
-rw-r--r--src/udev/udev-builtin-blkid.c14
-rw-r--r--src/udev/udev-builtin-btrfs.c4
-rw-r--r--src/udev/udev-builtin-hwdb.c8
-rw-r--r--src/udev/udev-builtin-input_id.c8
-rw-r--r--src/udev/udev-builtin-keyboard.c6
-rw-r--r--src/udev/udev-builtin-kmod.c7
-rw-r--r--src/udev/udev-builtin-net_id.c24
-rw-r--r--src/udev/udev-builtin-net_setup_link.c3
-rw-r--r--src/udev/udev-builtin-path_id.c16
-rw-r--r--src/udev/udev-builtin-uaccess.c6
-rw-r--r--src/udev/udev-builtin-usb_id.c13
-rw-r--r--src/udev/udev-builtin.c3
-rw-r--r--src/udev/udev-ctrl.c4
-rw-r--r--src/udev/udev-event.c27
-rw-r--r--src/udev/udev-node.c25
-rw-r--r--src/udev/udev-rules.c39
-rw-r--r--src/udev/udev.h11
-rw-r--r--src/udev/udevadm-hwdb.c15
-rw-r--r--src/udev/udevadm-info.c14
-rw-r--r--src/udev/udevadm-monitor.c5
-rw-r--r--src/udev/udevadm-settle.c8
-rw-r--r--src/udev/udevadm-test-builtin.c7
-rw-r--r--src/udev/udevadm-test.c13
-rw-r--r--src/udev/udevadm-trigger.c11
-rw-r--r--src/udev/udevadm-util.c1
-rw-r--r--src/udev/udevadm.c5
-rw-r--r--src/udev/udevd.c54
-rw-r--r--src/udev/v4l_id/v4l_id.c1
-rw-r--r--src/update-done/update-done.c4
-rw-r--r--src/update-utmp/update-utmp.c32
-rw-r--r--src/user-sessions/user-sessions.c5
-rw-r--r--src/vconsole/vconsole-setup.c27
744 files changed, 28586 insertions, 19809 deletions
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 5318829442..b7e6255f49 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -19,26 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
+#include <getopt.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
-#include <getopt.h>
+#include <unistd.h>
-#include "systemd/sd-daemon.h"
+#include "sd-daemon.h"
-#include "socket-util.h"
-#include "build.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "log.h"
-#include "strv.h"
#include "macro.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "strv.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
static char** arg_args = NULL;
static char** arg_setenv = NULL;
+static const char *arg_fdname = NULL;
static int add_epoll(int epoll_fd, int fd) {
struct epoll_event ev = {
@@ -137,8 +140,8 @@ static int launch(char* name, char **argv, char **env, int fds) {
length = strv_length(arg_setenv);
- /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
- envp = new0(char *, length + 7);
+ /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */
+ envp = new0(char *, length + 8);
if (!envp)
return log_oom();
@@ -146,7 +149,9 @@ static int launch(char* name, char **argv, char **env, int fds) {
if (strchr(*s, '='))
envp[n_env++] = *s;
else {
- _cleanup_free_ char *p = strappend(*s, "=");
+ _cleanup_free_ char *p;
+
+ p = strappend(*s, "=");
if (!p)
return log_oom();
envp[n_env] = strv_find_prefix(env, p);
@@ -165,15 +170,37 @@ static int launch(char* name, char **argv, char **env, int fds) {
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
return log_oom();
+ if (arg_fdname) {
+ char *e;
+
+ e = strappend("LISTEN_FDNAMES=", arg_fdname);
+ if (!e)
+ return log_oom();
+
+ for (i = 1; i < (unsigned) fds; i++) {
+ char *c;
+
+ c = strjoin(e, ":", arg_fdname, NULL);
+ if (!c) {
+ free(e);
+ return log_oom();
+ }
+
+ free(e);
+ e = c;
+ }
+
+ envp[n_env++] = e;
+ }
+
tmp = strv_join(argv, " ");
if (!tmp)
return log_oom();
log_info("Execing %s (%s)", name, tmp);
execvpe(name, argv, envp);
- log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
- return -errno;
+ return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
}
static int launch1(const char* child, char** argv, char **env, int fd) {
@@ -290,6 +317,7 @@ static void help(void) {
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
+ ARG_FDNAME,
};
static const struct option options[] = {
@@ -298,11 +326,12 @@ static int parse_argv(int argc, char *argv[]) {
{ "listen", required_argument, NULL, 'l' },
{ "accept", no_argument, NULL, 'a' },
{ "setenv", required_argument, NULL, 'E' },
- { "environment", required_argument, NULL, 'E' }, /* alias */
+ { "environment", required_argument, NULL, 'E' }, /* legacy alias */
+ { "fdname", required_argument, NULL, ARG_FDNAME },
{}
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -314,29 +343,34 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
- case 'l': {
- int r = strv_extend(&arg_listen, optarg);
+ case 'l':
+ r = strv_extend(&arg_listen, optarg);
if (r < 0)
- return r;
+ return log_oom();
break;
- }
case 'a':
arg_accept = true;
break;
- case 'E': {
- int r = strv_extend(&arg_setenv, optarg);
+ case 'E':
+ r = strv_extend(&arg_setenv, optarg);
if (r < 0)
- return r;
+ return log_oom();
break;
- }
+
+ case ARG_FDNAME:
+ if (!fdname_is_valid(optarg)) {
+ log_error("File descriptor name %s is not valid, refusing.", optarg);
+ return -EINVAL;
+ }
+
+ arg_fdname = optarg;
+ break;
case '?':
return -EINVAL;
diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c
index f4255f979e..a377996a37 100644
--- a/src/analyze/analyze-verify.c
+++ b/src/analyze/analyze-verify.c
@@ -21,12 +21,14 @@
#include <stdlib.h>
-#include "manager.h"
+#include "alloc-util.h"
+#include "analyze-verify.h"
#include "bus-util.h"
#include "log.h"
-#include "strv.h"
+#include "manager.h"
#include "pager.h"
-#include "analyze-verify.h"
+#include "path-util.h"
+#include "strv.h"
static int generate_path(char **var, char **filenames) {
char **filename;
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 3657ef50f1..27ead903e9 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -20,25 +20,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
#include <getopt.h>
#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "analyze-verify.h"
#include "bus-error.h"
-#include "log.h"
-#include "build.h"
-#include "util.h"
-#include "strxcpyx.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "special.h"
+#include "bus-util.h"
+#include "glob-util.h"
#include "hashmap.h"
+#include "locale-util.h"
+#include "log.h"
#include "pager.h"
-#include "analyze-verify.h"
+#include "parse-util.h"
+#include "special.h"
+#include "strv.h"
+#include "strxcpyx.h"
#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
@@ -318,6 +322,10 @@ finish:
}
static void free_host_info(struct host_info *hi) {
+
+ if (!hi)
+ return;
+
free(hi->hostname);
free(hi->kernel_name);
free(hi->kernel_release);
@@ -328,6 +336,8 @@ static void free_host_info(struct host_info *hi) {
free(hi);
}
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info);
+
static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -430,24 +440,25 @@ fail:
}
static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
- int r;
- struct host_info *host;
-
static const struct bus_properties_map hostname_map[] = {
- { "Hostname", "s", NULL, offsetof(struct host_info, hostname) },
- { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) },
- { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) },
- { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) },
+ { "Hostname", "s", NULL, offsetof(struct host_info, hostname) },
+ { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) },
+ { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) },
+ { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) },
{ "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) },
{}
};
static const struct bus_properties_map manager_map[] = {
- { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
- { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
+ { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
+ { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
{}
};
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(free_host_infop) struct host_info *host;
+ int r;
+
host = new0(struct host_info, 1);
if (!host)
return log_oom();
@@ -458,7 +469,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
hostname_map,
host);
if (r < 0)
- goto fail;
+ log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
@@ -466,13 +477,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
manager_map,
host);
if (r < 0)
- goto fail;
+ return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r));
*hi = host;
+ host = NULL;
+
return 0;
-fail:
- free_host_info(host);
- return r;
}
static int pretty_boot_time(sd_bus *bus, char **_buf) {
@@ -535,9 +545,9 @@ static void svg_graph_box(double height, double begin, double end) {
}
static int analyze_plot(sd_bus *bus) {
+ _cleanup_(free_host_infop) struct host_info *host = NULL;
struct unit_times *times;
struct boot_times *boot;
- struct host_info *host = NULL;
int n, m = 1, y=0;
double width;
_cleanup_free_ char *pretty_times = NULL;
@@ -557,7 +567,7 @@ static int analyze_plot(sd_bus *bus) {
n = acquire_time_data(bus, &times);
if (n <= 0)
- goto out;
+ return n;
qsort(times, n, sizeof(struct unit_times), compare_unit_start);
@@ -653,12 +663,12 @@ static int analyze_plot(sd_bus *bus) {
svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
- isempty(host->hostname) ? "" : host->hostname,
- isempty(host->kernel_name) ? "" : host->kernel_name,
- isempty(host->kernel_release) ? "" : host->kernel_release,
- isempty(host->kernel_version) ? "" : host->kernel_version,
- isempty(host->architecture) ? "" : host->architecture,
- isempty(host->virtualization) ? "" : host->virtualization);
+ strempty(host->hostname),
+ strempty(host->kernel_name),
+ strempty(host->kernel_release),
+ strempty(host->kernel_version),
+ strempty(host->architecture),
+ strempty(host->virtualization));
svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
@@ -742,8 +752,6 @@ static int analyze_plot(sd_bus *bus) {
free_unit_times(times, (unsigned) n);
n = 0;
-out:
- free_host_info(host);
return n;
}
@@ -1217,10 +1225,8 @@ static int dump(sd_bus *bus, char **args) {
&error,
&reply,
"");
- if (r < 0) {
- log_error("Failed issue method call: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed issue method call: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &text);
if (r < 0)
@@ -1251,11 +1257,36 @@ static int set_log_level(sd_bus *bus, char **args) {
&error,
"s",
args[0]);
- if (r < 0) {
- log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
- return -EIO;
+ if (r < 0)
+ return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
+static int set_log_target(sd_bus *bus, char **args) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(bus);
+ assert(args);
+
+ if (strv_length(args) != 1) {
+ log_error("This command expects one argument only.");
+ return -E2BIG;
}
+ r = sd_bus_set_property(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LogTarget",
+ &error,
+ "s",
+ args[0]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
+
return 0;
}
@@ -1285,7 +1316,8 @@ static void help(void) {
" critical-chain Print a tree of the time critical chain of units\n"
" plot Output SVG graphic showing service initialization\n"
" dot Output dependency graph in dot(1) format\n"
- " set-log-level LEVEL Set logging threshold for systemd\n"
+ " set-log-level LEVEL Set logging threshold for manager\n"
+ " set-log-target TARGET Set logging target for manager\n"
" dump Output state serialization of service manager\n"
" verify FILE... Check unit files for correctness\n"
, program_invocation_short_name);
@@ -1339,9 +1371,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USER:
arg_user = true;
@@ -1434,7 +1464,7 @@ int main(int argc, char *argv[]) {
else {
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
+ r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
@@ -1454,6 +1484,8 @@ int main(int argc, char *argv[]) {
r = dump(bus, argv+optind+1);
else if (streq(argv[optind], "set-log-level"))
r = set_log_level(bus, argv+optind+1);
+ else if (streq(argv[optind], "set-log-target"))
+ r = set_log_target(bus, argv+optind+1);
else
log_error("Unknown operation '%s'.", argv[optind]);
}
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index abfd545c79..a544866000 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -20,36 +20,36 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <getopt.h>
#include <stddef.h>
+#include <unistd.h>
+#include "ask-password-api.h"
+#include "def.h"
#include "log.h"
#include "macro.h"
#include "strv.h"
-#include "ask-password-api.h"
-#include "def.h"
static const char *arg_icon = NULL;
static const char *arg_id = NULL;
-static const char *arg_message = NULL;
-static bool arg_echo = false;
-static bool arg_use_tty = true;
+static const char *arg_keyname = NULL;
+static char *arg_message = NULL;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
-static bool arg_accept_cached = false;
static bool arg_multiple = false;
+static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
static void help(void) {
printf("%s [OPTIONS...] MESSAGE\n\n"
"Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
- " -h --help Show this help\n"
- " --icon=NAME Icon name\n"
- " --timeout=SEC Timeout in sec\n"
- " --echo Do not mask input (useful for usernames)\n"
- " --no-tty Ask question via agent even on TTY\n"
- " --accept-cached Accept cached passwords\n"
- " --multiple List multiple passwords if available\n"
- " --id=ID Query identifier (e.g. cryptsetup:/dev/sda5)\n"
+ " -h --help Show this help\n"
+ " --icon=NAME Icon name\n"
+ " --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
+ " --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
+ " --timeout=SEC Timeout in seconds\n"
+ " --echo Do not mask input (useful for usernames)\n"
+ " --no-tty Ask question via agent even on TTY\n"
+ " --accept-cached Accept cached passwords\n"
+ " --multiple List multiple passwords if available\n"
, program_invocation_short_name);
}
@@ -62,7 +62,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_TTY,
ARG_ACCEPT_CACHED,
ARG_MULTIPLE,
- ARG_ID
+ ARG_ID,
+ ARG_KEYNAME,
};
static const struct option options[] = {
@@ -74,6 +75,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
{ "multiple", no_argument, NULL, ARG_MULTIPLE },
{ "id", required_argument, NULL, ARG_ID },
+ { "keyname", required_argument, NULL, ARG_KEYNAME },
{}
};
@@ -102,15 +104,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ECHO:
- arg_echo = true;
+ arg_flags |= ASK_PASSWORD_ECHO;
break;
case ARG_NO_TTY:
- arg_use_tty = false;
+ arg_flags |= ASK_PASSWORD_NO_TTY;
break;
case ARG_ACCEPT_CACHED:
- arg_accept_cached = true;
+ arg_flags |= ASK_PASSWORD_ACCEPT_CACHED;
break;
case ARG_MULTIPLE:
@@ -121,6 +123,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_id = optarg;
break;
+ case ARG_KEYNAME:
+ arg_keyname = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -128,18 +134,20 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (optind != argc - 1) {
- log_error("%s: required argument missing.", program_invocation_short_name);
- return -EINVAL;
+ if (argc > optind) {
+ arg_message = strv_join(argv + optind, " ");
+ if (!arg_message)
+ return log_oom();
}
- arg_message = argv[optind];
return 1;
}
int main(int argc, char *argv[]) {
- int r;
+ _cleanup_strv_free_erase_ char **l = NULL;
usec_t timeout;
+ char **p;
+ int r;
log_parse_environment();
log_open();
@@ -153,36 +161,21 @@ int main(int argc, char *argv[]) {
else
timeout = 0;
- if (arg_use_tty && isatty(STDIN_FILENO)) {
- char *password = NULL;
-
- r = ask_password_tty(arg_message, timeout, arg_echo, NULL,
- &password);
- if (r >= 0) {
- puts(password);
- free(password);
- }
-
- } else {
- char **l;
-
- r = ask_password_agent(arg_message, arg_icon, arg_id, timeout,
- arg_echo, arg_accept_cached, &l);
- if (r >= 0) {
- char **p;
-
- STRV_FOREACH(p, l) {
- puts(*p);
+ r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l);
+ if (r < 0) {
+ log_error_errno(r, "Failed to query password: %m");
+ goto finish;
+ }
- if (!arg_multiple)
- break;
- }
+ STRV_FOREACH(p, l) {
+ puts(*p);
- strv_free(l);
- }
+ if (!arg_multiple)
+ break;
}
finish:
+ free(arg_message);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c
index c8961de946..b0fa079fec 100644
--- a/src/backlight/backlight.c
+++ b/src/backlight/backlight.c
@@ -19,12 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "mkdir.h"
-#include "fileio.h"
#include "libudev.h"
-#include "udev-util.h"
+
+#include "alloc-util.h"
#include "def.h"
+#include "escape.h"
+#include "fileio.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
+#include "udev-util.h"
+#include "util.h"
static struct udev_device *find_pci_or_platform_parent(struct udev_device *device) {
struct udev_device *parent;
@@ -375,7 +381,7 @@ int main(int argc, char *argv[]) {
_cleanup_free_ char *value = NULL;
const char *clamp;
- if (!shall_restore_state())
+ if (shall_restore_state() == 0)
return EXIT_SUCCESS;
if (!validate_device(udev, device))
diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c
new file mode 100644
index 0000000000..48183e381f
--- /dev/null
+++ b/src/basic/alloc-util.c
@@ -0,0 +1,81 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "util.h"
+
+void* memdup(const void *p, size_t l) {
+ void *r;
+
+ assert(p);
+
+ r = malloc(l);
+ if (!r)
+ return NULL;
+
+ memcpy(r, p, l);
+ return r;
+}
+
+void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
+ size_t a, newalloc;
+ void *q;
+
+ assert(p);
+ assert(allocated);
+
+ if (*allocated >= need)
+ return *p;
+
+ newalloc = MAX(need * 2, 64u / size);
+ a = newalloc * size;
+
+ /* check for overflows */
+ if (a < size * need)
+ return NULL;
+
+ q = realloc(*p, a);
+ if (!q)
+ return NULL;
+
+ *p = q;
+ *allocated = newalloc;
+ return q;
+}
+
+void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
+ size_t prev;
+ uint8_t *q;
+
+ assert(p);
+ assert(allocated);
+
+ prev = *allocated;
+
+ q = greedy_realloc(p, allocated, need, size);
+ if (!q)
+ return NULL;
+
+ if (*allocated > prev)
+ memzero(q + prev * size, (*allocated - prev) * size);
+
+ return q;
+}
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
new file mode 100644
index 0000000000..12b602e185
--- /dev/null
+++ b/src/basic/alloc-util.h
@@ -0,0 +1,108 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "macro.h"
+
+#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
+
+#define new0(t, n) ((t*) calloc((n), sizeof(t)))
+
+#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
+
+#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
+
+#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
+
+#define malloc0(n) (calloc(1, (n)))
+
+static inline void *mfree(void *memory) {
+ free(memory);
+ return NULL;
+}
+
+void* memdup(const void *p, size_t l) _alloc_(2);
+
+static inline void freep(void *p) {
+ free(*(void**) p);
+}
+
+#define _cleanup_free_ _cleanup_(freep)
+
+_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
+ if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+ return NULL;
+
+ return malloc(a * b);
+}
+
+_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
+ if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+ return NULL;
+
+ return realloc(p, a * b);
+}
+
+_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
+ if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
+ return NULL;
+
+ return memdup(p, a * b);
+}
+
+void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
+void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
+
+#define GREEDY_REALLOC(array, allocated, need) \
+ greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
+
+#define GREEDY_REALLOC0(array, allocated, need) \
+ greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
+
+#define alloca0(n) \
+ ({ \
+ char *_new_; \
+ size_t _len_ = n; \
+ _new_ = alloca(_len_); \
+ (void *) memset(_new_, 0, _len_); \
+ })
+
+/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
+#define alloca_align(size, align) \
+ ({ \
+ void *_ptr_; \
+ size_t _mask_ = (align) - 1; \
+ _ptr_ = alloca((size) + _mask_); \
+ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
+ })
+
+#define alloca0_align(size, align) \
+ ({ \
+ void *_new_; \
+ size_t _size_ = (size); \
+ _new_ = alloca_align(_size_, (align)); \
+ (void*)memset(_new_, 0, _size_); \
+ })
diff --git a/src/basic/async.c b/src/basic/async.c
index 7725e6d7d3..c3135f0efe 100644
--- a/src/basic/async.c
+++ b/src/basic/async.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include "async.h"
+#include "fd-util.h"
#include "log.h"
#include "util.h"
diff --git a/src/basic/audit.c b/src/basic/audit-util.c
index 1f593aa813..4612297334 100644
--- a/src/basic/audit.c
+++ b/src/basic/audit-util.c
@@ -22,11 +22,15 @@
#include <errno.h>
#include <stdio.h>
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "macro.h"
-#include "audit.h"
-#include "util.h"
+#include "parse-util.h"
#include "process-util.h"
-#include "fileio.h"
+#include "user-util.h"
+#include "util.h"
int audit_session_from_pid(pid_t pid, uint32_t *id) {
_cleanup_free_ char *s = NULL;
diff --git a/src/basic/audit.h b/src/basic/audit-util.h
index 6de331c73e..6de331c73e 100644
--- a/src/basic/audit.h
+++ b/src/basic/audit-util.h
diff --git a/src/basic/barrier.c b/src/basic/barrier.c
index 436ba95989..2d55bab4ab 100644
--- a/src/basic/barrier.c
+++ b/src/basic/barrier.c
@@ -30,6 +30,7 @@
#include <unistd.h>
#include "barrier.h"
+#include "fd-util.h"
#include "macro.h"
#include "util.h"
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
index 2eabf3e1c1..1449e2ea85 100644
--- a/src/basic/bitmap.c
+++ b/src/basic/bitmap.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-
+#include "alloc-util.h"
#include "bitmap.h"
+#include "util.h"
struct Bitmap {
uint64_t *bitmaps;
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 074deeccda..4c90bc0c80 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -20,23 +20,26 @@
***/
#include <stdlib.h>
-#include <sys/vfs.h>
#include <sys/stat.h>
-
+#include <sys/vfs.h>
#ifdef HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
+#include "alloc-util.h"
+#include "btrfs-ctree.h"
+#include "btrfs-util.h"
+#include "copy.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "macro.h"
#include "missing.h"
-#include "util.h"
#include "path-util.h"
-#include "macro.h"
-#include "copy.h"
#include "selinux-util.h"
#include "smack-util.h"
-#include "fileio.h"
-#include "btrfs-ctree.h"
-#include "btrfs-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
/* WARNING: Be careful with file system ioctls! When we get an fd, we
* need to make sure it either refers to only a regular file or
@@ -59,13 +62,13 @@ static int validate_subvolume_name(const char *name) {
static int open_parent(const char *path, int flags) {
_cleanup_free_ char *parent = NULL;
- int r, fd;
+ int fd;
assert(path);
- r = path_get_parent(path, &parent);
- if (r < 0)
- return r;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
fd = open(parent, flags);
if (fd < 0)
@@ -436,7 +439,7 @@ static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args
#define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \
((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header)))
-int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
+int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) {
struct btrfs_ioctl_search_args args = {
/* Tree of tree roots */
.key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
@@ -453,16 +456,23 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) {
.key.max_transid = (uint64_t) -1,
};
- uint64_t subvol_id;
bool found = false;
int r;
assert(fd >= 0);
assert(ret);
- r = btrfs_subvol_get_id_fd(fd, &subvol_id);
- if (r < 0)
- return r;
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+ if (r < 0)
+ return r;
+ } else {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+ }
args.key.min_objectid = args.key.max_objectid = subvol_id;
@@ -521,7 +531,7 @@ finish:
return 0;
}
-int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
+int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
struct btrfs_ioctl_search_args args = {
/* Tree of quota items */
@@ -540,18 +550,25 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
.key.max_transid = (uint64_t) -1,
};
- uint64_t subvol_id;
bool found_info = false, found_limit = false;
int r;
assert(fd >= 0);
assert(ret);
- r = btrfs_subvol_get_id_fd(fd, &subvol_id);
- if (r < 0)
- return r;
+ if (qgroupid == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+ if (r < 0)
+ return r;
+ } else {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+ }
- args.key.min_offset = args.key.max_offset = subvol_id;
+ args.key.min_offset = args.key.max_offset = qgroupid;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
const struct btrfs_ioctl_search_header *sh;
@@ -571,7 +588,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
if (sh->objectid != 0)
continue;
- if (sh->offset != subvol_id)
+ if (sh->offset != qgroupid)
continue;
if (sh->type == BTRFS_QGROUP_INFO_KEY) {
@@ -585,12 +602,14 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) {
} else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
- ret->referenced_max = le64toh(qli->max_rfer);
- ret->exclusive_max = le64toh(qli->max_excl);
-
- if (ret->referenced_max == 0)
+ if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER)
+ ret->referenced_max = le64toh(qli->max_rfer);
+ else
ret->referenced_max = (uint64_t) -1;
- if (ret->exclusive_max == 0)
+
+ if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL)
+ ret->exclusive_max = le64toh(qli->max_excl);
+ else
ret->exclusive_max = (uint64_t) -1;
found_limit = true;
@@ -622,6 +641,109 @@ finish:
return 0;
}
+int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
+}
+
+int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) {
+ uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0;
+ _cleanup_free_ uint64_t *qgroups = NULL;
+ int r, n, i;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ /* This finds the "subtree" qgroup for a specific
+ * subvolume. This only works for subvolumes that have been
+ * prepared with btrfs_subvol_auto_qgroup_fd() with
+ * insert_intermediary_qgroup=true (or equivalent). For others
+ * it will return the leaf qgroup instead. The two cases may
+ * be distuingished via the return value, which is 1 in case
+ * an appropriate "subtree" qgroup was found, and 0
+ * otherwise. */
+
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+ if (r < 0)
+ return r;
+ }
+
+ r = btrfs_qgroupid_split(subvol_id, &level, NULL);
+ if (r < 0)
+ return r;
+ if (level != 0) /* Input must be a leaf qgroup */
+ return -EINVAL;
+
+ n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
+ if (n < 0)
+ return n;
+
+ for (i = 0; i < n; i++) {
+ uint64_t id;
+
+ r = btrfs_qgroupid_split(qgroups[i], &level, &id);
+ if (r < 0)
+ return r;
+
+ if (id != subvol_id)
+ continue;
+
+ if (lowest == (uint64_t) -1 || level < lowest) {
+ lowest_qgroupid = qgroups[i];
+ lowest = level;
+ }
+ }
+
+ if (lowest == (uint64_t) -1) {
+ /* No suitable higher-level qgroup found, let's return
+ * the leaf qgroup instead, and indicate that with the
+ * return value. */
+
+ *ret = subvol_id;
+ return 0;
+ }
+
+ *ret = lowest_qgroupid;
+ return 1;
+}
+
+int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
+ uint64_t qgroupid;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ /* This determines the quota data of the qgroup with the
+ * lowest level, that shares the id part with the specified
+ * subvolume. This is useful for determining the quota data
+ * for entire subvolume subtrees, as long as the subtrees have
+ * been set up with btrfs_qgroup_subvol_auto_fd() or in a
+ * compatible way */
+
+ r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
+ if (r < 0)
+ return r;
+
+ return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret);
+}
+
+int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret);
+}
+
int btrfs_defrag_fd(int fd) {
struct stat st;
@@ -679,37 +801,79 @@ int btrfs_quota_enable(const char *path, bool b) {
return btrfs_quota_enable_fd(fd, b);
}
-int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) {
+int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) {
+
struct btrfs_ioctl_qgroup_limit_args args = {
- .lim.max_rfer =
- referenced_max == (uint64_t) -1 ? 0 :
- referenced_max == 0 ? 1 : referenced_max,
+ .lim.max_rfer = referenced_max,
.lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
};
+ unsigned c;
int r;
assert(fd >= 0);
- r = btrfs_is_filesystem(fd);
- if (r < 0)
- return r;
- if (!r)
- return -ENOTTY;
+ if (qgroupid == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+ if (r < 0)
+ return r;
+ } else {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+ }
- if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
- return -errno;
+ args.qgroupid = qgroupid;
+
+ for (c = 0;; c++) {
+ if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) {
+
+ if (errno == EBUSY && c < 10) {
+ (void) btrfs_quota_scan_wait(fd);
+ continue;
+ }
+
+ return -errno;
+ }
+
+ break;
+ }
return 0;
}
-int btrfs_quota_limit(const char *path, uint64_t referenced_max) {
+int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
+}
+
+int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) {
+ uint64_t qgroupid;
+ int r;
+
+ assert(fd >= 0);
+
+ r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid);
+ if (r < 0)
+ return r;
+
+ return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max);
+}
+
+int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) {
_cleanup_close_ int fd = -1;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd < 0)
return -errno;
- return btrfs_quota_limit_fd(fd, referenced_max);
+ return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max);
}
int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
@@ -799,7 +963,188 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
return btrfs_resize_loopback_fd(fd, new_size, grow_only);
}
-static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
+int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) {
+ assert(ret);
+
+ if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT)))
+ return -EINVAL;
+
+ if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT))
+ return -EINVAL;
+
+ *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
+ return 0;
+}
+
+int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) {
+ assert(level || id);
+
+ if (level)
+ *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT;
+
+ if (id)
+ *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1);
+
+ return 0;
+}
+
+static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) {
+
+ struct btrfs_ioctl_qgroup_create_args args = {
+ .create = b,
+ .qgroupid = qgroupid,
+ };
+ unsigned c;
+ int r;
+
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOTTY;
+
+ for (c = 0;; c++) {
+ if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) {
+
+ if (errno == EBUSY && c < 10) {
+ (void) btrfs_quota_scan_wait(fd);
+ continue;
+ }
+
+ return -errno;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+int btrfs_qgroup_create(int fd, uint64_t qgroupid) {
+ return qgroup_create_or_destroy(fd, true, qgroupid);
+}
+
+int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) {
+ return qgroup_create_or_destroy(fd, false, qgroupid);
+}
+
+int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) {
+ _cleanup_free_ uint64_t *qgroups = NULL;
+ uint64_t subvol_id;
+ int i, n, r;
+
+ /* Destroys the specified qgroup, but unassigns it from all
+ * its parents first. Also, it recursively destroys all
+ * qgroups it is assgined to that have the same id part of the
+ * qgroupid as the specified group. */
+
+ r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id);
+ if (r < 0)
+ return r;
+
+ n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups);
+ if (n < 0)
+ return n;
+
+ for (i = 0; i < n; i++) {
+ uint64_t id;
+
+ r = btrfs_qgroupid_split(qgroups[i], NULL, &id);
+ if (r < 0)
+ return r;
+
+ r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]);
+ if (r < 0)
+ return r;
+
+ if (id != subvol_id)
+ continue;
+
+ /* The parent qgroupid shares the same id part with
+ * us? If so, destroy it too. */
+
+ (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]);
+ }
+
+ return btrfs_qgroup_destroy(fd, qgroupid);
+}
+
+int btrfs_quota_scan_start(int fd) {
+ struct btrfs_ioctl_quota_rescan_args args = {};
+
+ assert(fd >= 0);
+
+ if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_quota_scan_wait(int fd) {
+ assert(fd >= 0);
+
+ if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_quota_scan_ongoing(int fd) {
+ struct btrfs_ioctl_quota_rescan_args args = {};
+
+ assert(fd >= 0);
+
+ if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0)
+ return -errno;
+
+ return !!args.flags;
+}
+
+static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) {
+ struct btrfs_ioctl_qgroup_assign_args args = {
+ .assign = b,
+ .src = child,
+ .dst = parent,
+ };
+ unsigned c;
+ int r;
+
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOTTY;
+
+ for (c = 0;; c++) {
+ r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
+ if (r < 0) {
+ if (errno == EBUSY && c < 10) {
+ (void) btrfs_quota_scan_wait(fd);
+ continue;
+ }
+
+ return -errno;
+ }
+
+ if (r == 0)
+ return 0;
+
+ /* If the return value is > 0, we need to request a rescan */
+
+ (void) btrfs_quota_scan_start(fd);
+ return 1;
+ }
+}
+
+int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) {
+ return qgroup_assign_or_unassign(fd, true, child, parent);
+}
+
+int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) {
+ return qgroup_assign_or_unassign(fd, false, child, parent);
+}
+
+static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) {
struct btrfs_ioctl_search_args args = {
.key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
@@ -828,16 +1173,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (!S_ISDIR(st.st_mode))
return -EINVAL;
- /* First, try to remove the subvolume. If it happens to be
- * already empty, this will just work. */
- strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
- if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
- return 0;
- if (!recursive || errno != ENOTEMPTY)
- return -errno;
-
- /* OK, the subvolume is not empty, let's look for child
- * subvolumes, and remove them, first */
subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (subvol_fd < 0)
return -errno;
@@ -848,6 +1183,19 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
return r;
}
+ /* First, try to remove the subvolume. If it happens to be
+ * already empty, this will just work. */
+ strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
+ (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */
+ return 0;
+ }
+ if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY)
+ return -errno;
+
+ /* OK, the subvolume is not empty, let's look for child
+ * subvolumes, and remove them, first */
+
args.key.min_offset = args.key.max_offset = subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
@@ -897,7 +1245,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (isempty(ino_args.name))
/* Subvolume is in the top-level
* directory of the subvolume. */
- r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive);
+ r = subvol_remove_children(subvol_fd, p, sh->objectid, flags);
else {
_cleanup_close_ int child_fd = -1;
@@ -909,7 +1257,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (child_fd < 0)
return -errno;
- r = subvol_remove_children(child_fd, p, sh->objectid, recursive);
+ r = subvol_remove_children(child_fd, p, sh->objectid, flags);
}
if (r < 0)
return r;
@@ -925,10 +1273,11 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
return -errno;
+ (void) btrfs_qgroup_destroy_recursive(fd, subvol_id);
return 0;
}
-int btrfs_subvol_remove(const char *path, bool recursive) {
+int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) {
_cleanup_close_ int fd = -1;
const char *subvolume;
int r;
@@ -943,11 +1292,194 @@ int btrfs_subvol_remove(const char *path, bool recursive) {
if (fd < 0)
return fd;
- return subvol_remove_children(fd, subvolume, 0, recursive);
+ return subvol_remove_children(fd, subvolume, 0, flags);
+}
+
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) {
+ return subvol_remove_children(fd, subvolume, 0, flags);
+}
+
+int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) {
+
+ struct btrfs_ioctl_search_args args = {
+ /* Tree of quota items */
+ .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+
+ /* The object ID is always 0 */
+ .key.min_objectid = 0,
+ .key.max_objectid = 0,
+
+ /* Look precisely for the quota items */
+ .key.min_type = BTRFS_QGROUP_LIMIT_KEY,
+ .key.max_type = BTRFS_QGROUP_LIMIT_KEY,
+
+ /* For our qgroup */
+ .key.min_offset = old_qgroupid,
+ .key.max_offset = old_qgroupid,
+
+ /* No restrictions on the other components */
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+
+ int r;
+
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+ const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh);
+ struct btrfs_ioctl_qgroup_limit_args qargs;
+ unsigned c;
+
+ /* Make sure we start the next search at least from this entry */
+ btrfs_ioctl_search_args_set(&args, sh);
+
+ if (sh->objectid != 0)
+ continue;
+ if (sh->type != BTRFS_QGROUP_LIMIT_KEY)
+ continue;
+ if (sh->offset != old_qgroupid)
+ continue;
+
+ /* We found the entry, now copy things over. */
+
+ qargs = (struct btrfs_ioctl_qgroup_limit_args) {
+ .qgroupid = new_qgroupid,
+
+ .lim.max_rfer = le64toh(qli->max_rfer),
+ .lim.max_excl = le64toh(qli->max_excl),
+ .lim.rsv_rfer = le64toh(qli->rsv_rfer),
+ .lim.rsv_excl = le64toh(qli->rsv_excl),
+
+ .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER|
+ BTRFS_QGROUP_LIMIT_MAX_EXCL|
+ BTRFS_QGROUP_LIMIT_RSV_RFER|
+ BTRFS_QGROUP_LIMIT_RSV_EXCL),
+ };
+
+ for (c = 0;; c++) {
+ if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) {
+ if (errno == EBUSY && c < 10) {
+ (void) btrfs_quota_scan_wait(fd);
+ continue;
+ }
+ return -errno;
+ }
+
+ break;
+ }
+
+ return 1;
+ }
+
+ /* Increase search key by one, to read the next item, if we can. */
+ if (!btrfs_ioctl_search_args_inc(&args))
+ break;
+ }
+
+ return 0;
+}
+
+static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) {
+ _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL;
+ bool copy_from_parent = false, insert_intermediary_qgroup = false;
+ int n_old_qgroups, n_old_parent_qgroups, r, i;
+ uint64_t old_parent_id;
+
+ assert(fd >= 0);
+
+ /* Copies a reduced form of quota information from the old to
+ * the new subvolume. */
+
+ n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups);
+ if (n_old_qgroups <= 0) /* Nothing to copy */
+ return n_old_qgroups;
+
+ r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id);
+ if (r < 0)
+ return r;
+
+ n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups);
+ if (n_old_parent_qgroups < 0)
+ return n_old_parent_qgroups;
+
+ for (i = 0; i < n_old_qgroups; i++) {
+ uint64_t id;
+ int j;
+
+ r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id);
+ if (r < 0)
+ return r;
+
+ if (id == old_subvol_id) {
+ /* The old subvolume was member of a qgroup
+ * that had the same id, but a different level
+ * as it self. Let's set up something similar
+ * in the destination. */
+ insert_intermediary_qgroup = true;
+ break;
+ }
+
+ for (j = 0; j < n_old_parent_qgroups; j++)
+ if (old_parent_qgroups[j] == old_qgroups[i]) {
+ /* The old subvolume shared a common
+ * parent qgroup with its parent
+ * subvolume. Let's set up something
+ * similar in the destination. */
+ copy_from_parent = true;
+ }
+ }
+
+ if (!insert_intermediary_qgroup && !copy_from_parent)
+ return 0;
+
+ return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup);
}
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) {
- return subvol_remove_children(fd, subvolume, 0, recursive);
+static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) {
+ uint64_t old_subtree_qgroup, new_subtree_qgroup;
+ bool changed;
+ int r;
+
+ /* First copy the leaf limits */
+ r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol);
+ if (r < 0)
+ return r;
+ changed = r > 0;
+
+ /* Then, try to copy the subtree limits, if there are any. */
+ r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return changed;
+
+ r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return changed;
+
+ r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup);
+ if (r != 0)
+ return r;
+
+ return changed;
}
static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) {
@@ -978,12 +1510,12 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
assert(subvolume);
strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
- vol_args.fd = old_fd;
if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0)
return -errno;
- if (!(flags & BTRFS_SNAPSHOT_RECURSIVE))
+ if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) &&
+ !(flags & BTRFS_SNAPSHOT_QUOTA))
return 0;
if (old_subvol_id == 0) {
@@ -996,6 +1528,17 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
if (r < 0)
return r;
+ if (flags & BTRFS_SNAPSHOT_QUOTA)
+ (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id);
+
+ if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) {
+
+ if (flags & BTRFS_SNAPSHOT_QUOTA)
+ (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
+
+ return 0;
+ }
+
args.key.min_offset = args.key.max_offset = old_subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
@@ -1113,6 +1656,9 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum
break;
}
+ if (flags & BTRFS_SNAPSHOT_QUOTA)
+ (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id);
+
return 0;
}
@@ -1137,14 +1683,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
r = copy_directory_fd(old_fd, new_path, true);
if (r < 0) {
- btrfs_subvol_remove(new_path, false);
+ (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
return r;
}
if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
r = btrfs_subvol_set_read_only(new_path, true);
if (r < 0) {
- btrfs_subvol_remove(new_path, false);
+ (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
return r;
}
}
@@ -1175,3 +1721,302 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnaps
return btrfs_subvol_snapshot_fd(old_fd, new_path, flags);
}
+
+int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) {
+
+ struct btrfs_ioctl_search_args args = {
+ /* Tree of quota items */
+ .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID,
+
+ /* Look precisely for the quota relation items */
+ .key.min_type = BTRFS_QGROUP_RELATION_KEY,
+ .key.max_type = BTRFS_QGROUP_RELATION_KEY,
+
+ /* No restrictions on the other components */
+ .key.min_offset = 0,
+ .key.max_offset = (uint64_t) -1,
+
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+
+ _cleanup_free_ uint64_t *items = NULL;
+ size_t n_items = 0, n_allocated = 0;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ if (qgroupid == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &qgroupid);
+ if (r < 0)
+ return r;
+ } else {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+ }
+
+ args.key.min_objectid = args.key.max_objectid = qgroupid;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+
+ /* Make sure we start the next search at least from this entry */
+ btrfs_ioctl_search_args_set(&args, sh);
+
+ if (sh->type != BTRFS_QGROUP_RELATION_KEY)
+ continue;
+ if (sh->offset < sh->objectid)
+ continue;
+ if (sh->objectid != qgroupid)
+ continue;
+
+ if (!GREEDY_REALLOC(items, n_allocated, n_items+1))
+ return -ENOMEM;
+
+ items[n_items++] = sh->offset;
+ }
+
+ /* Increase search key by one, to read the next item, if we can. */
+ if (!btrfs_ioctl_search_args_inc(&args))
+ break;
+ }
+
+ if (n_items <= 0) {
+ *ret = NULL;
+ return 0;
+ }
+
+ *ret = items;
+ items = NULL;
+
+ return (int) n_items;
+}
+
+int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) {
+ _cleanup_free_ uint64_t *qgroups = NULL;
+ uint64_t parent_subvol;
+ bool changed = false;
+ int n = 0, r;
+
+ assert(fd >= 0);
+
+ /*
+ * Sets up the specified subvolume's qgroup automatically in
+ * one of two ways:
+ *
+ * If insert_intermediary_qgroup is false, the subvolume's
+ * leaf qgroup will be assigned to the same parent qgroups as
+ * the subvolume's parent subvolume.
+ *
+ * If insert_intermediary_qgroup is true a new intermediary
+ * higher-level qgroup is created, with a higher level number,
+ * but reusing the id of the subvolume. The level number is
+ * picked as one smaller than the lowest level qgroup the
+ * parent subvolume is a member of. If the parent subvolume's
+ * leaf qgroup is assigned to no higher-level qgroup a new
+ * qgroup of level 255 is created instead. Either way, the new
+ * qgroup is then assigned to the parent's higher-level
+ * qgroup, and the subvolume itself is assigned to it.
+ *
+ * If the subvolume is already assigned to a higher level
+ * qgroup, no operation is executed.
+ *
+ * Effectively this means: regardless if
+ * insert_intermediary_qgroup is true or not, after this
+ * function is invoked the subvolume will be accounted within
+ * the same qgroups as the parent. However, if it is true, it
+ * will also get its own higher-level qgroup, which may in
+ * turn be used by subvolumes created beneath this subvolume
+ * later on.
+ *
+ * This hence defines a simple default qgroup setup for
+ * subvolumes, as long as this function is invoked on each
+ * created subvolume: each subvolume is always accounting
+ * together with its immediate parents. Optionally, if
+ * insert_intermediary_qgroup is true, it will also get a
+ * qgroup that then includes all its own child subvolumes.
+ */
+
+ if (subvol_id == 0) {
+ r = btrfs_is_subvol(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+
+ r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+ if (r < 0)
+ return r;
+ }
+
+ n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups);
+ if (n < 0)
+ return n;
+ if (n > 0) /* already parent qgroups set up, let's bail */
+ return 0;
+
+ r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol);
+ if (r < 0)
+ return r;
+
+ qgroups = mfree(qgroups);
+ n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups);
+ if (n < 0)
+ return n;
+
+ if (insert_intermediary_qgroup) {
+ uint64_t lowest = 256, new_qgroupid;
+ bool created = false;
+ int i;
+
+ /* Determine the lowest qgroup that the parent
+ * subvolume is assigned to. */
+
+ for (i = 0; i < n; i++) {
+ uint64_t level;
+
+ r = btrfs_qgroupid_split(qgroups[i], &level, NULL);
+ if (r < 0)
+ return r;
+
+ if (level < lowest)
+ lowest = level;
+ }
+
+ if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */
+ return -EBUSY;
+
+ r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid);
+ if (r < 0)
+ return r;
+
+ /* Create the new intermediary group, unless it already exists */
+ r = btrfs_qgroup_create(fd, new_qgroupid);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ if (r >= 0)
+ changed = created = true;
+
+ for (i = 0; i < n; i++) {
+ r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]);
+ if (r < 0 && r != -EEXIST) {
+ if (created)
+ (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
+
+ return r;
+ }
+ if (r >= 0)
+ changed = true;
+ }
+
+ r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid);
+ if (r < 0 && r != -EEXIST) {
+ if (created)
+ (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid);
+ return r;
+ }
+ if (r >= 0)
+ changed = true;
+
+ } else {
+ int i;
+
+ /* Assign our subvolume to all the same qgroups as the parent */
+
+ for (i = 0; i < n; i++) {
+ r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]);
+ if (r < 0 && r != -EEXIST)
+ return r;
+ if (r >= 0)
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return -errno;
+
+ return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup);
+}
+
+int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
+
+ struct btrfs_ioctl_search_args args = {
+ /* Tree of tree roots */
+ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
+
+ /* Look precisely for the subvolume items */
+ .key.min_type = BTRFS_ROOT_BACKREF_KEY,
+ .key.max_type = BTRFS_ROOT_BACKREF_KEY,
+
+ /* No restrictions on the other components */
+ .key.min_offset = 0,
+ .key.max_offset = (uint64_t) -1,
+
+ .key.min_transid = 0,
+ .key.max_transid = (uint64_t) -1,
+ };
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ if (subvol_id == 0) {
+ r = btrfs_subvol_get_id_fd(fd, &subvol_id);
+ if (r < 0)
+ return r;
+ } else {
+ r = btrfs_is_filesystem(fd);
+ if (r < 0)
+ return r;
+ if (!r)
+ return -ENOTTY;
+ }
+
+ args.key.min_objectid = args.key.max_objectid = subvol_id;
+
+ while (btrfs_ioctl_search_args_compare(&args) <= 0) {
+ const struct btrfs_ioctl_search_header *sh;
+ unsigned i;
+
+ args.key.nr_items = 256;
+ if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
+ return -errno;
+
+ if (args.key.nr_items <= 0)
+ break;
+
+ FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) {
+
+ if (sh->type != BTRFS_ROOT_BACKREF_KEY)
+ continue;
+ if (sh->objectid != subvol_id)
+ continue;
+
+ *ret = sh->offset;
+ return 0;
+ }
+ }
+
+ return -ENXIO;
+}
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index 8632c3638c..fc9efd72d5 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -47,42 +47,82 @@ typedef enum BtrfsSnapshotFlags {
BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
BTRFS_SNAPSHOT_READ_ONLY = 2,
BTRFS_SNAPSHOT_RECURSIVE = 4,
+ BTRFS_SNAPSHOT_QUOTA = 8,
} BtrfsSnapshotFlags;
+typedef enum BtrfsRemoveFlags {
+ BTRFS_REMOVE_RECURSIVE = 1,
+ BTRFS_REMOVE_QUOTA = 2,
+} BtrfsRemoveFlags;
+
int btrfs_is_filesystem(int fd);
int btrfs_is_subvol(int fd);
+int btrfs_reflink(int infd, int outfd);
+int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
+
+int btrfs_get_block_device_fd(int fd, dev_t *dev);
+int btrfs_get_block_device(const char *path, dev_t *dev);
+
+int btrfs_defrag_fd(int fd);
+int btrfs_defrag(const char *p);
+
+int btrfs_quota_enable_fd(int fd, bool b);
+int btrfs_quota_enable(const char *path, bool b);
+
+int btrfs_quota_scan_start(int fd);
+int btrfs_quota_scan_wait(int fd);
+int btrfs_quota_scan_ongoing(int fd);
+
+int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
+int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+
int btrfs_subvol_make(const char *path);
int btrfs_subvol_make_label(const char *path);
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
+int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
+int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
+
int btrfs_subvol_set_read_only_fd(int fd, bool b);
int btrfs_subvol_set_read_only(const char *path, bool b);
int btrfs_subvol_get_read_only_fd(int fd);
+
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
-int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info);
-int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota);
+int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret);
-int btrfs_reflink(int infd, int outfd);
-int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
+int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info);
-int btrfs_get_block_device_fd(int fd, dev_t *dev);
-int btrfs_get_block_device(const char *path, dev_t *dev);
+int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret);
-int btrfs_defrag_fd(int fd);
-int btrfs_defrag(const char *p);
+int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota);
+int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota);
-int btrfs_quota_enable_fd(int fd, bool b);
-int btrfs_quota_enable(const char *path, bool b);
+int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max);
+int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max);
-int btrfs_quota_limit_fd(int fd, uint64_t referenced_max);
-int btrfs_quota_limit(const char *path, uint64_t referenced_max);
+int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup);
+int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup);
-int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
-int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
+int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret);
+int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id);
+
+int btrfs_qgroup_create(int fd, uint64_t qgroupid);
+int btrfs_qgroup_destroy(int fd, uint64_t qgroupid);
+int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid);
+
+int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max);
+int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max);
+
+int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid);
+
+int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent);
+int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent);
+
+int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret);
-int btrfs_subvol_remove(const char *path, bool recursive);
-int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
+int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota);
+int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota);
diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c
index ccc9f2bf8e..c1534657ac 100644
--- a/src/basic/bus-label.c
+++ b/src/basic/bus-label.c
@@ -21,10 +21,11 @@
#include <stdlib.h>
-#include "util.h"
-#include "macro.h"
-
+#include "alloc-util.h"
#include "bus-label.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "util.h"
char *bus_label_escape(const char *s) {
char *r, *t;
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 2dcc9c5575..a6a906f453 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -22,7 +22,10 @@
#include <stdlib.h>
#include <string.h>
+#include "alloc-util.h"
+#include "string-util.h"
#include "calendarspec.h"
+#include "fileio.h"
#define BITS_WEEKDAYS 127
@@ -279,6 +282,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
fputc(':', f);
format_chain(f, 2, c->second);
+ if (c->utc)
+ fputs(" UTC", f);
+
r = fflush_and_check(f);
if (r < 0) {
free(buf);
@@ -646,6 +652,7 @@ fail:
int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
CalendarSpec *c;
int r;
+ const char *utc;
assert(p);
assert(spec);
@@ -657,6 +664,12 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (!c)
return -ENOMEM;
+ utc = endswith_no_case(p, " UTC");
+ if (utc) {
+ c->utc = true;
+ p = strndupa(p, utc - p);
+ }
+
if (strcaseeq(p, "minutely")) {
r = const_chain(0, &c->second);
if (r < 0)
@@ -859,13 +872,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) {
return r;
}
-static bool tm_out_of_bounds(const struct tm *tm) {
+static bool tm_out_of_bounds(const struct tm *tm, bool utc) {
struct tm t;
assert(tm);
t = *tm;
- if (mktime(&t) == (time_t) -1)
+ if (mktime_or_timegm(&t, utc) == (time_t) -1)
return true;
/* Did any normalization take place? If so, it was out of bounds before */
@@ -878,7 +891,7 @@ static bool tm_out_of_bounds(const struct tm *tm) {
t.tm_sec != tm->tm_sec;
}
-static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
+static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
struct tm t;
int k;
@@ -886,7 +899,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
return true;
t = *tm;
- if (mktime(&t) == (time_t) -1)
+ if (mktime_or_timegm(&t, utc) == (time_t) -1)
return false;
k = t.tm_wday == 0 ? 6 : t.tm_wday - 1;
@@ -904,7 +917,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
for (;;) {
/* Normalize the current date */
- mktime(&c);
+ mktime_or_timegm(&c, spec->utc);
c.tm_isdst = -1;
c.tm_year += 1900;
@@ -916,7 +929,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
}
- if (r < 0 || tm_out_of_bounds(&c))
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc))
return r;
c.tm_mon += 1;
@@ -927,7 +940,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
}
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_year ++;
c.tm_mon = 0;
c.tm_mday = 1;
@@ -938,14 +951,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->day, &c.tm_mday);
if (r > 0)
c.tm_hour = c.tm_min = c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mon ++;
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
}
- if (!matches_weekday(spec->weekdays_bits, &c)) {
+ if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
c.tm_mday++;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
@@ -954,7 +967,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->hour, &c.tm_hour);
if (r > 0)
c.tm_min = c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mday ++;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
@@ -963,14 +976,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->minute, &c.tm_min);
if (r > 0)
c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_hour ++;
c.tm_min = c.tm_sec = 0;
continue;
}
r = find_matching_component(spec->second, &c.tm_sec);
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_min ++;
c.tm_sec = 0;
continue;
@@ -991,13 +1004,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
assert(next);
t = (time_t) (usec / USEC_PER_SEC) + 1;
- assert_se(localtime_r(&t, &tm));
+ assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
r = find_next(spec, &tm);
if (r < 0)
return r;
- t = mktime(&tm);
+ t = mktime_or_timegm(&tm, spec->utc);
if (t == (time_t) -1)
return -EINVAL;
diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h
index 7baf318249..56dc02f391 100644
--- a/src/basic/calendarspec.h
+++ b/src/basic/calendarspec.h
@@ -36,6 +36,7 @@ typedef struct CalendarComponent {
typedef struct CalendarSpec {
int weekdays_bits;
+ bool utc;
CalendarComponent *year;
CalendarComponent *month;
diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c
index bd5bffbfa5..4d391510bc 100644
--- a/src/basic/cap-list.c
+++ b/src/basic/cap-list.c
@@ -21,9 +21,10 @@
#include <string.h>
-#include "util.h"
#include "cap-list.h"
#include "missing.h"
+#include "parse-util.h"
+#include "util.h"
static const struct capability_name* lookup_capability(register const char *str, register unsigned int len);
diff --git a/src/basic/capability.c b/src/basic/capability-util.c
index 8dbe4da5bb..0eb5c03d65 100644
--- a/src/basic/capability.c
+++ b/src/basic/capability-util.c
@@ -19,18 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
+#include <grp.h>
#include <stdio.h>
#include <sys/capability.h>
#include <sys/prctl.h>
-#include "grp.h"
+#include <unistd.h>
+#include "alloc-util.h"
+#include "capability-util.h"
+#include "fileio.h"
+#include "log.h"
#include "macro.h"
+#include "parse-util.h"
#include "util.h"
-#include "log.h"
-#include "fileio.h"
-#include "capability.h"
int have_effective_cap(int value) {
_cleanup_cap_free_ cap_t cap;
@@ -276,10 +278,8 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
assert(keep_capabilities & (1ULL << (i - 1)));
if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
- cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) {
- log_error_errno(errno, "Failed to enable capabilities bits: %m");
- return -errno;
- }
+ cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
+ return log_error_errno(errno, "Failed to enable capabilities bits: %m");
if (cap_set_proc(d) < 0)
return log_error_errno(errno, "Failed to increase capabilities: %m");
diff --git a/src/basic/capability.h b/src/basic/capability-util.h
index 4eb5c2a835..4eb5c2a835 100644
--- a/src/basic/capability.h
+++ b/src/basic/capability-util.h
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 95fc2b9e5d..f7fc2c2c97 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -19,28 +19,39 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <dirent.h>
#include <errno.h>
-#include <unistd.h>
+#include <ftw.h>
#include <signal.h>
-#include <string.h>
#include <stdlib.h>
-#include <dirent.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <ftw.h>
+#include <unistd.h>
-#include "set.h"
-#include "macro.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "dirent-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
-#include "process-util.h"
+#include "fs-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "unit-name.h"
-#include "fileio.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "set.h"
#include "special.h"
-#include "mkdir.h"
-#include "login-util.h"
-#include "cgroup-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
_cleanup_free_ char *fs = NULL;
diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c
new file mode 100644
index 0000000000..d49ca0537a
--- /dev/null
+++ b/src/basic/chattr-util.c
@@ -0,0 +1,107 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/fs.h>
+
+#include "chattr-util.h"
+#include "fd-util.h"
+#include "util.h"
+
+int chattr_fd(int fd, unsigned value, unsigned mask) {
+ unsigned old_attr, new_attr;
+ struct stat st;
+
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ /* Explicitly check whether this is a regular file or
+ * directory. If it is anything else (such as a device node or
+ * fifo), then the ioctl will not hit the file systems but
+ * possibly drivers, where the ioctl might have different
+ * effects. Notably, DRM is using the same ioctl() number. */
+
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
+
+ if (mask == 0)
+ return 0;
+
+ if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
+ return -errno;
+
+ new_attr = (old_attr & ~mask) | (value & mask);
+ if (new_attr == old_attr)
+ return 0;
+
+ if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+ return -errno;
+
+ return 1;
+}
+
+int chattr_path(const char *p, unsigned value, unsigned mask) {
+ _cleanup_close_ int fd = -1;
+
+ assert(p);
+
+ if (mask == 0)
+ return 0;
+
+ fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return chattr_fd(fd, value, mask);
+}
+
+int read_attr_fd(int fd, unsigned *ret) {
+ struct stat st;
+
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
+
+ if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int read_attr_path(const char *p, unsigned *ret) {
+ _cleanup_close_ int fd = -1;
+
+ assert(p);
+ assert(ret);
+
+ fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ return read_attr_fd(fd, ret);
+}
diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h
new file mode 100644
index 0000000000..ba6b8eb5c1
--- /dev/null
+++ b/src/basic/chattr-util.h
@@ -0,0 +1,28 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int chattr_fd(int fd, unsigned value, unsigned mask);
+int chattr_path(const char *p, unsigned value, unsigned mask);
+
+int read_attr_fd(int fd, unsigned *ret);
+int read_attr_path(const char *p, unsigned *ret);
diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c
index e4e03df1e4..00ee4c2796 100644
--- a/src/basic/clock-util.c
+++ b/src/basic/clock-util.c
@@ -20,15 +20,17 @@
***/
#include <errno.h>
-#include <stdio.h>
#include <fcntl.h>
+#include <linux/rtc.h>
+#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/time.h>
-#include <linux/rtc.h>
+#include "clock-util.h"
+#include "fd-util.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
-#include "clock-util.h"
int clock_get_hwclock(struct tm *tm) {
_cleanup_close_ int fd = -1;
diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h
index 8c2d235430..fef2d471a6 100644
--- a/src/basic/clock-util.h
+++ b/src/basic/clock-util.h
@@ -21,6 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <time.h>
int clock_is_localtime(void);
int clock_set_timezone(int *min);
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index da8745b284..be9972ffff 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -19,20 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
+#include <dirent.h>
#include <errno.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "conf-files.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "hashmap.h"
+#include "log.h"
#include "macro.h"
-#include "util.h"
#include "missing.h"
-#include "log.h"
-#include "strv.h"
#include "path-util.h"
-#include "hashmap.h"
-#include "conf-files.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
_cleanup_closedir_ DIR *dir = NULL;
diff --git a/src/basic/copy.c b/src/basic/copy.c
index b20c178727..a187ae08fe 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -22,10 +22,20 @@
#include <sys/sendfile.h>
#include <sys/xattr.h>
-#include "util.h"
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "strv.h"
+#include "chattr-util.h"
#include "copy.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "util.h"
+#include "xattr-util.h"
#define COPY_BUFFER_SIZE (16*1024)
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
new file mode 100644
index 0000000000..e2ec4ca83f
--- /dev/null
+++ b/src/basic/cpu-set-util.c
@@ -0,0 +1,111 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+ Copyright 2015 Filipe Brandenburger
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "cpu-set-util.h"
+#include "extract-word.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
+
+cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
+ cpu_set_t *c;
+ unsigned n = 1024;
+
+ /* Allocates the cpuset in the right size */
+
+ for (;;) {
+ c = CPU_ALLOC(n);
+ if (!c)
+ return NULL;
+
+ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
+ CPU_ZERO_S(CPU_ALLOC_SIZE(n), c);
+
+ if (ncpus)
+ *ncpus = n;
+
+ return c;
+ }
+
+ CPU_FREE(c);
+
+ if (errno != EINVAL)
+ return NULL;
+
+ n *= 2;
+ }
+}
+
+int parse_cpu_set_and_warn(
+ const char *rvalue,
+ cpu_set_t **cpu_set,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue) {
+
+ const char *whole_rvalue = rvalue;
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ unsigned ncpus = 0;
+
+ assert(lvalue);
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ unsigned cpu, cpu_lower, cpu_upper;
+ int r;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
+ if (r == 0)
+ break;
+
+ if (!c) {
+ c = cpu_set_malloc(&ncpus);
+ if (!c)
+ return log_oom();
+ }
+
+ r = parse_range(word, &cpu_lower, &cpu_upper);
+ if (r < 0)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word);
+ if (cpu_lower >= ncpus || cpu_upper >= ncpus)
+ return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus);
+
+ if (cpu_lower > cpu_upper)
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper);
+ else
+ for (cpu = cpu_lower; cpu <= cpu_upper; cpu++)
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ }
+
+ /* On success, sets *cpu_set and returns ncpus for the system. */
+ if (c) {
+ *cpu_set = c;
+ c = NULL;
+ }
+
+ return (int) ncpus;
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
new file mode 100644
index 0000000000..19b457a684
--- /dev/null
+++ b/src/basic/cpu-set-util.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+ Copyright 2015 Filipe Brandenburger
+
+ 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 <sched.h>
+
+#include "macro.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
+#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
+
+cpu_set_t* cpu_set_malloc(unsigned *ncpus);
+
+int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
diff --git a/src/basic/def.h b/src/basic/def.h
index 7c4161eb72..950f693899 100644
--- a/src/basic/def.h
+++ b/src/basic/def.h
@@ -35,17 +35,14 @@
* the watchdog pings will keep the loop busy. */
#define DEFAULT_EXIT_USEC (30*USEC_PER_SEC)
+/* The default value for the net.unix.max_dgram_qlen sysctl */
+#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL
+
#define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
-#define DIGITS "0123456789"
-#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
-#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
-#define ALPHANUMERICAL LETTERS DIGITS
-
#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
#ifdef HAVE_SPLIT_USR
@@ -78,3 +75,18 @@
#define NOTIFY_FD_MAX 768
#define NOTIFY_BUFFER_MAX PIPE_BUF
+
+/* 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
diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h
index 04ba4897e5..7db81f3d52 100644
--- a/src/basic/device-nodes.h
+++ b/src/basic/device-nodes.h
@@ -21,5 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/types.h>
+
int encode_devnode_name(const char *str, char *str_enc, size_t len);
int whitelisted_char_for_devnode(char c, const char *additional);
diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c
new file mode 100644
index 0000000000..c433d5844a
--- /dev/null
+++ b/src/basic/dirent-util.c
@@ -0,0 +1,81 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "dirent-util.h"
+#include "string-util.h"
+
+int dirent_ensure_type(DIR *d, struct dirent *de) {
+ struct stat st;
+
+ assert(d);
+ assert(de);
+
+ if (de->d_type != DT_UNKNOWN)
+ return 0;
+
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ return -errno;
+
+ de->d_type =
+ S_ISREG(st.st_mode) ? DT_REG :
+ S_ISDIR(st.st_mode) ? DT_DIR :
+ S_ISLNK(st.st_mode) ? DT_LNK :
+ S_ISFIFO(st.st_mode) ? DT_FIFO :
+ S_ISSOCK(st.st_mode) ? DT_SOCK :
+ S_ISCHR(st.st_mode) ? DT_CHR :
+ S_ISBLK(st.st_mode) ? DT_BLK :
+ DT_UNKNOWN;
+
+ return 0;
+}
+
+bool dirent_is_file(const struct dirent *de) {
+ assert(de);
+
+ if (hidden_file(de->d_name))
+ return false;
+
+ if (de->d_type != DT_REG &&
+ de->d_type != DT_LNK &&
+ de->d_type != DT_UNKNOWN)
+ return false;
+
+ return true;
+}
+
+bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
+ assert(de);
+
+ if (de->d_type != DT_REG &&
+ de->d_type != DT_LNK &&
+ de->d_type != DT_UNKNOWN)
+ return false;
+
+ if (hidden_file_allow_backup(de->d_name))
+ return false;
+
+ return endswith(de->d_name, suffix);
+}
diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h
new file mode 100644
index 0000000000..5866a755f4
--- /dev/null
+++ b/src/basic/dirent-util.h
@@ -0,0 +1,51 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dirent.h>
+
+#include "path-util.h"
+
+int dirent_ensure_type(DIR *d, struct dirent *de);
+
+bool dirent_is_file(const struct dirent *de) _pure_;
+bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
+
+#define FOREACH_DIRENT(de, d, on_error) \
+ for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
+ if (!de) { \
+ if (errno > 0) { \
+ on_error; \
+ } \
+ break; \
+ } else if (hidden_file((de)->d_name)) \
+ continue; \
+ else
+
+#define FOREACH_DIRENT_ALL(de, d, on_error) \
+ for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
+ if (!de) { \
+ if (errno > 0) { \
+ on_error; \
+ } \
+ break; \
+ } else
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 4804a67f91..9ddac5d6a1 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -22,11 +22,14 @@
#include <limits.h>
#include <unistd.h>
+#include "alloc-util.h"
+#include "def.h"
+#include "env-util.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "strv.h"
#include "utf8.h"
#include "util.h"
-#include "env-util.h"
-#include "def.h"
#define VALID_CHARS_ENV_NAME \
DIGITS LETTERS \
@@ -541,7 +544,7 @@ char **replace_env_argv(char **argv, char **env) {
STRV_FOREACH(i, argv) {
/* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{') {
+ if ((*i)[0] == '$' && (*i)[1] != '{' && (*i)[1] != '$') {
char *e;
char **w, **m = NULL;
unsigned q;
@@ -592,3 +595,13 @@ char **replace_env_argv(char **argv, char **env) {
ret[k] = NULL;
return ret;
}
+
+int getenv_bool(const char *p) {
+ const char *e;
+
+ e = getenv(p);
+ if (!e)
+ return -ENXIO;
+
+ return parse_boolean(e);
+}
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index 803aa61cad..6485dade18 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -47,3 +47,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_;
char *strv_env_get_n(char **l, const char *name, size_t k) _pure_;
char *strv_env_get(char **x, const char *n) _pure_;
+
+int getenv_bool(const char *p);
diff --git a/src/basic/escape.c b/src/basic/escape.c
new file mode 100644
index 0000000000..4815161b09
--- /dev/null
+++ b/src/basic/escape.c
@@ -0,0 +1,482 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "hexdecoct.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+size_t cescape_char(char c, char *buf) {
+ char * buf_old = buf;
+
+ switch (c) {
+
+ case '\a':
+ *(buf++) = '\\';
+ *(buf++) = 'a';
+ break;
+ case '\b':
+ *(buf++) = '\\';
+ *(buf++) = 'b';
+ break;
+ case '\f':
+ *(buf++) = '\\';
+ *(buf++) = 'f';
+ break;
+ case '\n':
+ *(buf++) = '\\';
+ *(buf++) = 'n';
+ break;
+ case '\r':
+ *(buf++) = '\\';
+ *(buf++) = 'r';
+ break;
+ case '\t':
+ *(buf++) = '\\';
+ *(buf++) = 't';
+ break;
+ case '\v':
+ *(buf++) = '\\';
+ *(buf++) = 'v';
+ break;
+ case '\\':
+ *(buf++) = '\\';
+ *(buf++) = '\\';
+ break;
+ case '"':
+ *(buf++) = '\\';
+ *(buf++) = '"';
+ break;
+ case '\'':
+ *(buf++) = '\\';
+ *(buf++) = '\'';
+ break;
+
+ default:
+ /* For special chars we prefer octal over
+ * hexadecimal encoding, simply because glib's
+ * g_strescape() does the same */
+ if ((c < ' ') || (c >= 127)) {
+ *(buf++) = '\\';
+ *(buf++) = octchar((unsigned char) c >> 6);
+ *(buf++) = octchar((unsigned char) c >> 3);
+ *(buf++) = octchar((unsigned char) c);
+ } else
+ *(buf++) = c;
+ break;
+ }
+
+ return buf - buf_old;
+}
+
+char *cescape(const char *s) {
+ char *r, *t;
+ const char *f;
+
+ assert(s);
+
+ /* Does C style string escaping. May be reversed with
+ * cunescape(). */
+
+ r = new(char, strlen(s)*4 + 1);
+ if (!r)
+ return NULL;
+
+ for (f = s, t = r; *f; f++)
+ t += cescape_char(*f, t);
+
+ *t = 0;
+
+ return r;
+}
+
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
+ int r = 1;
+
+ assert(p);
+ assert(*p);
+ assert(ret);
+
+ /* Unescapes C style. Returns the unescaped character in ret,
+ * unless we encountered a \u sequence in which case the full
+ * unicode character is returned in ret_unicode, instead. */
+
+ if (length != (size_t) -1 && length < 1)
+ return -EINVAL;
+
+ switch (p[0]) {
+
+ case 'a':
+ *ret = '\a';
+ break;
+ case 'b':
+ *ret = '\b';
+ break;
+ case 'f':
+ *ret = '\f';
+ break;
+ case 'n':
+ *ret = '\n';
+ break;
+ case 'r':
+ *ret = '\r';
+ break;
+ case 't':
+ *ret = '\t';
+ break;
+ case 'v':
+ *ret = '\v';
+ break;
+ case '\\':
+ *ret = '\\';
+ break;
+ case '"':
+ *ret = '"';
+ break;
+ case '\'':
+ *ret = '\'';
+ break;
+
+ case 's':
+ /* This is an extension of the XDG syntax files */
+ *ret = ' ';
+ break;
+
+ case 'x': {
+ /* hexadecimal encoding */
+ int a, b;
+
+ if (length != (size_t) -1 && length < 3)
+ return -EINVAL;
+
+ a = unhexchar(p[1]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unhexchar(p[2]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* Don't allow NUL bytes */
+ if (a == 0 && b == 0)
+ return -EINVAL;
+
+ *ret = (char) ((a << 4U) | b);
+ r = 3;
+ break;
+ }
+
+ case 'u': {
+ /* C++11 style 16bit unicode */
+
+ int a[4];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 5)
+ return -EINVAL;
+
+ for (i = 0; i < 4; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 5;
+ break;
+ }
+
+ case 'U': {
+ /* C++11 style 32bit unicode */
+
+ int a[8];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 9)
+ return -EINVAL;
+
+ for (i = 0; i < 8; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
+ ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ /* Don't allow invalid code points */
+ if (!unichar_is_valid(c))
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 9;
+ break;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': {
+ /* octal encoding */
+ int a, b, c;
+ uint32_t m;
+
+ if (length != (size_t) -1 && length < 3)
+ return -EINVAL;
+
+ a = unoctchar(p[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unoctchar(p[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unoctchar(p[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ /* don't allow NUL bytes */
+ if (a == 0 && b == 0 && c == 0)
+ return -EINVAL;
+
+ /* Don't allow bytes above 255 */
+ m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
+ if (m > 255)
+ return -EINVAL;
+
+ *ret = m;
+ r = 3;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return r;
+}
+
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
+ char *r, *t;
+ const char *f;
+ size_t pl;
+
+ assert(s);
+ assert(ret);
+
+ /* Undoes C style string escaping, and optionally prefixes it. */
+
+ pl = prefix ? strlen(prefix) : 0;
+
+ r = new(char, pl+length+1);
+ if (!r)
+ return -ENOMEM;
+
+ if (prefix)
+ memcpy(r, prefix, pl);
+
+ for (f = s, t = r + pl; f < s + length; f++) {
+ size_t remaining;
+ uint32_t u;
+ char c;
+ int k;
+
+ remaining = s + length - f;
+ assert(remaining > 0);
+
+ if (*f != '\\') {
+ /* A literal literal, copy verbatim */
+ *(t++) = *f;
+ continue;
+ }
+
+ if (remaining == 1) {
+ if (flags & UNESCAPE_RELAX) {
+ /* A trailing backslash, copy verbatim */
+ *(t++) = *f;
+ continue;
+ }
+
+ free(r);
+ return -EINVAL;
+ }
+
+ k = cunescape_one(f + 1, remaining - 1, &c, &u);
+ if (k < 0) {
+ if (flags & UNESCAPE_RELAX) {
+ /* Invalid escape code, let's take it literal then */
+ *(t++) = '\\';
+ continue;
+ }
+
+ free(r);
+ return k;
+ }
+
+ if (c != 0)
+ /* Non-Unicode? Let's encode this directly */
+ *(t++) = c;
+ else
+ /* Unicode? Then let's encode this in UTF-8 */
+ t += utf8_encode_unichar(t, u);
+
+ f += k;
+ }
+
+ *t = 0;
+
+ *ret = r;
+ return t - r;
+}
+
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
+ return cunescape_length_with_prefix(s, length, NULL, flags, ret);
+}
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret) {
+ return cunescape_length(s, strlen(s), flags, ret);
+}
+
+char *xescape(const char *s, const char *bad) {
+ char *r, *t;
+ const char *f;
+
+ /* Escapes all chars in bad, in addition to \ and all special
+ * chars, in \xFF style escaping. May be reversed with
+ * cunescape(). */
+
+ r = new(char, strlen(s) * 4 + 1);
+ if (!r)
+ return NULL;
+
+ for (f = s, t = r; *f; f++) {
+
+ if ((*f < ' ') || (*f >= 127) ||
+ (*f == '\\') || strchr(bad, *f)) {
+ *(t++) = '\\';
+ *(t++) = 'x';
+ *(t++) = hexchar(*f >> 4);
+ *(t++) = hexchar(*f);
+ } else
+ *(t++) = *f;
+ }
+
+ *t = 0;
+
+ return r;
+}
+
+static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
+ assert(bad);
+
+ for (; *s; s++) {
+ if (*s == '\\' || strchr(bad, *s))
+ *(t++) = '\\';
+
+ *(t++) = *s;
+ }
+
+ return t;
+}
+
+char *shell_escape(const char *s, const char *bad) {
+ char *r, *t;
+
+ r = new(char, strlen(s)*2+1);
+ if (!r)
+ return NULL;
+
+ t = strcpy_backslash_escaped(r, s, bad);
+ *t = 0;
+
+ return r;
+}
+
+char *shell_maybe_quote(const char *s) {
+ const char *p;
+ char *r, *t;
+
+ assert(s);
+
+ /* Encloses a string in double quotes if necessary to make it
+ * OK as shell string. */
+
+ for (p = s; *p; p++)
+ if (*p <= ' ' ||
+ *p >= 127 ||
+ strchr(SHELL_NEED_QUOTES, *p))
+ break;
+
+ if (!*p)
+ return strdup(s);
+
+ r = new(char, 1+strlen(s)*2+1+1);
+ if (!r)
+ return NULL;
+
+ t = r;
+ *(t++) = '"';
+ t = mempcpy(t, s, p - s);
+
+ t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
+
+ *(t++)= '"';
+ *t = 0;
+
+ return r;
+}
diff --git a/src/basic/escape.h b/src/basic/escape.h
new file mode 100644
index 0000000000..85ba909081
--- /dev/null
+++ b/src/basic/escape.h
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <inttypes.h>
+
+/* What characters are special in the shell? */
+/* must be escaped outside and inside double-quotes */
+#define SHELL_NEED_ESCAPE "\"\\`$"
+/* can be escaped or double-quoted */
+#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
+
+typedef enum UnescapeFlags {
+ UNESCAPE_RELAX = 1,
+} UnescapeFlags;
+
+char *cescape(const char *s);
+size_t cescape_char(char c, char *buf);
+
+int cunescape(const char *s, UnescapeFlags flags, char **ret);
+int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
+int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
+int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode);
+
+char *xescape(const char *s, const char *bad);
+
+char *shell_escape(const char *s, const char *bad);
+char *shell_maybe_quote(const char *s);
diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c
new file mode 100644
index 0000000000..2bf3bfec1d
--- /dev/null
+++ b/src/basic/ether-addr-util.c
@@ -0,0 +1,44 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+
+#include "ether-addr-util.h"
+#include "macro.h"
+
+char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
+ assert(addr);
+ assert(buffer);
+
+ /* Like ether_ntoa() but uses %02x instead of %x to print
+ * ethernet addresses, which makes them look less funny. Also,
+ * doesn't use a static buffer. */
+
+ sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
+ addr->ether_addr_octet[0],
+ addr->ether_addr_octet[1],
+ addr->ether_addr_octet[2],
+ addr->ether_addr_octet[3],
+ addr->ether_addr_octet[4],
+ addr->ether_addr_octet[5]);
+
+ return buffer;
+}
diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h
index 7033138788..008f3b893e 100644
--- a/src/basic/ether-addr-util.h
+++ b/src/basic/ether-addr-util.h
@@ -25,3 +25,7 @@
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
+
+#define ETHER_ADDR_TO_STRING_MAX (3*6)
+
+char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
new file mode 100644
index 0000000000..6721b85c0a
--- /dev/null
+++ b/src/basic/extract-word.c
@@ -0,0 +1,286 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "extract-word.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
+ _cleanup_free_ char *s = NULL;
+ size_t allocated = 0, sz = 0;
+ int r;
+
+ char quote = 0; /* 0 or ' or " */
+ bool backslash = false; /* whether we've just seen a backslash */
+ bool separator = false; /* whether we've just seen a separator */
+ bool start = true; /* false means we're looking at a value */
+
+ assert(p);
+ assert(ret);
+
+ if (!separators)
+ separators = WHITESPACE;
+
+ /* Bail early if called after last value or with no input */
+ if (!*p)
+ goto finish_force_terminate;
+
+ /* Parses the first word of a string, and returns it in
+ * *ret. Removes all quotes in the process. When parsing fails
+ * (because of an uneven number of quotes or similar), leaves
+ * the pointer *p at the first invalid character. */
+
+ for (;;) {
+ char c = **p;
+
+ if (start) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
+ if (c == 0)
+ goto finish_force_terminate;
+ else if (strchr(separators, c)) {
+ (*p) ++;
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ goto finish_force_next;
+ continue;
+ }
+
+ /* We found a non-blank character, so we will always
+ * want to return a string (even if it is empty),
+ * allocate it here. */
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
+ start = false;
+ }
+
+ if (backslash) {
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
+ return -ENOMEM;
+
+ if (c == 0) {
+ if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+ (!quote || flags & EXTRACT_RELAX)) {
+ /* If we find an unquoted trailing backslash and we're in
+ * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
+ * output.
+ *
+ * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+ * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
+ */
+ s[sz++] = '\\';
+ goto finish_force_terminate;
+ }
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
+ return -EINVAL;
+ }
+
+ if (flags & EXTRACT_CUNESCAPE) {
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
+ if (r < 0) {
+ if (flags & EXTRACT_CUNESCAPE_RELAX) {
+ s[sz++] = '\\';
+ s[sz++] = c;
+ goto end_escape;
+ }
+ return -EINVAL;
+ }
+
+ (*p) += r - 1;
+
+ if (c != 0)
+ s[sz++] = c; /* normal explicit char */
+ else
+ sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+ } else
+ s[sz++] = c;
+
+end_escape:
+ backslash = false;
+
+ } else if (quote) { /* inside either single or double quotes */
+ if (c == 0) {
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
+ return -EINVAL;
+ } else if (c == quote) /* found the end quote */
+ quote = 0;
+ else if (c == '\\')
+ backslash = true;
+ else {
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ }
+
+ } else if (separator) {
+ if (c == 0)
+ goto finish_force_terminate;
+ if (!strchr(separators, c))
+ goto finish;
+
+ } else {
+ if (c == 0)
+ goto finish_force_terminate;
+ else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES))
+ quote = c;
+ else if (c == '\\')
+ backslash = true;
+ else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+ (*p) ++;
+ goto finish_force_next;
+ }
+ separator = true;
+ } else {
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ }
+ }
+
+ (*p) ++;
+ }
+
+finish_force_terminate:
+ *p = NULL;
+finish:
+ if (!s) {
+ *p = NULL;
+ *ret = NULL;
+ return 0;
+ }
+
+finish_force_next:
+ s[sz] = 0;
+ *ret = s;
+ s = NULL;
+
+ return 1;
+}
+
+int extract_first_word_and_warn(
+ const char **p,
+ char **ret,
+ const char *separators,
+ ExtractFlags flags,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *rvalue) {
+
+ /* Try to unquote it, if it fails, warn about it and try again
+ * but this time using EXTRACT_CUNESCAPE_RELAX to keep the
+ * backslashes verbatim in invalid escape sequences. */
+
+ const char *save;
+ int r;
+
+ save = *p;
+ r = extract_first_word(p, ret, separators, flags);
+ if (r >= 0)
+ return r;
+
+ if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+
+ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
+ *p = save;
+ r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
+ if (r >= 0) {
+ /* It worked this time, hence it must have been an invalid escape sequence we could correct. */
+ log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue);
+ return r;
+ }
+
+ /* If it's still EINVAL; then it must be unbalanced quoting, report this. */
+ if (r == -EINVAL)
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue);
+ }
+
+ /* Can be any error, report it */
+ return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue);
+}
+
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
+ va_list ap;
+ char **l;
+ int n = 0, i, c, r;
+
+ /* Parses a number of words from a string, stripping any
+ * quotes if necessary. */
+
+ assert(p);
+
+ /* Count how many words are expected */
+ va_start(ap, flags);
+ for (;;) {
+ if (!va_arg(ap, char **))
+ break;
+ n++;
+ }
+ va_end(ap);
+
+ if (n <= 0)
+ return 0;
+
+ /* Read all words into a temporary array */
+ l = newa0(char*, n);
+ for (c = 0; c < n; c++) {
+
+ r = extract_first_word(p, &l[c], separators, flags);
+ if (r < 0) {
+ int j;
+
+ for (j = 0; j < c; j++)
+ free(l[j]);
+
+ return r;
+ }
+
+ if (r == 0)
+ break;
+ }
+
+ /* If we managed to parse all words, return them in the passed
+ * in parameters */
+ va_start(ap, flags);
+ for (i = 0; i < n; i++) {
+ char **v;
+
+ v = va_arg(ap, char **);
+ assert(v);
+
+ *v = l[i];
+ }
+ va_end(ap);
+
+ return c;
+}
diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h
new file mode 100644
index 0000000000..ddc1c4f463
--- /dev/null
+++ b/src/basic/extract-word.h
@@ -0,0 +1,36 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "macro.h"
+
+typedef enum ExtractFlags {
+ EXTRACT_RELAX = 1,
+ EXTRACT_CUNESCAPE = 2,
+ EXTRACT_CUNESCAPE_RELAX = 4,
+ EXTRACT_QUOTES = 8,
+ EXTRACT_DONT_COALESCE_SEPARATORS = 16,
+} ExtractFlags;
+
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
+int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
new file mode 100644
index 0000000000..d1b1db3a4d
--- /dev/null
+++ b/src/basic/fd-util.c
@@ -0,0 +1,351 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "util.h"
+
+int close_nointr(int fd) {
+ assert(fd >= 0);
+
+ if (close(fd) >= 0)
+ return 0;
+
+ /*
+ * Just ignore EINTR; a retry loop is the wrong thing to do on
+ * Linux.
+ *
+ * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+ * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+ * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+ */
+ if (errno == EINTR)
+ return 0;
+
+ return -errno;
+}
+
+int safe_close(int fd) {
+
+ /*
+ * Like close_nointr() but cannot fail. Guarantees errno is
+ * unchanged. Is a NOP with negative fds passed, and returns
+ * -1, so that it can be used in this syntax:
+ *
+ * fd = safe_close(fd);
+ */
+
+ if (fd >= 0) {
+ PROTECT_ERRNO;
+
+ /* The kernel might return pretty much any error code
+ * via close(), but the fd will be closed anyway. The
+ * only condition we want to check for here is whether
+ * the fd was invalid at all... */
+
+ assert_se(close_nointr(fd) != -EBADF);
+ }
+
+ return -1;
+}
+
+void safe_close_pair(int p[]) {
+ assert(p);
+
+ if (p[0] == p[1]) {
+ /* Special case pairs which use the same fd in both
+ * directions... */
+ p[0] = p[1] = safe_close(p[0]);
+ return;
+ }
+
+ p[0] = safe_close(p[0]);
+ p[1] = safe_close(p[1]);
+}
+
+void close_many(const int fds[], unsigned n_fd) {
+ unsigned i;
+
+ assert(fds || n_fd <= 0);
+
+ for (i = 0; i < n_fd; i++)
+ safe_close(fds[i]);
+}
+
+int fclose_nointr(FILE *f) {
+ assert(f);
+
+ /* Same as close_nointr(), but for fclose() */
+
+ if (fclose(f) == 0)
+ return 0;
+
+ if (errno == EINTR)
+ return 0;
+
+ return -errno;
+}
+
+FILE* safe_fclose(FILE *f) {
+
+ /* Same as safe_close(), but for fclose() */
+
+ if (f) {
+ PROTECT_ERRNO;
+
+ assert_se(fclose_nointr(f) != EBADF);
+ }
+
+ return NULL;
+}
+
+DIR* safe_closedir(DIR *d) {
+
+ if (d) {
+ PROTECT_ERRNO;
+
+ assert_se(closedir(d) >= 0 || errno != EBADF);
+ }
+
+ return NULL;
+}
+
+int fd_nonblock(int fd, bool nonblock) {
+ int flags, nflags;
+
+ assert(fd >= 0);
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags < 0)
+ return -errno;
+
+ if (nonblock)
+ nflags = flags | O_NONBLOCK;
+ else
+ nflags = flags & ~O_NONBLOCK;
+
+ if (nflags == flags)
+ return 0;
+
+ if (fcntl(fd, F_SETFL, nflags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int fd_cloexec(int fd, bool cloexec) {
+ int flags, nflags;
+
+ assert(fd >= 0);
+
+ flags = fcntl(fd, F_GETFD, 0);
+ if (flags < 0)
+ return -errno;
+
+ if (cloexec)
+ nflags = flags | FD_CLOEXEC;
+ else
+ nflags = flags & ~FD_CLOEXEC;
+
+ if (nflags == flags)
+ return 0;
+
+ if (fcntl(fd, F_SETFD, nflags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
+ unsigned i;
+
+ assert(n_fdset == 0 || fdset);
+
+ for (i = 0; i < n_fdset; i++)
+ if (fdset[i] == fd)
+ return true;
+
+ return false;
+}
+
+int close_all_fds(const int except[], unsigned n_except) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ int r = 0;
+
+ assert(n_except == 0 || except);
+
+ d = opendir("/proc/self/fd");
+ if (!d) {
+ int fd;
+ struct rlimit rl;
+
+ /* When /proc isn't available (for example in chroots)
+ * the fallback is brute forcing through the fd
+ * table */
+
+ assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
+ for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
+
+ if (fd_in_set(fd, except, n_except))
+ continue;
+
+ if (close_nointr(fd) < 0)
+ if (errno != EBADF && r == 0)
+ r = -errno;
+ }
+
+ return r;
+ }
+
+ while ((de = readdir(d))) {
+ int fd = -1;
+
+ if (hidden_file(de->d_name))
+ continue;
+
+ if (safe_atoi(de->d_name, &fd) < 0)
+ /* Let's better ignore this, just in case */
+ continue;
+
+ if (fd < 3)
+ continue;
+
+ if (fd == dirfd(d))
+ continue;
+
+ if (fd_in_set(fd, except, n_except))
+ continue;
+
+ if (close_nointr(fd) < 0) {
+ /* Valgrind has its own FD and doesn't want to have it closed */
+ if (errno != EBADF && r == 0)
+ r = -errno;
+ }
+ }
+
+ return r;
+}
+
+int same_fd(int a, int b) {
+ struct stat sta, stb;
+ pid_t pid;
+ int r, fa, fb;
+
+ assert(a >= 0);
+ assert(b >= 0);
+
+ /* Compares two file descriptors. Note that semantics are
+ * quite different depending on whether we have kcmp() or we
+ * don't. If we have kcmp() this will only return true for
+ * dup()ed file descriptors, but not otherwise. If we don't
+ * have kcmp() this will also return true for two fds of the same
+ * file, created by separate open() calls. Since we use this
+ * call mostly for filtering out duplicates in the fd store
+ * this difference hopefully doesn't matter too much. */
+
+ if (a == b)
+ return true;
+
+ /* Try to use kcmp() if we have it. */
+ pid = getpid();
+ r = kcmp(pid, pid, KCMP_FILE, a, b);
+ if (r == 0)
+ return true;
+ if (r > 0)
+ return false;
+ if (errno != ENOSYS)
+ return -errno;
+
+ /* We don't have kcmp(), use fstat() instead. */
+ if (fstat(a, &sta) < 0)
+ return -errno;
+
+ if (fstat(b, &stb) < 0)
+ return -errno;
+
+ if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
+ return false;
+
+ /* We consider all device fds different, since two device fds
+ * might refer to quite different device contexts even though
+ * they share the same inode and backing dev_t. */
+
+ if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
+ return false;
+
+ if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
+ return false;
+
+ /* The fds refer to the same inode on disk, let's also check
+ * if they have the same fd flags. This is useful to
+ * distinguish the read and write side of a pipe created with
+ * pipe(). */
+ fa = fcntl(a, F_GETFL);
+ if (fa < 0)
+ return -errno;
+
+ fb = fcntl(b, F_GETFL);
+ if (fb < 0)
+ return -errno;
+
+ return fa == fb;
+}
+
+void cmsg_close_all(struct msghdr *mh) {
+ struct cmsghdr *cmsg;
+
+ assert(mh);
+
+ CMSG_FOREACH(cmsg, mh)
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
+}
+
+bool fdname_is_valid(const char *s) {
+ const char *p;
+
+ /* Validates a name for $LISTEN_FDNAMES. We basically allow
+ * everything ASCII that's not a control character. Also, as
+ * special exception the ":" character is not allowed, as we
+ * use that as field separator in $LISTEN_FDNAMES.
+ *
+ * Note that the empty string is explicitly allowed
+ * here. However, we limit the length of the names to 255
+ * characters. */
+
+ if (!s)
+ return false;
+
+ for (p = s; *p; p++) {
+ if (*p < ' ')
+ return false;
+ if (*p >= 127)
+ return false;
+ if (*p == ':')
+ return false;
+ }
+
+ return p - s < 256;
+}
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
new file mode 100644
index 0000000000..1ca10f0383
--- /dev/null
+++ b/src/basic/fd-util.h
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <dirent.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include "macro.h"
+
+int close_nointr(int fd);
+int safe_close(int fd);
+void safe_close_pair(int p[]);
+
+void close_many(const int fds[], unsigned n_fd);
+
+int fclose_nointr(FILE *f);
+FILE* safe_fclose(FILE *f);
+DIR* safe_closedir(DIR *f);
+
+static inline void closep(int *fd) {
+ safe_close(*fd);
+}
+
+static inline void close_pairp(int (*p)[2]) {
+ safe_close_pair(*p);
+}
+
+static inline void fclosep(FILE **f) {
+ safe_fclose(*f);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
+DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
+
+#define _cleanup_close_ _cleanup_(closep)
+#define _cleanup_fclose_ _cleanup_(fclosep)
+#define _cleanup_pclose_ _cleanup_(pclosep)
+#define _cleanup_closedir_ _cleanup_(closedirp)
+#define _cleanup_close_pair_ _cleanup_(close_pairp)
+
+int fd_nonblock(int fd, bool nonblock);
+int fd_cloexec(int fd, bool cloexec);
+
+int close_all_fds(const int except[], unsigned n_except);
+
+int same_fd(int a, int b);
+
+void cmsg_close_all(struct msghdr *mh);
+
+bool fdname_is_valid(const char *s);
diff --git a/src/basic/fdset.c b/src/basic/fdset.c
index d70fe156a2..42b0b2b98f 100644
--- a/src/basic/fdset.c
+++ b/src/basic/fdset.c
@@ -23,11 +23,15 @@
#include <dirent.h>
#include <fcntl.h>
+#include "sd-daemon.h"
+
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fdset.h"
+#include "macro.h"
+#include "parse-util.h"
#include "set.h"
#include "util.h"
-#include "macro.h"
-#include "fdset.h"
-#include "sd-daemon.h"
#define MAKE_SET(s) ((Set*) s)
#define MAKE_FDSET(s) ((FDSet*) s)
@@ -40,7 +44,7 @@ FDSet *fdset_new(void) {
return MAKE_FDSET(set_new(NULL));
}
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) {
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) {
unsigned i;
FDSet *s;
int r;
diff --git a/src/basic/fdset.h b/src/basic/fdset.h
index 340438d7c4..70d8acbcff 100644
--- a/src/basic/fdset.h
+++ b/src/basic/fdset.h
@@ -35,7 +35,7 @@ int fdset_consume(FDSet *s, int fd);
bool fdset_contains(FDSet *s, int fd);
int fdset_remove(FDSet *s, int fd);
-int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds);
+int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds);
int fdset_new_fill(FDSet **ret);
int fdset_new_listen_fds(FDSet **ret, bool unset);
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 4a9105f421..619dafb517 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -21,11 +21,20 @@
#include <unistd.h>
-#include "util.h"
-#include "strv.h"
-#include "utf8.h"
+#include "alloc-util.h"
#include "ctype.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "path-util.h"
+#include "random-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "utf8.h"
+#include "util.h"
int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
@@ -51,7 +60,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
if (r < 0)
return r;
- fchmod_umask(fileno(f), 0644);
+ (void) fchmod_umask(fileno(f), 0644);
r = write_string_stream(f, line, enforce_newline);
if (r >= 0) {
@@ -60,7 +69,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
}
if (r < 0)
- unlink(p);
+ (void) unlink(p);
return r;
}
@@ -775,15 +784,19 @@ int executable_is_script(const char *path, char **interpreter) {
/**
* Retrieve one field from a file like /proc/self/status. pattern
- * should start with '\n' and end with a ':'. Whitespace and zeros
- * after the ':' will be skipped. field must be freed afterwards.
+ * should not include whitespace or the delimiter (':'). pattern matches only
+ * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
+ * zeros after the ':' will be skipped. field must be freed afterwards.
+ * terminator specifies the terminating characters of the field value (not
+ * included in the value).
*/
-int get_status_field(const char *filename, const char *pattern, char **field) {
+int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
_cleanup_free_ char *status = NULL;
char *t, *f;
size_t len;
int r;
+ assert(terminator);
assert(filename);
assert(pattern);
assert(field);
@@ -792,11 +805,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
if (r < 0)
return r;
- t = strstr(status, pattern);
- if (!t)
- return -ENOENT;
+ t = status;
+
+ do {
+ bool pattern_ok;
+
+ do {
+ t = strstr(t, pattern);
+ if (!t)
+ return -ENOENT;
+
+ /* Check that pattern occurs in beginning of line. */
+ pattern_ok = (t == status || t[-1] == '\n');
+
+ t += strlen(pattern);
+
+ } while (!pattern_ok);
+
+ t += strspn(t, " \t");
+ if (!*t)
+ return -ENOENT;
+
+ } while (*t != ':');
+
+ t++;
- t += strlen(pattern);
if (*t) {
t += strspn(t, " \t");
@@ -812,7 +845,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
t --;
}
- len = strcspn(t, WHITESPACE);
+ len = strcspn(t, terminator);
f = strndup(t, len);
if (!f)
@@ -821,3 +854,298 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
*field = f;
return 0;
}
+
+DIR *xopendirat(int fd, const char *name, int flags) {
+ int nfd;
+ DIR *d;
+
+ assert(!(flags & O_CREAT));
+
+ nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
+ if (nfd < 0)
+ return NULL;
+
+ d = fdopendir(nfd);
+ if (!d) {
+ safe_close(nfd);
+ return NULL;
+ }
+
+ return d;
+}
+
+static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
+ char **i;
+
+ assert(path);
+ assert(mode);
+ assert(_f);
+
+ if (!path_strv_resolve_uniq(search, root))
+ return -ENOMEM;
+
+ STRV_FOREACH(i, search) {
+ _cleanup_free_ char *p = NULL;
+ FILE *f;
+
+ if (root)
+ p = strjoin(root, *i, "/", path, NULL);
+ else
+ p = strjoin(*i, "/", path, NULL);
+ if (!p)
+ return -ENOMEM;
+
+ f = fopen(p, mode);
+ if (f) {
+ *_f = f;
+ return 0;
+ }
+
+ if (errno != ENOENT)
+ return -errno;
+ }
+
+ return -ENOENT;
+}
+
+int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
+ _cleanup_strv_free_ char **copy = NULL;
+
+ assert(path);
+ assert(mode);
+ assert(_f);
+
+ if (path_is_absolute(path)) {
+ FILE *f;
+
+ f = fopen(path, mode);
+ if (f) {
+ *_f = f;
+ return 0;
+ }
+
+ return -errno;
+ }
+
+ copy = strv_copy((char**) search);
+ if (!copy)
+ return -ENOMEM;
+
+ return search_and_fopen_internal(path, mode, root, copy, _f);
+}
+
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
+ _cleanup_strv_free_ char **s = NULL;
+
+ if (path_is_absolute(path)) {
+ FILE *f;
+
+ f = fopen(path, mode);
+ if (f) {
+ *_f = f;
+ return 0;
+ }
+
+ return -errno;
+ }
+
+ s = strv_split_nulstr(search);
+ if (!s)
+ return -ENOMEM;
+
+ return search_and_fopen_internal(path, mode, root, s, _f);
+}
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
+ FILE *f;
+ char *t;
+ int r, fd;
+
+ assert(path);
+ assert(_f);
+ assert(_temp_path);
+
+ r = tempfn_xxxxxx(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
+ if (fd < 0) {
+ free(t);
+ return -errno;
+ }
+
+ f = fdopen(fd, "we");
+ if (!f) {
+ unlink_noerrno(t);
+ free(t);
+ safe_close(fd);
+ return -errno;
+ }
+
+ *_f = f;
+ *_temp_path = t;
+
+ return 0;
+}
+
+int fflush_and_check(FILE *f) {
+ assert(f);
+
+ errno = 0;
+ fflush(f);
+
+ if (ferror(f))
+ return errno ? -errno : -EIO;
+
+ return 0;
+}
+
+/* This is much like like mkostemp() but is subject to umask(). */
+int mkostemp_safe(char *pattern, int flags) {
+ _cleanup_umask_ mode_t u;
+ int fd;
+
+ assert(pattern);
+
+ u = umask(077);
+
+ fd = mkostemp(pattern, flags);
+ if (fd < 0)
+ return -errno;
+
+ return fd;
+}
+
+int open_tmpfile(const char *path, int flags) {
+ char *p;
+ int fd;
+
+ assert(path);
+
+#ifdef O_TMPFILE
+ /* Try O_TMPFILE first, if it is supported */
+ fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
+ if (fd >= 0)
+ return fd;
+#endif
+
+ /* Fall back to unguessable name + unlinking */
+ p = strjoina(path, "/systemd-tmp-XXXXXX");
+
+ fd = mkostemp_safe(p, flags);
+ if (fd < 0)
+ return fd;
+
+ unlink(p);
+ return fd;
+}
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
+ const char *fn;
+ char *t;
+
+ assert(p);
+ assert(ret);
+
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#<extra>waldoXXXXXX
+ */
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ if (extra == NULL)
+ extra = "";
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
+
+ *ret = path_kill_slashes(t);
+ return 0;
+}
+
+int tempfn_random(const char *p, const char *extra, char **ret) {
+ const char *fn;
+ char *t, *x;
+ uint64_t u;
+ unsigned i;
+
+ assert(p);
+ assert(ret);
+
+ /*
+ * Turns this:
+ * /foo/bar/waldo
+ *
+ * Into this:
+ * /foo/bar/.#<extra>waldobaa2a261115984a9
+ */
+
+ fn = basename(p);
+ if (!filename_is_valid(fn))
+ return -EINVAL;
+
+ if (!extra)
+ extra = "";
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
+
+ u = random_u64();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(u & 0xF);
+ u >>= 4;
+ }
+
+ *x = 0;
+
+ *ret = path_kill_slashes(t);
+ return 0;
+}
+
+int tempfn_random_child(const char *p, const char *extra, char **ret) {
+ char *t, *x;
+ uint64_t u;
+ unsigned i;
+
+ assert(p);
+ assert(ret);
+
+ /* Turns this:
+ * /foo/bar/waldo
+ * Into this:
+ * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
+ */
+
+ if (!extra)
+ extra = "";
+
+ t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
+ if (!t)
+ return -ENOMEM;
+
+ x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
+
+ u = random_u64();
+ for (i = 0; i < 16; i++) {
+ *(x++) = hexchar(u & 0xF);
+ u >>= 4;
+ }
+
+ *x = 0;
+
+ *ret = path_kill_slashes(t);
+ return 0;
+}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 2e8148ff24..fa7f192331 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -20,8 +20,12 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+
+#include <dirent.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
+#include <sys/types.h>
#include "macro.h"
@@ -48,4 +52,28 @@ int write_env_file(const char *fname, char **l);
int executable_is_script(const char *path, char **interpreter);
-int get_status_field(const char *filename, const char *pattern, char **field);
+int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
+
+DIR *xopendirat(int dirfd, const char *name, int flags);
+
+int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
+
+#define FOREACH_LINE(line, f, on_error) \
+ for (;;) \
+ if (!fgets(line, sizeof(line), f)) { \
+ if (ferror(f)) { \
+ on_error; \
+ } \
+ break; \
+ } else
+
+int fflush_and_check(FILE *f);
+
+int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
+int mkostemp_safe(char *pattern, int flags);
+int open_tmpfile(const char *path, int flags);
+
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
+int tempfn_random(const char *p, const char *extra, char **ret);
+int tempfn_random_child(const char *p, const char *extra, char **ret);
diff --git a/src/shared/formats-util.h b/src/basic/formats-util.h
index ce516b117d..ce516b117d 100644
--- a/src/shared/formats-util.h
+++ b/src/basic/formats-util.h
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
new file mode 100644
index 0000000000..7aee404bfc
--- /dev/null
+++ b/src/basic/fs-util.c
@@ -0,0 +1,480 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+
+int unlink_noerrno(const char *path) {
+ PROTECT_ERRNO;
+ int r;
+
+ r = unlink(path);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int rmdir_parents(const char *path, const char *stop) {
+ size_t l;
+ int r = 0;
+
+ assert(path);
+ assert(stop);
+
+ l = strlen(path);
+
+ /* Skip trailing slashes */
+ while (l > 0 && path[l-1] == '/')
+ l--;
+
+ while (l > 0) {
+ char *t;
+
+ /* Skip last component */
+ while (l > 0 && path[l-1] != '/')
+ l--;
+
+ /* Skip trailing slashes */
+ while (l > 0 && path[l-1] == '/')
+ l--;
+
+ if (l <= 0)
+ break;
+
+ t = strndup(path, l);
+ if (!t)
+ return -ENOMEM;
+
+ if (path_startswith(stop, t)) {
+ free(t);
+ return 0;
+ }
+
+ r = rmdir(t);
+ free(t);
+
+ if (r < 0)
+ if (errno != ENOENT)
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
+ struct stat buf;
+ int ret;
+
+ ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
+ if (ret >= 0)
+ return 0;
+
+ /* renameat2() exists since Linux 3.15, btrfs added support for it later.
+ * If it is not implemented, fallback to another method. */
+ if (!IN_SET(errno, EINVAL, ENOSYS))
+ return -errno;
+
+ /* The link()/unlink() fallback does not work on directories. But
+ * renameat() without RENAME_NOREPLACE gives the same semantics on
+ * directories, except when newpath is an *empty* directory. This is
+ * good enough. */
+ ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
+ if (ret >= 0 && S_ISDIR(buf.st_mode)) {
+ ret = renameat(olddirfd, oldpath, newdirfd, newpath);
+ return ret >= 0 ? 0 : -errno;
+ }
+
+ /* If it is not a directory, use the link()/unlink() fallback. */
+ ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
+ if (ret < 0)
+ return -errno;
+
+ ret = unlinkat(olddirfd, oldpath, 0);
+ if (ret < 0) {
+ /* backup errno before the following unlinkat() alters it */
+ ret = errno;
+ (void) unlinkat(newdirfd, newpath, 0);
+ errno = ret;
+ return -errno;
+ }
+
+ return 0;
+}
+
+int readlinkat_malloc(int fd, const char *p, char **ret) {
+ size_t l = 100;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ for (;;) {
+ char *c;
+ ssize_t n;
+
+ c = new(char, l);
+ if (!c)
+ return -ENOMEM;
+
+ n = readlinkat(fd, p, c, l-1);
+ if (n < 0) {
+ r = -errno;
+ free(c);
+ return r;
+ }
+
+ if ((size_t) n < l-1) {
+ c[n] = 0;
+ *ret = c;
+ return 0;
+ }
+
+ free(c);
+ l *= 2;
+ }
+}
+
+int readlink_malloc(const char *p, char **ret) {
+ return readlinkat_malloc(AT_FDCWD, p, ret);
+}
+
+int readlink_value(const char *p, char **ret) {
+ _cleanup_free_ char *link = NULL;
+ char *value;
+ int r;
+
+ r = readlink_malloc(p, &link);
+ if (r < 0)
+ return r;
+
+ value = basename(link);
+ if (!value)
+ return -ENOENT;
+
+ value = strdup(value);
+ if (!value)
+ return -ENOMEM;
+
+ *ret = value;
+
+ return 0;
+}
+
+int readlink_and_make_absolute(const char *p, char **r) {
+ _cleanup_free_ char *target = NULL;
+ char *k;
+ int j;
+
+ assert(p);
+ assert(r);
+
+ j = readlink_malloc(p, &target);
+ if (j < 0)
+ return j;
+
+ k = file_in_same_dir(p, target);
+ if (!k)
+ return -ENOMEM;
+
+ *r = k;
+ return 0;
+}
+
+int readlink_and_canonicalize(const char *p, char **r) {
+ char *t, *s;
+ int j;
+
+ assert(p);
+ assert(r);
+
+ j = readlink_and_make_absolute(p, &t);
+ if (j < 0)
+ return j;
+
+ s = canonicalize_file_name(t);
+ if (s) {
+ free(t);
+ *r = s;
+ } else
+ *r = t;
+
+ path_kill_slashes(*r);
+
+ return 0;
+}
+
+int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
+ assert(path);
+
+ /* Under the assumption that we are running privileged we
+ * first change the access mode and only then hand out
+ * ownership to avoid a window where access is too open. */
+
+ if (mode != MODE_INVALID)
+ if (chmod(path, mode) < 0)
+ return -errno;
+
+ if (uid != UID_INVALID || gid != GID_INVALID)
+ if (chown(path, uid, gid) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+ assert(fd >= 0);
+
+ /* Under the assumption that we are running privileged we
+ * first change the access mode and only then hand out
+ * ownership to avoid a window where access is too open. */
+
+ if (mode != MODE_INVALID)
+ if (fchmod(fd, mode) < 0)
+ return -errno;
+
+ if (uid != UID_INVALID || gid != GID_INVALID)
+ if (fchown(fd, uid, gid) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int fchmod_umask(int fd, mode_t m) {
+ mode_t u;
+ int r;
+
+ u = umask(0777);
+ r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
+ umask(u);
+
+ return r;
+}
+
+int fd_warn_permissions(const char *path, int fd) {
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (st.st_mode & 0111)
+ log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
+
+ if (st.st_mode & 0002)
+ log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
+
+ if (getpid() == 1 && (st.st_mode & 0044) != 0044)
+ log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
+
+ return 0;
+}
+
+int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
+ _cleanup_close_ int fd;
+ int r;
+
+ assert(path);
+
+ if (parents)
+ mkdir_parents(path, 0755);
+
+ fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
+ if (fd < 0)
+ return -errno;
+
+ if (mode > 0) {
+ r = fchmod(fd, mode);
+ if (r < 0)
+ return -errno;
+ }
+
+ if (uid != UID_INVALID || gid != GID_INVALID) {
+ r = fchown(fd, uid, gid);
+ if (r < 0)
+ return -errno;
+ }
+
+ if (stamp != USEC_INFINITY) {
+ struct timespec ts[2];
+
+ timespec_store(&ts[0], stamp);
+ ts[1] = ts[0];
+ r = futimens(fd, ts);
+ } else
+ r = futimens(fd, NULL);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int touch(const char *path) {
+ return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
+}
+
+int symlink_idempotent(const char *from, const char *to) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ assert(from);
+ assert(to);
+
+ if (symlink(from, to) < 0) {
+ if (errno != EEXIST)
+ return -errno;
+
+ r = readlink_malloc(to, &p);
+ if (r < 0)
+ return r;
+
+ if (!streq(p, from))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int symlink_atomic(const char *from, const char *to) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(from);
+ assert(to);
+
+ r = tempfn_random(to, NULL, &t);
+ if (r < 0)
+ return r;
+
+ if (symlink(from, t) < 0)
+ return -errno;
+
+ if (rename(t, to) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
+int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(path);
+
+ r = tempfn_random(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ if (mknod(t, mode, dev) < 0)
+ return -errno;
+
+ if (rename(t, path) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
+int mkfifo_atomic(const char *path, mode_t mode) {
+ _cleanup_free_ char *t = NULL;
+ int r;
+
+ assert(path);
+
+ r = tempfn_random(path, NULL, &t);
+ if (r < 0)
+ return r;
+
+ if (mkfifo(t, mode) < 0)
+ return -errno;
+
+ if (rename(t, path) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
+
+ return 0;
+}
+
+int get_files_in_directory(const char *path, char ***list) {
+ _cleanup_closedir_ DIR *d = NULL;
+ size_t bufsize = 0, n = 0;
+ _cleanup_strv_free_ char **l = NULL;
+
+ assert(path);
+
+ /* Returns all files in a directory in *list, and the number
+ * of files as return value. If list is NULL returns only the
+ * number. */
+
+ d = opendir(path);
+ if (!d)
+ return -errno;
+
+ for (;;) {
+ struct dirent *de;
+
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
+ if (!de)
+ break;
+
+ dirent_ensure_type(d, de);
+
+ if (!dirent_is_file(de))
+ continue;
+
+ if (list) {
+ /* one extra slot is needed for the terminating NULL */
+ if (!GREEDY_REALLOC(l, bufsize, n + 2))
+ return -ENOMEM;
+
+ l[n] = strdup(de->d_name);
+ if (!l[n])
+ return -ENOMEM;
+
+ l[++n] = NULL;
+ } else
+ n++;
+ }
+
+ if (list) {
+ *list = l;
+ l = NULL; /* avoid freeing */
+ }
+
+ return n;
+}
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
new file mode 100644
index 0000000000..b94873e65b
--- /dev/null
+++ b/src/basic/fs-util.h
@@ -0,0 +1,74 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "time-util.h"
+
+int unlink_noerrno(const char *path);
+
+int rmdir_parents(const char *path, const char *stop);
+
+int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+int readlinkat_malloc(int fd, const char *p, char **ret);
+int readlink_malloc(const char *p, char **r);
+int readlink_value(const char *p, char **ret);
+int readlink_and_make_absolute(const char *p, char **r);
+int readlink_and_canonicalize(const char *p, char **r);
+
+int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
+
+int fchmod_umask(int fd, mode_t mode);
+
+int fd_warn_permissions(const char *path, int fd);
+
+#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
+
+int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
+int touch(const char *path);
+
+int symlink_idempotent(const char *from, const char *to);
+
+int symlink_atomic(const char *from, const char *to);
+int mknod_atomic(const char *path, mode_t mode, dev_t dev);
+int mkfifo_atomic(const char *path, mode_t mode);
+
+int get_files_in_directory(const char *path, char ***list);
+
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
+
+#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
+ for ((e) = &buffer.ev; \
+ (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
+ (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
+
+union inotify_event_buffer {
+ struct inotify_event ev;
+ uint8_t raw[INOTIFY_EVENT_MAX];
+};
diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c
new file mode 100644
index 0000000000..0bfbcb1d37
--- /dev/null
+++ b/src/basic/glob-util.c
@@ -0,0 +1,72 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <glob.h>
+
+#include "glob-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+
+int glob_exists(const char *path) {
+ _cleanup_globfree_ glob_t g = {};
+ int k;
+
+ assert(path);
+
+ errno = 0;
+ k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+ if (k == GLOB_NOMATCH)
+ return 0;
+ if (k == GLOB_NOSPACE)
+ return -ENOMEM;
+ if (k != 0)
+ return errno ? -errno : -EIO;
+
+ return !strv_isempty(g.gl_pathv);
+}
+
+int glob_extend(char ***strv, const char *path) {
+ _cleanup_globfree_ glob_t g = {};
+ int k;
+ char **p;
+
+ errno = 0;
+ k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+ if (k == GLOB_NOMATCH)
+ return -ENOENT;
+ if (k == GLOB_NOSPACE)
+ return -ENOMEM;
+ if (k != 0)
+ return errno ? -errno : -EIO;
+ if (strv_isempty(g.gl_pathv))
+ return -ENOENT;
+
+ STRV_FOREACH(p, g.gl_pathv) {
+ k = strv_extend(strv, *p);
+ if (k < 0)
+ return k;
+ }
+
+ return 0;
+}
diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h
new file mode 100644
index 0000000000..793adf4a6c
--- /dev/null
+++ b/src/basic/glob-util.h
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "macro.h"
+#include "string-util.h"
+
+int glob_exists(const char *path);
+int glob_extend(char ***strv, const char *path);
+
+#define _cleanup_globfree_ _cleanup_(globfree)
+
+_pure_ static inline bool string_is_glob(const char *p) {
+ /* Check if a string contains any glob patterns. */
+ return !!strpbrk(p, GLOB_CHARS);
+}
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 7d2a4160c6..4109a08c6c 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -20,18 +20,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
+#include <stdlib.h>
-#include "util.h"
+#include "alloc-util.h"
#include "hashmap.h"
-#include "set.h"
#include "macro.h"
-#include "siphash24.h"
-#include "strv.h"
#include "mempool.h"
+#include "process-util.h"
#include "random-util.h"
+#include "set.h"
+#include "siphash24.h"
+#include "strv.h"
+#include "util.h"
#ifdef ENABLE_DEBUG_HASHMAP
#include "list.h"
@@ -276,10 +278,8 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
},
};
-unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, strlen(p), hash_key);
- return (unsigned long) u;
+void string_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, strlen(p) + 1, state);
}
int string_compare_func(const void *a, const void *b) {
@@ -291,10 +291,8 @@ const struct hash_ops string_hash_ops = {
.compare = string_compare_func
};
-unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, &p, sizeof(p), hash_key);
- return (unsigned long) u;
+void trivial_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(&p, sizeof(p), state);
}
int trivial_compare_func(const void *a, const void *b) {
@@ -306,10 +304,8 @@ const struct hash_ops trivial_hash_ops = {
.compare = trivial_compare_func
};
-unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key);
- return (unsigned long) u;
+void uint64_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(uint64_t), state);
}
int uint64_compare_func(const void *_a, const void *_b) {
@@ -325,10 +321,8 @@ const struct hash_ops uint64_hash_ops = {
};
#if SIZEOF_DEV_T != 8
-unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, sizeof(dev_t), hash_key);
- return (unsigned long) u;
+void devt_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(dev_t), state);
}
int devt_compare_func(const void *_a, const void *_b) {
@@ -379,7 +373,16 @@ static uint8_t *hash_key(HashmapBase *h) {
}
static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
- return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h));
+ struct siphash state;
+ uint64_t hash;
+
+ siphash24_init(&state, hash_key(h));
+
+ h->hash_ops->hash(p, &state);
+
+ siphash24_finalize((uint8_t*)&hash, &state);
+
+ return (unsigned) (hash % n_buckets(h));
}
#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index 2af23024de..ed6a092d82 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "macro.h"
+#include "siphash24.h"
#include "util.h"
/*
@@ -67,7 +68,7 @@ typedef struct {
#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 void (*hash_func_t)(const void *p, struct siphash *state);
typedef int (*compare_func_t)(const void *a, const void *b);
struct hash_ops {
@@ -75,28 +76,28 @@ struct hash_ops {
compare_func_t compare;
};
-unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void string_hash_func(const void *p, struct siphash *state);
int string_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops string_hash_ops;
/* This will compare the passed pointers directly, and will not
* dereference them. This is hence not useful for strings or
* suchlike. */
-unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void trivial_hash_func(const void *p, struct siphash *state);
int trivial_compare_func(const void *a, const void *b) _const_;
extern const struct hash_ops trivial_hash_ops;
/* 32bit values we can always just embedd in the pointer itself, but
* in order to support 32bit archs we need store 64bit values
* indirectly, since they don't fit in a pointer. */
-unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void uint64_hash_func(const void *p, struct siphash *state);
int uint64_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops uint64_hash_ops;
/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
* it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
#if SIZEOF_DEV_T != 8
-unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void devt_hash_func(const void *p, struct siphash *state) _pure_;
int devt_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops devt_hash_ops = {
.hash = devt_hash_func,
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
new file mode 100644
index 0000000000..4eb566b15a
--- /dev/null
+++ b/src/basic/hexdecoct.c
@@ -0,0 +1,698 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "alloc-util.h"
+#include "hexdecoct.h"
+#include "util.h"
+
+char octchar(int x) {
+ return '0' + (x & 7);
+}
+
+int unoctchar(char c) {
+
+ if (c >= '0' && c <= '7')
+ return c - '0';
+
+ return -EINVAL;
+}
+
+char decchar(int x) {
+ return '0' + (x % 10);
+}
+
+int undecchar(char c) {
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ return -EINVAL;
+}
+
+char hexchar(int x) {
+ static const char table[16] = "0123456789abcdef";
+
+ return table[x & 15];
+}
+
+int unhexchar(char c) {
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+
+ return -EINVAL;
+}
+
+char *hexmem(const void *p, size_t l) {
+ char *r, *z;
+ const uint8_t *x;
+
+ z = r = malloc(l * 2 + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + l; x++) {
+ *(z++) = hexchar(*x >> 4);
+ *(z++) = hexchar(*x & 15);
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ uint8_t *z;
+ const char *x;
+
+ assert(mem);
+ assert(len);
+ assert(p);
+
+ z = r = malloc((l + 1) / 2 + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + l; x += 2) {
+ int a, b;
+
+ a = unhexchar(x[0]);
+ if (a < 0)
+ return a;
+ else if (x+1 < p + l) {
+ b = unhexchar(x[1]);
+ if (b < 0)
+ return b;
+ } else
+ b = 0;
+
+ *(z++) = (uint8_t) a << 4 | (uint8_t) b;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *len = (l + 1) / 2;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-6
+ * Notice that base32hex differs from base32 in the alphabet it uses.
+ * The distinction is that the base32hex representation preserves the
+ * order of the underlying data when compared as bytestrings, this is
+ * useful when representing NSEC3 hashes, as one can then verify the
+ * order of hashes directly from their representation. */
+char base32hexchar(int x) {
+ static const char table[32] = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUV";
+
+ return table[x & 31];
+}
+
+int unbase32hexchar(char c) {
+ unsigned offset;
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ offset = '9' - '0' + 1;
+
+ if (c >= 'A' && c <= 'V')
+ return c - 'A' + offset;
+
+ return -EINVAL;
+}
+
+char *base32hexmem(const void *p, size_t l, bool padding) {
+ char *r, *z;
+ const uint8_t *x;
+ size_t len;
+
+ if (padding)
+ /* five input bytes makes eight output bytes, padding is added so we must round up */
+ len = 8 * (l + 4) / 5;
+ else {
+ /* same, but round down as there is no padding */
+ len = 8 * l / 5;
+
+ switch (l % 5) {
+ case 4:
+ len += 7;
+ break;
+ case 3:
+ len += 5;
+ break;
+ case 2:
+ len += 4;
+ break;
+ case 1:
+ len += 2;
+ break;
+ }
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
+ x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
+ *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
+ }
+
+ switch (l % 5) {
+ case 4:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
+ if (padding)
+ *(z++) = '=';
+
+ break;
+
+ case 3:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 2:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 1:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d, e, f, g, h;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+ unsigned pad = 0;
+
+ assert(p);
+
+ /* padding ensures any base32hex input has input divisible by 8 */
+ if (padding && l % 8 != 0)
+ return -EINVAL;
+
+ if (padding) {
+ /* strip the padding */
+ while (l > 0 && p[l - 1] == '=' && pad < 7) {
+ pad ++;
+ l --;
+ }
+ }
+
+ /* a group of eight input bytes needs five output bytes, in case of
+ padding we need to add some extra bytes */
+ len = (l / 8) * 5;
+
+ switch (l % 8) {
+ case 7:
+ len += 4;
+ break;
+ case 5:
+ len += 3;
+ break;
+ case 4:
+ len += 2;
+ break;
+ case 2:
+ len += 1;
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 8) * 8; x += 8) {
+ /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
+ e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ h = unbase32hexchar(x[7]);
+ if (h < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+ *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
+ }
+
+ switch (l % 8) {
+ case 7:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ /* g == 000VV000 */
+ if (g & 7)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+
+ break;
+ case 5:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ /* e == 000SSSS0 */
+ if (e & 1)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+
+ break;
+ case 4:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ /* d == 000W0000 */
+ if (d & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+
+ break;
+ case 2:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 000YYY00 */
+ if (b & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-4 */
+char base64char(int x) {
+ static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ return table[x & 63];
+}
+
+int unbase64char(char c) {
+ unsigned offset;
+
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+
+ offset = 'Z' - 'A' + 1;
+
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + offset;
+
+ offset += 'z' - 'a' + 1;
+
+ if (c >= '0' && c <= '9')
+ return c - '0' + offset;
+
+ offset += '9' - '0' + 1;
+
+ if (c == '+')
+ return offset;
+
+ offset ++;
+
+ if (c == '/')
+ return offset;
+
+ return -EINVAL;
+}
+
+char *base64mem(const void *p, size_t l) {
+ char *r, *z;
+ const uint8_t *x;
+
+ /* three input bytes makes four output bytes, padding is added so we must round up */
+ z = r = malloc(4 * (l + 2) / 3 + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
+ *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
+ }
+
+ switch (l % 3) {
+ case 2:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
+ *(z++) = '=';
+
+ break;
+ case 1:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
+ *(z++) = '=';
+ *(z++) = '=';
+
+ break;
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+
+ assert(p);
+
+ /* padding ensures any base63 input has input divisible by 4 */
+ if (l % 4 != 0)
+ return -EINVAL;
+
+ /* strip the padding */
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+
+ /* a group of four input bytes needs three output bytes, in case of
+ padding we need to add two or three extra bytes */
+ len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 4) * 4; x += 4) {
+ /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase64char(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+ *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
+ }
+
+ switch (l % 4) {
+ case 3:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ /* c == 00ZZZZ00 */
+ if (c & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+
+ break;
+ case 2:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 00YY0000 */
+ if (b & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+
+ break;
+ case 0:
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
+void hexdump(FILE *f, const void *p, size_t s) {
+ const uint8_t *b = p;
+ unsigned n = 0;
+
+ assert(s == 0 || b);
+
+ while (s > 0) {
+ size_t i;
+
+ fprintf(f, "%04x ", n);
+
+ for (i = 0; i < 16; i++) {
+
+ if (i >= s)
+ fputs(" ", f);
+ else
+ fprintf(f, "%02x ", b[i]);
+
+ if (i == 7)
+ fputc(' ', f);
+ }
+
+ fputc(' ', f);
+
+ for (i = 0; i < 16; i++) {
+
+ if (i >= s)
+ fputc(' ', f);
+ else
+ fputc(isprint(b[i]) ? (char) b[i] : '.', f);
+ }
+
+ fputc('\n', f);
+
+ if (s < 16)
+ break;
+
+ n += 16;
+ b += 16;
+ s -= 16;
+ }
+}
diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h
new file mode 100644
index 0000000000..4aeb4c3bdc
--- /dev/null
+++ b/src/basic/hexdecoct.h
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+char octchar(int x) _const_;
+int unoctchar(char c) _const_;
+
+char decchar(int x) _const_;
+int undecchar(char c) _const_;
+
+char hexchar(int x) _const_;
+int unhexchar(char c) _const_;
+
+char *hexmem(const void *p, size_t l);
+int unhexmem(const char *p, size_t l, void **mem, size_t *len);
+
+char base32hexchar(int x) _const_;
+int unbase32hexchar(char c) _const_;
+
+char base64char(int x) _const_;
+int unbase64char(char c) _const_;
+
+char *base32hexmem(const void *p, size_t l, bool padding);
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
+
+char *base64mem(const void *p, size_t l);
+int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
+
+void hexdump(FILE *f, const void *p, size_t s);
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index 1b816fb77a..ea0528c6fc 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/utsname.h>
#include <ctype.h>
+#include <sys/utsname.h>
-#include "util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "hostname-util.h"
+#include "string-util.h"
+#include "util.h"
bool hostname_is_set(void) {
struct utsname u;
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index d88864b598..f4e24121e7 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -21,6 +21,7 @@
#include <arpa/inet.h>
+#include "alloc-util.h"
#include "in-addr-util.h"
int in_addr_is_null(int family, const union in_addr_union *u) {
diff --git a/src/basic/io-util.c b/src/basic/io-util.c
new file mode 100644
index 0000000000..ac8f93ff57
--- /dev/null
+++ b/src/basic/io-util.c
@@ -0,0 +1,261 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <poll.h>
+#include <unistd.h>
+
+#include "io-util.h"
+
+int flush_fd(int fd) {
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = POLLIN,
+ };
+
+ for (;;) {
+ char buf[LINE_MAX];
+ ssize_t l;
+ int r;
+
+ r = poll(&pollfd, 1, 0);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+
+ } else if (r == 0)
+ return 0;
+
+ l = read(fd, buf, sizeof(buf));
+ if (l < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN)
+ return 0;
+
+ return -errno;
+ } else if (l == 0)
+ return 0;
+ }
+}
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
+ uint8_t *p = buf;
+ ssize_t n = 0;
+
+ assert(fd >= 0);
+ assert(buf);
+
+ /* If called with nbytes == 0, let's call read() at least
+ * once, to validate the operation */
+
+ if (nbytes > (size_t) SSIZE_MAX)
+ return -EINVAL;
+
+ do {
+ ssize_t k;
+
+ k = read(fd, p, nbytes);
+ if (k < 0) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN && do_poll) {
+
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via read() */
+
+ (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+ continue;
+ }
+
+ return n > 0 ? n : -errno;
+ }
+
+ if (k == 0)
+ return n;
+
+ assert((size_t) k <= nbytes);
+
+ p += k;
+ nbytes -= k;
+ n += k;
+ } while (nbytes > 0);
+
+ return n;
+}
+
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
+ ssize_t n;
+
+ n = loop_read(fd, buf, nbytes, do_poll);
+ if (n < 0)
+ return (int) n;
+ if ((size_t) n != nbytes)
+ return -EIO;
+
+ return 0;
+}
+
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
+ const uint8_t *p = buf;
+
+ assert(fd >= 0);
+ assert(buf);
+
+ if (nbytes > (size_t) SSIZE_MAX)
+ return -EINVAL;
+
+ do {
+ ssize_t k;
+
+ k = write(fd, p, nbytes);
+ if (k < 0) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN && do_poll) {
+ /* We knowingly ignore any return value here,
+ * and expect that any error/EOF is reported
+ * via write() */
+
+ (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
+ continue;
+ }
+
+ return -errno;
+ }
+
+ if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
+ return -EIO;
+
+ assert((size_t) k <= nbytes);
+
+ p += k;
+ nbytes -= k;
+ } while (nbytes > 0);
+
+ return 0;
+}
+
+int pipe_eof(int fd) {
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = POLLIN|POLLHUP,
+ };
+
+ int r;
+
+ r = poll(&pollfd, 1, 0);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents & POLLHUP;
+}
+
+int fd_wait_for_event(int fd, int event, usec_t t) {
+
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = event,
+ };
+
+ struct timespec ts;
+ int r;
+
+ r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
+ if (r < 0)
+ return -errno;
+
+ if (r == 0)
+ return 0;
+
+ return pollfd.revents;
+}
+
+static size_t nul_length(const uint8_t *p, size_t sz) {
+ size_t n = 0;
+
+ while (sz > 0) {
+ if (*p != 0)
+ break;
+
+ n++;
+ p++;
+ sz--;
+ }
+
+ return n;
+}
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
+ const uint8_t *q, *w, *e;
+ ssize_t l;
+
+ q = w = p;
+ e = q + sz;
+ while (q < e) {
+ size_t n;
+
+ n = nul_length(q, e - q);
+
+ /* If there are more than the specified run length of
+ * NUL bytes, or if this is the beginning or the end
+ * of the buffer, then seek instead of write */
+ if ((n > run_length) ||
+ (n > 0 && q == p) ||
+ (n > 0 && q + n >= e)) {
+ if (q > w) {
+ l = write(fd, w, q - w);
+ if (l < 0)
+ return -errno;
+ if (l != q -w)
+ return -EIO;
+ }
+
+ if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
+ return -errno;
+
+ q += n;
+ w = q;
+ } else if (n > 0)
+ q += n;
+ else
+ q ++;
+ }
+
+ if (q > w) {
+ l = write(fd, w, q - w);
+ if (l < 0)
+ return -errno;
+ if (l != q - w)
+ return -EIO;
+ }
+
+ return q - (const uint8_t*) p;
+}
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
new file mode 100644
index 0000000000..cd2aa75ad2
--- /dev/null
+++ b/src/basic/io-util.h
@@ -0,0 +1,76 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include "time-util.h"
+
+int flush_fd(int fd);
+
+ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
+int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
+int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
+
+int pipe_eof(int fd);
+
+int fd_wait_for_event(int fd, int event, usec_t timeout);
+
+ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
+
+#define IOVEC_SET_STRING(i, s) \
+ do { \
+ struct iovec *_i = &(i); \
+ char *_s = (char *)(s); \
+ _i->iov_base = _s; \
+ _i->iov_len = strlen(_s); \
+ } while(false)
+
+static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
+ unsigned j;
+ size_t r = 0;
+
+ for (j = 0; j < n; j++)
+ r += i[j].iov_len;
+
+ return r;
+}
+
+static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
+ unsigned j;
+
+ for (j = 0; j < n; j++) {
+ size_t sub;
+
+ if (_unlikely_(k <= 0))
+ break;
+
+ sub = MIN(i[j].iov_len, k);
+ i[j].iov_len -= sub;
+ i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
+ k -= sub;
+ }
+
+ return k;
+}
diff --git a/src/basic/json.c b/src/basic/json.c
index be40a0d203..716705e5ff 100644
--- a/src/basic/json.c
+++ b/src/basic/json.c
@@ -19,11 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <math.h>
+#include <sys/types.h>
+
+#include "alloc-util.h"
+#include "json.h"
#include "macro.h"
+#include "hexdecoct.h"
+#include "string-util.h"
#include "utf8.h"
-#include "json.h"
int json_variant_new(JsonVariant **ret, JsonVariantType type) {
JsonVariant *v;
diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c
index 61db9a8125..b87fd7670b 100644
--- a/src/basic/locale-util.c
+++ b/src/basic/locale-util.c
@@ -19,14 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <langinfo.h>
+#include <locale.h>
#include <sys/mman.h>
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "locale-util.h"
+#include "path-util.h"
#include "set.h"
-#include "util.h"
-#include "utf8.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
-
-#include "locale-util.h"
+#include "utf8.h"
+#include "util.h"
static int add_locales_from_archive(Set *locales) {
/* Stolen from glibc... */
@@ -204,6 +210,88 @@ bool locale_is_valid(const char *name) {
return true;
}
+void init_gettext(void) {
+ setlocale(LC_ALL, "");
+ textdomain(GETTEXT_PACKAGE);
+}
+
+bool is_locale_utf8(void) {
+ const char *set;
+ static int cached_answer = -1;
+
+ /* Note that we default to 'true' here, since today UTF8 is
+ * pretty much supported everywhere. */
+
+ if (cached_answer >= 0)
+ goto out;
+
+ if (!setlocale(LC_ALL, "")) {
+ cached_answer = true;
+ goto out;
+ }
+
+ set = nl_langinfo(CODESET);
+ if (!set) {
+ cached_answer = true;
+ goto out;
+ }
+
+ if (streq(set, "UTF-8")) {
+ cached_answer = true;
+ goto out;
+ }
+
+ /* For LC_CTYPE=="C" return true, because CTYPE is effectly
+ * unset and everything can do to UTF-8 nowadays. */
+ set = setlocale(LC_CTYPE, NULL);
+ if (!set) {
+ cached_answer = true;
+ goto out;
+ }
+
+ /* Check result, but ignore the result if C was set
+ * explicitly. */
+ cached_answer =
+ STR_IN_SET(set, "C", "POSIX") &&
+ !getenv("LC_ALL") &&
+ !getenv("LC_CTYPE") &&
+ !getenv("LANG");
+
+out:
+ return (bool) cached_answer;
+}
+
+
+const char *draw_special_char(DrawSpecialChar ch) {
+
+ static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
+
+ /* UTF-8 */ {
+ [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
+ [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
+ [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
+ [DRAW_TREE_SPACE] = " ", /* */
+ [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
+ [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
+ [DRAW_ARROW] = "\342\206\222", /* → */
+ [DRAW_DASH] = "\342\200\223", /* – */
+ },
+
+ /* ASCII fallback */ {
+ [DRAW_TREE_VERTICAL] = "| ",
+ [DRAW_TREE_BRANCH] = "|-",
+ [DRAW_TREE_RIGHT] = "`-",
+ [DRAW_TREE_SPACE] = " ",
+ [DRAW_TRIANGULAR_BULLET] = ">",
+ [DRAW_BLACK_CIRCLE] = "*",
+ [DRAW_ARROW] = "->",
+ [DRAW_DASH] = "-",
+ }
+ };
+
+ return draw_table[!is_locale_utf8()][ch];
+}
+
static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
[VARIABLE_LANG] = "LANG",
[VARIABLE_LANGUAGE] = "LANGUAGE",
diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h
index e48aa3d9af..c71d145139 100644
--- a/src/basic/locale-util.h
+++ b/src/basic/locale-util.h
@@ -21,6 +21,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <libintl.h>
#include <stdbool.h>
#include "macro.h"
@@ -50,5 +51,25 @@ typedef enum LocaleVariable {
int get_locales(char ***l);
bool locale_is_valid(const char *name);
+#define _(String) gettext(String)
+#define N_(String) String
+void init_gettext(void);
+
+bool is_locale_utf8(void);
+
+typedef enum DrawSpecialChar {
+ DRAW_TREE_VERTICAL,
+ DRAW_TREE_BRANCH,
+ DRAW_TREE_RIGHT,
+ DRAW_TREE_SPACE,
+ DRAW_TRIANGULAR_BULLET,
+ DRAW_BLACK_CIRCLE,
+ DRAW_ARROW,
+ DRAW_DASH,
+ _DRAW_SPECIAL_CHAR_MAX
+} DrawSpecialChar;
+
+const char *draw_special_char(DrawSpecialChar ch);
+
const char* locale_variable_to_string(LocaleVariable i) _const_;
LocaleVariable locale_variable_from_string(const char *s) _pure_;
diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c
index f3ec6a3e52..87c3aef7af 100644
--- a/src/basic/lockfile-util.c
+++ b/src/basic/lockfile-util.c
@@ -27,9 +27,13 @@
#include <limits.h>
#include <sys/file.h>
-#include "util.h"
-#include "lockfile-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
+#include "lockfile-util.h"
+#include "path-util.h"
+#include "util.h"
int make_lock_file(const char *p, int operation, LockFile *ret) {
_cleanup_close_ int fd = -1;
diff --git a/src/basic/log.c b/src/basic/log.c
index 38f42b3a6e..fe29cacd9e 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -19,26 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdarg.h>
-#include <stdio.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <stddef.h>
-#include <printf.h>
+#include <unistd.h>
#include "sd-messages.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
#include "log.h"
-#include "util.h"
-#include "missing.h"
#include "macro.h"
-#include "socket-util.h"
-#include "formats-util.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
#include "process-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
@@ -435,7 +445,7 @@ static int write_to_syslog(
static int write_to_kmsg(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *object_field,
@@ -506,7 +516,7 @@ static int log_do_header(
static int write_to_journal(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *object_field,
@@ -640,7 +650,7 @@ int log_dump_internal(
int log_internalv(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *format,
@@ -667,7 +677,7 @@ int log_internalv(
int log_internal(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *format, ...) {
@@ -685,7 +695,7 @@ int log_internal(
int log_object_internalv(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *object_field,
@@ -729,7 +739,7 @@ int log_object_internalv(
int log_object_internal(
int level,
int error,
- const char*file,
+ const char *file,
int line,
const char *func,
const char *object_field,
@@ -922,7 +932,7 @@ int log_set_max_level_from_string(const char *e) {
t = log_level_from_string(e);
if (t < 0)
- return t;
+ return -EINVAL;
log_set_max_level(t);
return 0;
diff --git a/src/basic/log.h b/src/basic/log.h
index 569762d083..cda1e45cc8 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -21,14 +21,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
+#include <errno.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdlib.h>
-#include <syslog.h>
#include <sys/signalfd.h>
-#include <errno.h>
+#include <syslog.h>
#include "sd-id128.h"
+
#include "macro.h"
typedef enum LogTarget{
@@ -227,3 +228,15 @@ int log_syntax_internal(
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
: -abs(_e); \
})
+
+#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
+ ({ \
+ int _level = (level); \
+ if (log_get_max_level() >= LOG_PRI(_level)) { \
+ _cleanup_free_ char *_p = NULL; \
+ _p = utf8_escape_invalid(rvalue); \
+ log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \
+ "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
+ } \
+ -EINVAL; \
+ })
diff --git a/src/basic/login-util.c b/src/basic/login-util.c
index e25437f0f4..832f477bd2 100644
--- a/src/basic/login-util.c
+++ b/src/basic/login-util.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "login-util.h"
#include "def.h"
+#include "string-util.h"
+#include "login-util.h"
bool session_id_valid(const char *id) {
diff --git a/src/basic/login-util.h b/src/basic/login-util.h
index a79f20c1b1..be5bb64870 100644
--- a/src/basic/login-util.h
+++ b/src/basic/login-util.h
@@ -22,5 +22,10 @@
#pragma once
#include <stdbool.h>
+#include <unistd.h>
bool session_id_valid(const char *id);
+
+static inline bool logind_running(void) {
+ return access("/run/systemd/seats/", F_OK) >= 0;
+}
diff --git a/src/basic/macro.h b/src/basic/macro.h
index f55d65e2f1..5088e6720d 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -22,11 +22,10 @@
***/
#include <assert.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/uio.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <sys/param.h>
+#include <sys/types.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -295,111 +294,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p)))
#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u)))
-/* The following macros add 1 when converting things, since UID 0 is a
- * valid UID, while the pointer NULL is special */
-#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
-#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
-
-#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
-#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
-
-#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
-#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
-
-#define memzero(x,l) (memset((x), 0, (l)))
-#define zero(x) (memzero(&(x), sizeof(x)))
-
#define CHAR_TO_STR(x) ((char[2]) { x, 0 })
#define char_array_0(x) x[sizeof(x)-1] = 0;
-#define IOVEC_SET_STRING(i, s) \
- do { \
- struct iovec *_i = &(i); \
- char *_s = (char *)(s); \
- _i->iov_base = _s; \
- _i->iov_len = strlen(_s); \
- } while(false)
-
-static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
- unsigned j;
- size_t r = 0;
-
- for (j = 0; j < n; j++)
- r += i[j].iov_len;
-
- return r;
-}
-
-static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
- unsigned j;
-
- for (j = 0; j < n; j++) {
- size_t sub;
-
- if (_unlikely_(k <= 0))
- break;
-
- sub = MIN(i[j].iov_len, k);
- i[j].iov_len -= sub;
- i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
- k -= sub;
- }
-
- return k;
-}
-
-#define VA_FORMAT_ADVANCE(format, ap) \
-do { \
- int _argtypes[128]; \
- size_t _i, _k; \
- _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
- assert(_k < ELEMENTSOF(_argtypes)); \
- for (_i = 0; _i < _k; _i++) { \
- if (_argtypes[_i] & PA_FLAG_PTR) { \
- (void) va_arg(ap, void*); \
- continue; \
- } \
- \
- switch (_argtypes[_i]) { \
- case PA_INT: \
- case PA_INT|PA_FLAG_SHORT: \
- case PA_CHAR: \
- (void) va_arg(ap, int); \
- break; \
- case PA_INT|PA_FLAG_LONG: \
- (void) va_arg(ap, long int); \
- break; \
- case PA_INT|PA_FLAG_LONG_LONG: \
- (void) va_arg(ap, long long int); \
- break; \
- case PA_WCHAR: \
- (void) va_arg(ap, wchar_t); \
- break; \
- case PA_WSTRING: \
- case PA_STRING: \
- case PA_POINTER: \
- (void) va_arg(ap, void*); \
- break; \
- case PA_FLOAT: \
- case PA_DOUBLE: \
- (void) va_arg(ap, double); \
- break; \
- case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
- (void) va_arg(ap, long double); \
- break; \
- default: \
- assert_not_reached("Unknown format string argument."); \
- } \
- } \
-} while(false)
-
- /* Because statfs.t_type can be int on some architectures, we have to cast
- * the const magic to the type, otherwise the compiler warns about
- * signed/unsigned comparison, because the magic can be 32 bit unsigned.
- */
-#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
-
/* Returns the number of chars needed to format variables of the
* specified type as a decimal string. Adds in extra space for a
* negative '-' prefix (hence works correctly on signed
@@ -410,6 +308,15 @@ do { \
sizeof(type) <= 4 ? 10 : \
sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)])))
+#define DECIMAL_STR_WIDTH(x) \
+ ({ \
+ typeof(x) _x_ = (x); \
+ unsigned ans = 1; \
+ while (_x_ /= 10) \
+ ans++; \
+ ans; \
+ })
+
#define SET_FLAG(v, flag, b) \
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
@@ -427,21 +334,6 @@ do { \
_found; \
})
-/* Return a nulstr for a standard cascade of configuration directories,
- * suitable to pass to conf_files_list_nulstr or config_parse_many. */
-#define CONF_DIRS_NULSTR(n) \
- "/etc/" n ".d\0" \
- "/run/" n ".d\0" \
- "/usr/local/lib/" n ".d\0" \
- "/usr/lib/" n ".d\0" \
- CONF_DIR_SPLIT_USR(n)
-
-#ifdef HAVE_SPLIT_USR
-#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0"
-#else
-#define CONF_DIR_SPLIT_USR(n)
-#endif
-
/* Define C11 thread_local attribute even on older gcc compiler
* version */
#ifndef thread_local
@@ -466,10 +358,6 @@ do { \
#endif
#endif
-#define UID_INVALID ((uid_t) -1)
-#define GID_INVALID ((gid_t) -1)
-#define MODE_INVALID ((mode_t) -1)
-
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
@@ -477,7 +365,4 @@ do { \
} \
struct __useless_struct_to_allow_trailing_semicolon__
-#define CMSG_FOREACH(cmsg, mh) \
- for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
-
#include "log.h"
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index e99a738e1f..92630f6b25 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -19,19 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-
#ifdef HAVE_LINUX_MEMFD_H
-# include <linux/memfd.h>
+#include <linux/memfd.h>
#endif
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "memfd-util.h"
-#include "utf8.h"
#include "missing.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
int memfd_new(const char *name) {
_cleanup_free_ char *g = NULL;
diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h
index 3ed551fb37..2cb404ea81 100644
--- a/src/basic/memfd-util.h
+++ b/src/basic/memfd-util.h
@@ -21,7 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
+#include <sys/types.h>
+#include <inttypes.h>
int memfd_new(const char *name);
int memfd_new_and_map(const char *name, size_t sz, void **p);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 9811b6b23e..306c56a156 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -126,6 +126,10 @@
#define SOL_NETLINK 270
#endif
+#ifndef NETLINK_LIST_MEMBERSHIPS
+#define NETLINK_LIST_MEMBERSHIPS 9
+#endif
+
#if !HAVE_DECL_PIVOT_ROOT
static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
@@ -248,6 +252,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
#endif
+#ifndef BTRFS_QGROUP_LEVEL_SHIFT
+#define BTRFS_QGROUP_LEVEL_SHIFT 48
+#endif
+
#ifndef HAVE_LINUX_BTRFS_H
struct btrfs_ioctl_vol_args {
int64_t fd;
@@ -486,6 +494,10 @@ struct btrfs_ioctl_quota_ctl_args {
#define BTRFS_QGROUP_LIMIT_KEY 244
#endif
+#ifndef BTRFS_QGROUP_RELATION_KEY
+#define BTRFS_QGROUP_RELATION_KEY 246
+#endif
+
#ifndef BTRFS_ROOT_BACKREF_KEY
#define BTRFS_ROOT_BACKREF_KEY 144
#endif
@@ -842,6 +854,19 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_BR_PRIORITY
+#define IFLA_BR_UNSPEC 0
+#define IFLA_BR_FORWARD_DELAY 1
+#define IFLA_BR_HELLO_TIME 2
+#define IFLA_BR_MAX_AGE 3
+#define IFLA_BR_AGEING_TIME 4
+#define IFLA_BR_STP_STATE 5
+#define IFLA_BR_PRIORITY 6
+#define __IFLA_BR_MAX 7
+
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+#endif
+
#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
@@ -1050,3 +1075,48 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
#ifndef INPUT_PROP_ACCELEROMETER
#define INPUT_PROP_ACCELEROMETER 0x06
#endif
+
+#if !HAVE_DECL_KEY_SERIAL_T
+typedef int32_t key_serial_t;
+#endif
+
+#if !HAVE_DECL_KEYCTL
+static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
+#if defined(__NR_keyctl)
+ return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
+#if defined (__NR_add_key)
+ return syscall(__NR_add_key, type, description, payload, plen, ringid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
+#if defined (__NR_request_key)
+ return syscall(__NR_request_key, type, description, callout_info, destringid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+#ifndef KEYCTL_READ
+#define KEYCTL_READ 11
+#endif
+
+#ifndef KEYCTL_SET_TIMEOUT
+#define KEYCTL_SET_TIMEOUT 15
+#endif
+
+#ifndef KEY_SPEC_USER_KEYRING
+#define KEY_SPEC_USER_KEYRING -4
+#endif
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index 7ee4546988..0214c4627e 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -22,9 +22,12 @@
#include <string.h>
#include <errno.h>
-#include "util.h"
-#include "path-util.h"
+#include "fs-util.h"
#include "mkdir.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "user-util.h"
+#include "util.h"
int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
struct stat st;
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
new file mode 100644
index 0000000000..29997b1ce7
--- /dev/null
+++ b/src/basic/mount-util.c
@@ -0,0 +1,529 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "util.h"
+
+static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
+ char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
+ _cleanup_free_ char *fdinfo = NULL;
+ _cleanup_close_ int subfd = -1;
+ char *p;
+ int r;
+
+ if ((flags & AT_EMPTY_PATH) && isempty(filename))
+ xsprintf(path, "/proc/self/fdinfo/%i", fd);
+ else {
+ subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
+ if (subfd < 0)
+ return -errno;
+
+ xsprintf(path, "/proc/self/fdinfo/%i", subfd);
+ }
+
+ r = read_full_file(path, &fdinfo, NULL);
+ if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
+ return -EOPNOTSUPP;
+ if (r < 0)
+ return -errno;
+
+ p = startswith(fdinfo, "mnt_id:");
+ if (!p) {
+ p = strstr(fdinfo, "\nmnt_id:");
+ if (!p) /* The mnt_id field is a relatively new addition */
+ return -EOPNOTSUPP;
+
+ p += 8;
+ }
+
+ p += strspn(p, WHITESPACE);
+ p[strcspn(p, WHITESPACE)] = 0;
+
+ return safe_atoi(p, mnt_id);
+}
+
+
+int fd_is_mount_point(int fd, const char *filename, int flags) {
+ union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
+ int mount_id = -1, mount_id_parent = -1;
+ bool nosupp = false, check_st_dev = true;
+ struct stat a, b;
+ int r;
+
+ assert(fd >= 0);
+ assert(filename);
+
+ /* First we will try the name_to_handle_at() syscall, which
+ * tells us the mount id and an opaque file "handle". It is
+ * not supported everywhere though (kernel compile-time
+ * option, not all file systems are hooked up). If it works
+ * the mount id is usually good enough to tell us whether
+ * something is a mount point.
+ *
+ * If that didn't work we will try to read the mount id from
+ * /proc/self/fdinfo/<fd>. This is almost as good as
+ * name_to_handle_at(), however, does not return the
+ * opaque file handle. The opaque file handle is pretty useful
+ * to detect the root directory, which we should always
+ * consider a mount point. Hence we use this only as
+ * fallback. Exporting the mnt_id in fdinfo is a pretty recent
+ * kernel addition.
+ *
+ * As last fallback we do traditional fstat() based st_dev
+ * comparisons. This is how things were traditionally done,
+ * but unionfs breaks breaks this since it exposes file
+ * systems with a variety of st_dev reported. Also, btrfs
+ * subvolumes have different st_dev, even though they aren't
+ * real mounts of their own. */
+
+ r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
+ if (r < 0) {
+ if (errno == ENOSYS)
+ /* This kernel does not support name_to_handle_at()
+ * fall back to simpler logic. */
+ goto fallback_fdinfo;
+ else if (errno == EOPNOTSUPP)
+ /* This kernel or file system does not support
+ * name_to_handle_at(), hence let's see if the
+ * upper fs supports it (in which case it is a
+ * mount point), otherwise fallback to the
+ * traditional stat() logic */
+ nosupp = true;
+ else
+ return -errno;
+ }
+
+ r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
+ if (r < 0) {
+ if (errno == EOPNOTSUPP) {
+ if (nosupp)
+ /* Neither parent nor child do name_to_handle_at()?
+ We have no choice but to fall back. */
+ goto fallback_fdinfo;
+ else
+ /* The parent can't do name_to_handle_at() but the
+ * directory we are interested in can?
+ * If so, it must be a mount point. */
+ return 1;
+ } else
+ return -errno;
+ }
+
+ /* The parent can do name_to_handle_at() but the
+ * directory we are interested in can't? If so, it
+ * must be a mount point. */
+ if (nosupp)
+ return 1;
+
+ /* If the file handle for the directory we are
+ * interested in and its parent are identical, we
+ * assume this is the root directory, which is a mount
+ * point. */
+
+ if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
+ h.handle.handle_type == h_parent.handle.handle_type &&
+ memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
+ return 1;
+
+ return mount_id != mount_id_parent;
+
+fallback_fdinfo:
+ r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
+ if (r == -EOPNOTSUPP)
+ goto fallback_fstat;
+ if (r < 0)
+ return r;
+
+ r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
+ if (r < 0)
+ return r;
+
+ if (mount_id != mount_id_parent)
+ return 1;
+
+ /* Hmm, so, the mount ids are the same. This leaves one
+ * special case though for the root file system. For that,
+ * let's see if the parent directory has the same inode as we
+ * are interested in. Hence, let's also do fstat() checks now,
+ * too, but avoid the st_dev comparisons, since they aren't
+ * that useful on unionfs mounts. */
+ check_st_dev = false;
+
+fallback_fstat:
+ /* yay for fstatat() taking a different set of flags than the other
+ * _at() above */
+ if (flags & AT_SYMLINK_FOLLOW)
+ flags &= ~AT_SYMLINK_FOLLOW;
+ else
+ flags |= AT_SYMLINK_NOFOLLOW;
+ if (fstatat(fd, filename, &a, flags) < 0)
+ return -errno;
+
+ if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
+ return -errno;
+
+ /* A directory with same device and inode as its parent? Must
+ * be the root directory */
+ if (a.st_dev == b.st_dev &&
+ a.st_ino == b.st_ino)
+ return 1;
+
+ return check_st_dev && (a.st_dev != b.st_dev);
+}
+
+/* flags can be AT_SYMLINK_FOLLOW or 0 */
+int path_is_mount_point(const char *t, int flags) {
+ _cleanup_close_ int fd = -1;
+ _cleanup_free_ char *canonical = NULL, *parent = NULL;
+
+ assert(t);
+
+ if (path_equal(t, "/"))
+ return 1;
+
+ /* we need to resolve symlinks manually, we can't just rely on
+ * fd_is_mount_point() to do that for us; if we have a structure like
+ * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
+ * look at needs to be /usr, not /. */
+ if (flags & AT_SYMLINK_FOLLOW) {
+ canonical = canonicalize_file_name(t);
+ if (!canonical)
+ return -errno;
+
+ t = canonical;
+ }
+
+ parent = dirname_malloc(t);
+ if (!parent)
+ return -ENOMEM;
+
+ fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
+ if (fd < 0)
+ return -errno;
+
+ return fd_is_mount_point(fd, basename(t), flags);
+}
+
+int umount_recursive(const char *prefix, int flags) {
+ bool again;
+ int n = 0, r;
+
+ /* Try to umount everything recursively below a
+ * directory. Also, take care of stacked mounts, and keep
+ * unmounting them until they are gone. */
+
+ do {
+ _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+
+ again = false;
+ r = 0;
+
+ proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+ if (!proc_self_mountinfo)
+ return -errno;
+
+ for (;;) {
+ _cleanup_free_ char *path = NULL, *p = NULL;
+ int k;
+
+ k = fscanf(proc_self_mountinfo,
+ "%*s " /* (1) mount id */
+ "%*s " /* (2) parent id */
+ "%*s " /* (3) major:minor */
+ "%*s " /* (4) root */
+ "%ms " /* (5) mount point */
+ "%*s" /* (6) mount options */
+ "%*[^-]" /* (7) optional fields */
+ "- " /* (8) separator */
+ "%*s " /* (9) file system type */
+ "%*s" /* (10) mount source */
+ "%*s" /* (11) mount options 2 */
+ "%*[^\n]", /* some rubbish at the end */
+ &path);
+ if (k != 1) {
+ if (k == EOF)
+ break;
+
+ continue;
+ }
+
+ r = cunescape(path, UNESCAPE_RELAX, &p);
+ if (r < 0)
+ return r;
+
+ if (!path_startswith(p, prefix))
+ continue;
+
+ if (umount2(p, flags) < 0) {
+ r = -errno;
+ continue;
+ }
+
+ again = true;
+ n++;
+
+ break;
+ }
+
+ } while (again);
+
+ return r ? r : n;
+}
+
+static int get_mount_flags(const char *path, unsigned long *flags) {
+ struct statvfs buf;
+
+ if (statvfs(path, &buf) < 0)
+ return -errno;
+ *flags = buf.f_flag;
+ return 0;
+}
+
+int bind_remount_recursive(const char *prefix, bool ro) {
+ _cleanup_set_free_free_ Set *done = NULL;
+ _cleanup_free_ char *cleaned = NULL;
+ int r;
+
+ /* Recursively remount a directory (and all its submounts)
+ * read-only or read-write. If the directory is already
+ * mounted, we reuse the mount and simply mark it
+ * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
+ * operation). If it isn't we first make it one. Afterwards we
+ * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
+ * submounts we can access, too. When mounts are stacked on
+ * the same mount point we only care for each individual
+ * "top-level" mount on each point, as we cannot
+ * influence/access the underlying mounts anyway. We do not
+ * have any effect on future submounts that might get
+ * propagated, they migt be writable. This includes future
+ * submounts that have been triggered via autofs. */
+
+ cleaned = strdup(prefix);
+ if (!cleaned)
+ return -ENOMEM;
+
+ path_kill_slashes(cleaned);
+
+ done = set_new(&string_hash_ops);
+ if (!done)
+ return -ENOMEM;
+
+ for (;;) {
+ _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
+ _cleanup_set_free_free_ Set *todo = NULL;
+ bool top_autofs = false;
+ char *x;
+ unsigned long orig_flags;
+
+ todo = set_new(&string_hash_ops);
+ if (!todo)
+ return -ENOMEM;
+
+ proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
+ if (!proc_self_mountinfo)
+ return -errno;
+
+ for (;;) {
+ _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
+ int k;
+
+ k = fscanf(proc_self_mountinfo,
+ "%*s " /* (1) mount id */
+ "%*s " /* (2) parent id */
+ "%*s " /* (3) major:minor */
+ "%*s " /* (4) root */
+ "%ms " /* (5) mount point */
+ "%*s" /* (6) mount options (superblock) */
+ "%*[^-]" /* (7) optional fields */
+ "- " /* (8) separator */
+ "%ms " /* (9) file system type */
+ "%*s" /* (10) mount source */
+ "%*s" /* (11) mount options (bind mount) */
+ "%*[^\n]", /* some rubbish at the end */
+ &path,
+ &type);
+ if (k != 2) {
+ if (k == EOF)
+ break;
+
+ continue;
+ }
+
+ r = cunescape(path, UNESCAPE_RELAX, &p);
+ if (r < 0)
+ return r;
+
+ /* Let's ignore autofs mounts. If they aren't
+ * triggered yet, we want to avoid triggering
+ * them, as we don't make any guarantees for
+ * future submounts anyway. If they are
+ * already triggered, then we will find
+ * another entry for this. */
+ if (streq(type, "autofs")) {
+ top_autofs = top_autofs || path_equal(cleaned, p);
+ continue;
+ }
+
+ if (path_startswith(p, cleaned) &&
+ !set_contains(done, p)) {
+
+ r = set_consume(todo, p);
+ p = NULL;
+
+ if (r == -EEXIST)
+ continue;
+ if (r < 0)
+ return r;
+ }
+ }
+
+ /* If we have no submounts to process anymore and if
+ * the root is either already done, or an autofs, we
+ * are done */
+ if (set_isempty(todo) &&
+ (top_autofs || set_contains(done, cleaned)))
+ return 0;
+
+ if (!set_contains(done, cleaned) &&
+ !set_contains(todo, cleaned)) {
+ /* The prefix directory itself is not yet a
+ * mount, make it one. */
+ if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
+ return -errno;
+
+ orig_flags = 0;
+ (void) get_mount_flags(cleaned, &orig_flags);
+ orig_flags &= ~MS_RDONLY;
+
+ if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+ return -errno;
+
+ x = strdup(cleaned);
+ if (!x)
+ return -ENOMEM;
+
+ r = set_consume(done, x);
+ if (r < 0)
+ return r;
+ }
+
+ while ((x = set_steal_first(todo))) {
+
+ r = set_consume(done, x);
+ if (r == -EEXIST || r == 0)
+ continue;
+ if (r < 0)
+ return r;
+
+ /* Try to reuse the original flag set, but
+ * don't care for errors, in case of
+ * obstructed mounts */
+ orig_flags = 0;
+ (void) get_mount_flags(x, &orig_flags);
+ orig_flags &= ~MS_RDONLY;
+
+ if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
+
+ /* Deal with mount points that are
+ * obstructed by a later mount */
+
+ if (errno != ENOENT)
+ return -errno;
+ }
+
+ }
+ }
+}
+
+int mount_move_root(const char *path) {
+ assert(path);
+
+ if (chdir(path) < 0)
+ return -errno;
+
+ if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
+ return -errno;
+
+ if (chroot(".") < 0)
+ return -errno;
+
+ if (chdir("/") < 0)
+ return -errno;
+
+ return 0;
+}
+
+bool fstype_is_network(const char *fstype) {
+ static const char table[] =
+ "afs\0"
+ "cifs\0"
+ "smbfs\0"
+ "sshfs\0"
+ "ncpfs\0"
+ "ncp\0"
+ "nfs\0"
+ "nfs4\0"
+ "gfs\0"
+ "gfs2\0"
+ "glusterfs\0";
+
+ const char *x;
+
+ x = startswith(fstype, "fuse.");
+ if (x)
+ fstype = x;
+
+ return nulstr_contains(table, fstype);
+}
+
+int repeat_unmount(const char *path, int flags) {
+ bool done = false;
+
+ assert(path);
+
+ /* If there are multiple mounts on a mount point, this
+ * removes them all */
+
+ for (;;) {
+ if (umount2(path, flags) < 0) {
+
+ if (errno == EINVAL)
+ return done;
+
+ return -errno;
+ }
+
+ done = true;
+ }
+}
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
new file mode 100644
index 0000000000..48954c2d67
--- /dev/null
+++ b/src/basic/mount-util.h
@@ -0,0 +1,52 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <mntent.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "missing.h"
+
+int fd_is_mount_point(int fd, const char *filename, int flags);
+int path_is_mount_point(const char *path, int flags);
+
+int repeat_unmount(const char *path, int flags);
+
+int umount_recursive(const char *target, int flags);
+int bind_remount_recursive(const char *prefix, bool ro);
+
+int mount_move_root(const char *path);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
+#define _cleanup_endmntent_ _cleanup_(endmntentp)
+
+bool fstype_is_network(const char *fstype);
+
+union file_handle_union {
+ struct file_handle handle;
+ char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
+};
+
+#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
new file mode 100644
index 0000000000..b6358c459a
--- /dev/null
+++ b/src/basic/parse-util.c
@@ -0,0 +1,460 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
+
+int parse_boolean(const char *v) {
+ assert(v);
+
+ if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
+ return 1;
+ else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
+ return 0;
+
+ return -EINVAL;
+}
+
+int parse_pid(const char *s, pid_t* ret_pid) {
+ unsigned long ul = 0;
+ pid_t pid;
+ int r;
+
+ assert(s);
+ assert(ret_pid);
+
+ r = safe_atolu(s, &ul);
+ if (r < 0)
+ return r;
+
+ pid = (pid_t) ul;
+
+ if ((unsigned long) pid != ul)
+ return -ERANGE;
+
+ if (pid <= 0)
+ return -ERANGE;
+
+ *ret_pid = pid;
+ return 0;
+}
+
+int parse_mode(const char *s, mode_t *ret) {
+ char *x;
+ long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtol(s, &x, 8);
+ if (errno != 0)
+ return -errno;
+
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (l < 0 || l > 07777)
+ return -ERANGE;
+
+ *ret = (mode_t) l;
+ return 0;
+}
+
+int parse_ifindex(const char *s, int *ret) {
+ int ifi, r;
+
+ r = safe_atoi(s, &ifi);
+ if (r < 0)
+ return r;
+ if (ifi <= 0)
+ return -EINVAL;
+
+ *ret = ifi;
+ return 0;
+}
+
+int parse_size(const char *t, uint64_t base, uint64_t *size) {
+
+ /* Soo, sometimes we want to parse IEC binary suffixes, and
+ * sometimes SI decimal suffixes. This function can parse
+ * both. Which one is the right way depends on the
+ * context. Wikipedia suggests that SI is customary for
+ * hardware metrics and network speeds, while IEC is
+ * customary for most data sizes used by software and volatile
+ * (RAM) memory. Hence be careful which one you pick!
+ *
+ * In either case we use just K, M, G as suffix, and not Ki,
+ * Mi, Gi or so (as IEC would suggest). That's because that's
+ * frickin' ugly. But this means you really need to make sure
+ * to document which base you are parsing when you use this
+ * call. */
+
+ struct table {
+ const char *suffix;
+ unsigned long long factor;
+ };
+
+ static const struct table iec[] = {
+ { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+ { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
+ { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
+ { "G", 1024ULL*1024ULL*1024ULL },
+ { "M", 1024ULL*1024ULL },
+ { "K", 1024ULL },
+ { "B", 1ULL },
+ { "", 1ULL },
+ };
+
+ static const struct table si[] = {
+ { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+ { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+ { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
+ { "G", 1000ULL*1000ULL*1000ULL },
+ { "M", 1000ULL*1000ULL },
+ { "K", 1000ULL },
+ { "B", 1ULL },
+ { "", 1ULL },
+ };
+
+ const struct table *table;
+ const char *p;
+ unsigned long long r = 0;
+ unsigned n_entries, start_pos = 0;
+
+ assert(t);
+ assert(base == 1000 || base == 1024);
+ assert(size);
+
+ if (base == 1000) {
+ table = si;
+ n_entries = ELEMENTSOF(si);
+ } else {
+ table = iec;
+ n_entries = ELEMENTSOF(iec);
+ }
+
+ p = t;
+ do {
+ unsigned long long l, tmp;
+ double frac = 0;
+ char *e;
+ unsigned i;
+
+ p += strspn(p, WHITESPACE);
+ if (*p == '-')
+ return -ERANGE;
+
+ errno = 0;
+ l = strtoull(p, &e, 10);
+ if (errno > 0)
+ return -errno;
+ if (e == p)
+ return -EINVAL;
+
+ if (*e == '.') {
+ e++;
+
+ /* strtoull() itself would accept space/+/- */
+ if (*e >= '0' && *e <= '9') {
+ unsigned long long l2;
+ char *e2;
+
+ l2 = strtoull(e, &e2, 10);
+ if (errno > 0)
+ return -errno;
+
+ /* Ignore failure. E.g. 10.M is valid */
+ frac = l2;
+ for (; e < e2; e++)
+ frac /= 10;
+ }
+ }
+
+ e += strspn(e, WHITESPACE);
+
+ for (i = start_pos; i < n_entries; i++)
+ if (startswith(e, table[i].suffix))
+ break;
+
+ if (i >= n_entries)
+ return -EINVAL;
+
+ if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
+ return -ERANGE;
+
+ tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
+ if (tmp > ULLONG_MAX - r)
+ return -ERANGE;
+
+ r += tmp;
+ if ((unsigned long long) (uint64_t) r != r)
+ return -ERANGE;
+
+ p = e + strlen(table[i].suffix);
+
+ start_pos = i + 1;
+
+ } while (*p);
+
+ *size = r;
+
+ return 0;
+}
+
+int parse_range(const char *t, unsigned *lower, unsigned *upper) {
+ _cleanup_free_ char *word = NULL;
+ unsigned l, u;
+ int r;
+
+ assert(lower);
+ assert(upper);
+
+ /* Extract the lower bound. */
+ r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+
+ r = safe_atou(word, &l);
+ if (r < 0)
+ return r;
+
+ /* Check for the upper bound and extract it if needed */
+ if (!t)
+ /* Single number with no dashes. */
+ u = l;
+ else if (!*t)
+ /* Trailing dash is an error. */
+ return -EINVAL;
+ else {
+ r = safe_atou(t, &u);
+ if (r < 0)
+ return r;
+ }
+
+ *lower = l;
+ *upper = u;
+ return 0;
+}
+
+char *format_bytes(char *buf, size_t l, uint64_t t) {
+ unsigned i;
+
+ /* This only does IEC units so far */
+
+ static const struct {
+ const char *suffix;
+ uint64_t factor;
+ } table[] = {
+ { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "M", UINT64_C(1024)*UINT64_C(1024) },
+ { "K", UINT64_C(1024) },
+ };
+
+ if (t == (uint64_t) -1)
+ return NULL;
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+
+ if (t >= table[i].factor) {
+ snprintf(buf, l,
+ "%" PRIu64 ".%" PRIu64 "%s",
+ t / table[i].factor,
+ ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
+ table[i].suffix);
+
+ goto finish;
+ }
+ }
+
+ snprintf(buf, l, "%" PRIu64 "B", t);
+
+finish:
+ buf[l-1] = 0;
+ return buf;
+
+}
+
+int safe_atou(const char *s, unsigned *ret_u) {
+ char *x = NULL;
+ unsigned long l;
+
+ assert(s);
+ assert(ret_u);
+
+ errno = 0;
+ l = strtoul(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((unsigned long) (unsigned) l != l)
+ return -ERANGE;
+
+ *ret_u = (unsigned) l;
+ return 0;
+}
+
+int safe_atoi(const char *s, int *ret_i) {
+ char *x = NULL;
+ long l;
+
+ assert(s);
+ assert(ret_i);
+
+ errno = 0;
+ l = strtol(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((long) (int) l != l)
+ return -ERANGE;
+
+ *ret_i = (int) l;
+ return 0;
+}
+
+int safe_atollu(const char *s, long long unsigned *ret_llu) {
+ char *x = NULL;
+ unsigned long long l;
+
+ assert(s);
+ assert(ret_llu);
+
+ errno = 0;
+ l = strtoull(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno ? -errno : -EINVAL;
+
+ *ret_llu = l;
+ return 0;
+}
+
+int safe_atolli(const char *s, long long int *ret_lli) {
+ char *x = NULL;
+ long long l;
+
+ assert(s);
+ assert(ret_lli);
+
+ errno = 0;
+ l = strtoll(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno ? -errno : -EINVAL;
+
+ *ret_lli = l;
+ return 0;
+}
+
+int safe_atou8(const char *s, uint8_t *ret) {
+ char *x = NULL;
+ unsigned long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtoul(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((unsigned long) (uint8_t) l != l)
+ return -ERANGE;
+
+ *ret = (uint8_t) l;
+ return 0;
+}
+
+int safe_atou16(const char *s, uint16_t *ret) {
+ char *x = NULL;
+ unsigned long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtoul(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((unsigned long) (uint16_t) l != l)
+ return -ERANGE;
+
+ *ret = (uint16_t) l;
+ return 0;
+}
+
+int safe_atoi16(const char *s, int16_t *ret) {
+ char *x = NULL;
+ long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtol(s, &x, 0);
+
+ if (!x || x == s || *x || errno)
+ return errno > 0 ? -errno : -EINVAL;
+
+ if ((long) (int16_t) l != l)
+ return -ERANGE;
+
+ *ret = (int16_t) l;
+ return 0;
+}
+
+int safe_atod(const char *s, double *ret_d) {
+ char *x = NULL;
+ double d = 0;
+ locale_t loc;
+
+ assert(s);
+ assert(ret_d);
+
+ loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
+ if (loc == (locale_t) 0)
+ return -errno;
+
+ errno = 0;
+ d = strtod_l(s, &x, loc);
+
+ if (!x || x == s || *x || errno) {
+ freelocale(loc);
+ return errno ? -errno : -EINVAL;
+ }
+
+ freelocale(loc);
+ *ret_d = (double) d;
+ return 0;
+}
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
new file mode 100644
index 0000000000..408690d0b3
--- /dev/null
+++ b/src/basic/parse-util.h
@@ -0,0 +1,92 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+#define MODE_INVALID ((mode_t) -1)
+
+int parse_boolean(const char *v) _pure_;
+int parse_pid(const char *s, pid_t* ret_pid);
+int parse_mode(const char *s, mode_t *ret);
+int parse_ifindex(const char *s, int *ret);
+
+int parse_size(const char *t, uint64_t base, uint64_t *size);
+int parse_range(const char *t, unsigned *lower, unsigned *upper);
+
+#define FORMAT_BYTES_MAX 8
+char *format_bytes(char *buf, size_t l, uint64_t t);
+
+int safe_atou(const char *s, unsigned *ret_u);
+int safe_atoi(const char *s, int *ret_i);
+int safe_atollu(const char *s, unsigned long long *ret_u);
+int safe_atolli(const char *s, long long int *ret_i);
+
+int safe_atou8(const char *s, uint8_t *ret);
+
+int safe_atou16(const char *s, uint16_t *ret);
+int safe_atoi16(const char *s, int16_t *ret);
+
+static inline int safe_atou32(const char *s, uint32_t *ret_u) {
+ assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+ return safe_atou(s, (unsigned*) ret_u);
+}
+
+static inline int safe_atoi32(const char *s, int32_t *ret_i) {
+ assert_cc(sizeof(int32_t) == sizeof(int));
+ return safe_atoi(s, (int*) ret_i);
+}
+
+static inline int safe_atou64(const char *s, uint64_t *ret_u) {
+ assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
+ return safe_atollu(s, (unsigned long long*) ret_u);
+}
+
+static inline int safe_atoi64(const char *s, int64_t *ret_i) {
+ assert_cc(sizeof(int64_t) == sizeof(long long int));
+ return safe_atolli(s, (long long int*) ret_i);
+}
+
+#if LONG_MAX == INT_MAX
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+ assert_cc(sizeof(unsigned long) == sizeof(unsigned));
+ return safe_atou(s, (unsigned*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+ assert_cc(sizeof(long int) == sizeof(int));
+ return safe_atoi(s, (int*) ret_u);
+}
+#else
+static inline int safe_atolu(const char *s, unsigned long *ret_u) {
+ assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
+ return safe_atollu(s, (unsigned long long*) ret_u);
+}
+static inline int safe_atoli(const char *s, long int *ret_u) {
+ assert_cc(sizeof(long int) == sizeof(long long int));
+ return safe_atolli(s, (long long int*) ret_u);
+}
+#endif
+
+int safe_atod(const char *s, double *ret_d);
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 5cbfc145a4..ec90c432a4 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -19,21 +19,33 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/statvfs.h>
+#include <unistd.h>
-#include "macro.h"
-#include "util.h"
+/* When we include libgen.h because we need dirname() we immediately
+ * undefine basename() since libgen.h defines it as a macro to the
+ * POSIX version which is really broken. We prefer GNU basename(). */
+#include <libgen.h>
+#undef basename
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "log.h"
-#include "strv.h"
-#include "path-util.h"
+#include "macro.h"
#include "missing.h"
-#include "fileio.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
@@ -43,61 +55,25 @@ bool is_path(const char *p) {
return !!strchr(p, '/');
}
-int path_get_parent(const char *path, char **_r) {
- const char *e, *a = NULL, *b = NULL, *p;
- char *r;
- bool slash = false;
-
- assert(path);
- assert(_r);
-
- if (!*path)
- return -EINVAL;
-
- for (e = path; *e; e++) {
-
- if (!slash && *e == '/') {
- a = b;
- b = e;
- slash = true;
- } else if (slash && *e != '/')
- slash = false;
- }
-
- if (*(e-1) == '/')
- p = a;
- else
- p = b;
-
- if (!p)
- return -EINVAL;
-
- if (p == path)
- r = strdup("/");
- else
- r = strndup(path, p-path);
-
- if (!r)
- return -ENOMEM;
-
- *_r = r;
- return 0;
-}
-
-char **path_split_and_make_absolute(const char *p) {
+int path_split_and_make_absolute(const char *p, char ***ret) {
char **l;
+ int r;
+
assert(p);
+ assert(ret);
l = strv_split(p, ":");
if (!l)
- return NULL;
+ return -ENOMEM;
- if (!path_strv_make_absolute_cwd(l)) {
+ r = path_strv_make_absolute_cwd(l);
+ if (r < 0) {
strv_free(l);
- return NULL;
+ return r;
}
- return l;
+ *ret = l;
+ return r;
}
char *path_make_absolute(const char *p, const char *prefix) {
@@ -112,22 +88,31 @@ char *path_make_absolute(const char *p, const char *prefix) {
return strjoin(prefix, "/", p, NULL);
}
-char *path_make_absolute_cwd(const char *p) {
- _cleanup_free_ char *cwd = NULL;
+int path_make_absolute_cwd(const char *p, char **ret) {
+ char *c;
assert(p);
+ assert(ret);
/* Similar to path_make_absolute(), but prefixes with the
* current working directory. */
if (path_is_absolute(p))
- return strdup(p);
+ c = strdup(p);
+ else {
+ _cleanup_free_ char *cwd = NULL;
- cwd = get_current_dir_name();
- if (!cwd)
- return NULL;
+ cwd = get_current_dir_name();
+ if (!cwd)
+ return -errno;
+
+ c = strjoin(cwd, "/", p, NULL);
+ }
+ if (!c)
+ return -ENOMEM;
- return strjoin(cwd, "/", p, NULL);
+ *ret = c;
+ return 0;
}
int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
@@ -215,8 +200,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
return 0;
}
-char **path_strv_make_absolute_cwd(char **l) {
+int path_strv_make_absolute_cwd(char **l) {
char **s;
+ int r;
/* Goes through every item in the string list and makes it
* absolute. This works in place and won't rollback any
@@ -225,15 +211,15 @@ char **path_strv_make_absolute_cwd(char **l) {
STRV_FOREACH(s, l) {
char *t;
- t = path_make_absolute_cwd(*s);
- if (!t)
- return NULL;
+ r = path_make_absolute_cwd(*s, &t);
+ if (r < 0)
+ return r;
free(*s);
*s = t;
}
- return l;
+ return 0;
}
char **path_strv_resolve(char **l, const char *prefix) {
@@ -411,7 +397,7 @@ int path_compare(const char *a, const char *b) {
* Which one is sorted before the other does not really matter.
* Here a relative path is ordered before an absolute path. */
d = (a[0] == '/') - (b[0] == '/');
- if (d)
+ if (d != 0)
return d;
for (;;) {
@@ -434,12 +420,12 @@ int path_compare(const char *a, const char *b) {
/* Alphabetical sort: "/foo/aaa" before "/foo/b" */
d = memcmp(a, b, MIN(j, k));
- if (d)
+ if (d != 0)
return (d > 0) - (d < 0); /* sign of d */
/* Sort "/foo/a" before "/foo/aaa" */
d = (j > k) - (j < k); /* sign of (j - k) */
- if (d)
+ if (d != 0)
return d;
a += j;
@@ -471,294 +457,66 @@ char* path_join(const char *root, const char *path, const char *rest) {
NULL);
}
-static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
- char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
- _cleanup_free_ char *fdinfo = NULL;
- _cleanup_close_ int subfd = -1;
- char *p;
- int r;
-
- if ((flags & AT_EMPTY_PATH) && isempty(filename))
- xsprintf(path, "/proc/self/fdinfo/%i", fd);
- else {
- subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
- if (subfd < 0)
- return -errno;
-
- xsprintf(path, "/proc/self/fdinfo/%i", subfd);
- }
-
- r = read_full_file(path, &fdinfo, NULL);
- if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
- return -EOPNOTSUPP;
- if (r < 0)
- return -errno;
-
- p = startswith(fdinfo, "mnt_id:");
- if (!p) {
- p = strstr(fdinfo, "\nmnt_id:");
- if (!p) /* The mnt_id field is a relatively new addition */
- return -EOPNOTSUPP;
-
- p += 8;
- }
-
- p += strspn(p, WHITESPACE);
- p[strcspn(p, WHITESPACE)] = 0;
-
- return safe_atoi(p, mnt_id);
-}
-
-int fd_is_mount_point(int fd, const char *filename, int flags) {
- union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
- int mount_id = -1, mount_id_parent = -1;
- bool nosupp = false, check_st_dev = true;
- struct stat a, b;
- int r;
+int find_binary(const char *name, char **ret) {
+ int last_error, r;
+ const char *p;
- assert(fd >= 0);
- assert(filename);
-
- /* First we will try the name_to_handle_at() syscall, which
- * tells us the mount id and an opaque file "handle". It is
- * not supported everywhere though (kernel compile-time
- * option, not all file systems are hooked up). If it works
- * the mount id is usually good enough to tell us whether
- * something is a mount point.
- *
- * If that didn't work we will try to read the mount id from
- * /proc/self/fdinfo/<fd>. This is almost as good as
- * name_to_handle_at(), however, does not return the
- * opaque file handle. The opaque file handle is pretty useful
- * to detect the root directory, which we should always
- * consider a mount point. Hence we use this only as
- * fallback. Exporting the mnt_id in fdinfo is a pretty recent
- * kernel addition.
- *
- * As last fallback we do traditional fstat() based st_dev
- * comparisons. This is how things were traditionally done,
- * but unionfs breaks breaks this since it exposes file
- * systems with a variety of st_dev reported. Also, btrfs
- * subvolumes have different st_dev, even though they aren't
- * real mounts of their own. */
-
- r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
- if (r < 0) {
- if (errno == ENOSYS)
- /* This kernel does not support name_to_handle_at()
- * fall back to simpler logic. */
- goto fallback_fdinfo;
- else if (errno == EOPNOTSUPP)
- /* This kernel or file system does not support
- * name_to_handle_at(), hence let's see if the
- * upper fs supports it (in which case it is a
- * mount point), otherwise fallback to the
- * traditional stat() logic */
- nosupp = true;
- else
- return -errno;
- }
+ assert(name);
- r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
- if (r < 0) {
- if (errno == EOPNOTSUPP) {
- if (nosupp)
- /* Neither parent nor child do name_to_handle_at()?
- We have no choice but to fall back. */
- goto fallback_fdinfo;
- else
- /* The parent can't do name_to_handle_at() but the
- * directory we are interested in can?
- * If so, it must be a mount point. */
- return 1;
- } else
+ if (is_path(name)) {
+ if (access(name, X_OK) < 0)
return -errno;
- }
-
- /* The parent can do name_to_handle_at() but the
- * directory we are interested in can't? If so, it
- * must be a mount point. */
- if (nosupp)
- return 1;
-
- /* If the file handle for the directory we are
- * interested in and its parent are identical, we
- * assume this is the root directory, which is a mount
- * point. */
-
- if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
- h.handle.handle_type == h_parent.handle.handle_type &&
- memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
- return 1;
-
- return mount_id != mount_id_parent;
-
-fallback_fdinfo:
- r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
- if (r == -EOPNOTSUPP)
- goto fallback_fstat;
- if (r < 0)
- return r;
-
- r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
- if (r < 0)
- return r;
-
- if (mount_id != mount_id_parent)
- return 1;
-
- /* Hmm, so, the mount ids are the same. This leaves one
- * special case though for the root file system. For that,
- * let's see if the parent directory has the same inode as we
- * are interested in. Hence, let's also do fstat() checks now,
- * too, but avoid the st_dev comparisons, since they aren't
- * that useful on unionfs mounts. */
- check_st_dev = false;
-
-fallback_fstat:
- /* yay for fstatat() taking a different set of flags than the other
- * _at() above */
- if (flags & AT_SYMLINK_FOLLOW)
- flags &= ~AT_SYMLINK_FOLLOW;
- else
- flags |= AT_SYMLINK_NOFOLLOW;
- if (fstatat(fd, filename, &a, flags) < 0)
- return -errno;
-
- if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
- return -errno;
-
- /* A directory with same device and inode as its parent? Must
- * be the root directory */
- if (a.st_dev == b.st_dev &&
- a.st_ino == b.st_ino)
- return 1;
-
- return check_st_dev && (a.st_dev != b.st_dev);
-}
-/* flags can be AT_SYMLINK_FOLLOW or 0 */
-int path_is_mount_point(const char *t, int flags) {
- _cleanup_close_ int fd = -1;
- _cleanup_free_ char *canonical = NULL, *parent = NULL;
- int r;
-
- assert(t);
-
- if (path_equal(t, "/"))
- return 1;
-
- /* we need to resolve symlinks manually, we can't just rely on
- * fd_is_mount_point() to do that for us; if we have a structure like
- * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
- * look at needs to be /usr, not /. */
- if (flags & AT_SYMLINK_FOLLOW) {
- canonical = canonicalize_file_name(t);
- if (!canonical)
- return -errno;
+ if (ret) {
+ r = path_make_absolute_cwd(name, ret);
+ if (r < 0)
+ return r;
+ }
- t = canonical;
+ return 0;
}
- r = path_get_parent(t, &parent);
- if (r < 0)
- return r;
-
- fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
- if (fd < 0)
- return -errno;
-
- return fd_is_mount_point(fd, basename(t), flags);
-}
-
-int path_is_read_only_fs(const char *path) {
- struct statvfs st;
-
- assert(path);
-
- if (statvfs(path, &st) < 0)
- return -errno;
-
- if (st.f_flag & ST_RDONLY)
- return true;
-
- /* On NFS, statvfs() might not reflect whether we can actually
- * write to the remote share. Let's try again with
- * access(W_OK) which is more reliable, at least sometimes. */
- if (access(path, W_OK) < 0 && errno == EROFS)
- return true;
-
- return false;
-}
-
-int path_is_os_tree(const char *path) {
- char *p;
- int r;
-
- /* We use /usr/lib/os-release as flag file if something is an OS */
- p = strjoina(path, "/usr/lib/os-release");
- r = access(p, F_OK);
-
- if (r >= 0)
- return 1;
-
- /* Also check for the old location in /etc, just in case. */
- p = strjoina(path, "/etc/os-release");
- r = access(p, F_OK);
-
- return r >= 0;
-}
-
-int find_binary(const char *name, bool local, char **filename) {
- assert(name);
+ /**
+ * Plain getenv, not secure_getenv, because we want
+ * to actually allow the user to pick the binary.
+ */
+ p = getenv("PATH");
+ if (!p)
+ p = DEFAULT_PATH;
- if (is_path(name)) {
- if (local && access(name, X_OK) < 0)
- return -errno;
+ last_error = -ENOENT;
- if (filename) {
- char *p;
+ for (;;) {
+ _cleanup_free_ char *j = NULL, *element = NULL;
- p = path_make_absolute_cwd(name);
- if (!p)
- return -ENOMEM;
+ r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
- *filename = p;
- }
+ if (!path_is_absolute(element))
+ continue;
- return 0;
- } else {
- const char *path;
- const char *word, *state;
- size_t l;
-
- /**
- * Plain getenv, not secure_getenv, because we want
- * to actually allow the user to pick the binary.
- */
- path = getenv("PATH");
- if (!path)
- path = DEFAULT_PATH;
-
- FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
- _cleanup_free_ char *p = NULL;
-
- if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
- return -ENOMEM;
+ j = strjoin(element, "/", name, NULL);
+ if (!j)
+ return -ENOMEM;
- if (access(p, X_OK) < 0)
- continue;
+ if (access(j, X_OK) >= 0) {
+ /* Found it! */
- if (filename) {
- *filename = path_kill_slashes(p);
- p = NULL;
+ if (ret) {
+ *ret = path_kill_slashes(j);
+ j = NULL;
}
return 0;
}
- return -ENOENT;
+ last_error = -errno;
}
+
+ return last_error;
}
bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
@@ -796,14 +554,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
return changed;
}
-int fsck_exists(const char *fstype) {
+static int binary_is_good(const char *binary) {
_cleanup_free_ char *p = NULL, *d = NULL;
- const char *checker;
int r;
- checker = strjoina("fsck.", fstype);
-
- r = find_binary(checker, true, &p);
+ r = find_binary(binary, &p);
+ if (r == -ENOENT)
+ return 0;
if (r < 0)
return r;
@@ -811,13 +568,39 @@ int fsck_exists(const char *fstype) {
* fsck */
r = readlink_malloc(p, &d);
- if (r >= 0 &&
- (path_equal(d, "/bin/true") ||
- path_equal(d, "/usr/bin/true") ||
- path_equal(d, "/dev/null")))
- return -ENOENT;
+ if (r == -EINVAL) /* not a symlink */
+ return 1;
+ if (r < 0)
+ return r;
- return 0;
+ return !path_equal(d, "true") &&
+ !path_equal(d, "/bin/true") &&
+ !path_equal(d, "/usr/bin/true") &&
+ !path_equal(d, "/dev/null");
+}
+
+int fsck_exists(const char *fstype) {
+ const char *checker;
+
+ assert(fstype);
+
+ if (streq(fstype, "auto"))
+ return -EINVAL;
+
+ checker = strjoina("fsck.", fstype);
+ return binary_is_good(checker);
+}
+
+int mkfs_exists(const char *fstype) {
+ const char *mkfs;
+
+ assert(fstype);
+
+ if (streq(fstype, "auto"))
+ return -EINVAL;
+
+ mkfs = strjoina("mkfs.", fstype);
+ return binary_is_good(mkfs);
}
char *prefix_root(const char *root, const char *path) {
@@ -853,3 +636,166 @@ char *prefix_root(const char *root, const char *path) {
strcpy(p, path);
return n;
}
+
+int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
+ char *p;
+ int r;
+
+ /*
+ * This function is intended to be used in command line
+ * parsers, to handle paths that are passed in. It makes the
+ * path absolute, and reduces it to NULL if omitted or
+ * root (the latter optionally).
+ *
+ * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
+ * SUCCESS! Hence, do not pass in uninitialized pointers.
+ */
+
+ if (isempty(path)) {
+ *arg = mfree(*arg);
+ return 0;
+ }
+
+ r = path_make_absolute_cwd(path, &p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
+
+ path_kill_slashes(p);
+ if (suppress_root && path_equal(p, "/"))
+ p = mfree(p);
+
+ free(*arg);
+ *arg = p;
+ return 0;
+}
+
+char* dirname_malloc(const char *path) {
+ char *d, *dir, *dir2;
+
+ assert(path);
+
+ d = strdup(path);
+ if (!d)
+ return NULL;
+
+ dir = dirname(d);
+ assert(dir);
+
+ if (dir == d)
+ return d;
+
+ dir2 = strdup(dir);
+ free(d);
+
+ return dir2;
+}
+
+bool filename_is_valid(const char *p) {
+ const char *e;
+
+ if (isempty(p))
+ return false;
+
+ if (streq(p, "."))
+ return false;
+
+ if (streq(p, ".."))
+ return false;
+
+ e = strchrnul(p, '/');
+ if (*e != 0)
+ return false;
+
+ if (e - p > FILENAME_MAX)
+ return false;
+
+ return true;
+}
+
+bool path_is_safe(const char *p) {
+
+ if (isempty(p))
+ return false;
+
+ if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
+ return false;
+
+ if (strlen(p)+1 > PATH_MAX)
+ return false;
+
+ /* The following two checks are not really dangerous, but hey, they still are confusing */
+ if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
+ return false;
+
+ if (strstr(p, "//"))
+ return false;
+
+ return true;
+}
+
+char *file_in_same_dir(const char *path, const char *filename) {
+ char *e, *ret;
+ size_t k;
+
+ assert(path);
+ assert(filename);
+
+ /* This removes the last component of path and appends
+ * filename, unless the latter is absolute anyway or the
+ * former isn't */
+
+ if (path_is_absolute(filename))
+ return strdup(filename);
+
+ e = strrchr(path, '/');
+ if (!e)
+ return strdup(filename);
+
+ k = strlen(filename);
+ ret = new(char, (e + 1 - path) + k + 1);
+ if (!ret)
+ return NULL;
+
+ memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
+ return ret;
+}
+
+bool hidden_file_allow_backup(const char *filename) {
+ assert(filename);
+
+ return
+ filename[0] == '.' ||
+ streq(filename, "lost+found") ||
+ streq(filename, "aquota.user") ||
+ streq(filename, "aquota.group") ||
+ endswith(filename, ".rpmnew") ||
+ endswith(filename, ".rpmsave") ||
+ endswith(filename, ".rpmorig") ||
+ endswith(filename, ".dpkg-old") ||
+ endswith(filename, ".dpkg-new") ||
+ endswith(filename, ".dpkg-tmp") ||
+ endswith(filename, ".dpkg-dist") ||
+ endswith(filename, ".dpkg-bak") ||
+ endswith(filename, ".dpkg-backup") ||
+ endswith(filename, ".dpkg-remove") ||
+ endswith(filename, ".swp");
+}
+
+bool hidden_file(const char *filename) {
+ assert(filename);
+
+ if (endswith(filename, "~"))
+ return true;
+
+ return hidden_file_allow_backup(filename);
+}
+
+bool is_device_path(const char *path) {
+
+ /* Returns true on paths that refer to a device, either in
+ * sysfs or in /dev */
+
+ return
+ path_startswith(path, "/dev/") ||
+ path_startswith(path, "/sys/");
+}
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 1eac89c51b..989e0f9004 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -36,11 +36,10 @@
#endif
bool is_path(const char *p) _pure_;
-char** path_split_and_make_absolute(const char *p);
-int path_get_parent(const char *path, char **parent);
+int path_split_and_make_absolute(const char *p, char ***ret);
bool path_is_absolute(const char *p) _pure_;
char* path_make_absolute(const char *p, const char *prefix);
-char* path_make_absolute_cwd(const char *p);
+int path_make_absolute_cwd(const char *p, char **ret);
int path_make_relative(const char *from_dir, const char *to_path, char **_r);
char* path_kill_slashes(char *path);
char* path_startswith(const char *path, const char *prefix) _pure_;
@@ -49,20 +48,16 @@ bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b);
char* path_join(const char *root, const char *path, const char *rest);
-char** path_strv_make_absolute_cwd(char **l);
+int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
-int fd_is_mount_point(int fd, const char *filename, int flags);
-int path_is_mount_point(const char *path, int flags);
-int path_is_read_only_fs(const char *path);
-int path_is_os_tree(const char *path);
-
-int find_binary(const char *name, bool local, char **filename);
+int find_binary(const char *name, char **filename);
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
int fsck_exists(const char *fstype);
+int mkfs_exists(const char *fstype);
/* Iterates through the path prefixes of the specified path, going up
* the tree, to root. Also returns "" (and not "/"!) for the root
@@ -100,3 +95,17 @@ char *prefix_root(const char *root, const char *path);
} \
_ret; \
})
+
+int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
+
+char* dirname_malloc(const char *path);
+
+bool filename_is_valid(const char *p) _pure_;
+bool path_is_safe(const char *p) _pure_;
+
+char *file_in_same_dir(const char *path, const char *filename);
+
+bool hidden_file_allow_backup(const char *filename);
+bool hidden_file(const char *filename) _pure_;
+
+bool is_device_path(const char *path);
diff --git a/src/basic/prioq.c b/src/basic/prioq.c
index b89888be0e..7590698911 100644
--- a/src/basic/prioq.c
+++ b/src/basic/prioq.c
@@ -19,8 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+/*
+ * Priority Queue
+ * The prioq object implements a priority queue. That is, it orders objects by
+ * their priority and allows O(1) access to the object with the highest
+ * priority. Insertion and removal are Θ(log n). Optionally, the caller can
+ * provide a pointer to an index which will be kept up-to-date by the prioq.
+ *
+ * The underlying algorithm used in this implementation is a Heap.
+ */
+
+#include "alloc-util.h"
#include "prioq.h"
+#include "util.h"
struct prioq_item {
void *data;
@@ -101,7 +112,7 @@ static unsigned shuffle_up(Prioq *q, unsigned idx) {
k = (idx-1)/2;
- if (q->compare_func(q->items[k].data, q->items[idx].data) < 0)
+ if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0)
break;
swap(q, idx, k);
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
new file mode 100644
index 0000000000..4464573c5b
--- /dev/null
+++ b/src/basic/proc-cmdline.c
@@ -0,0 +1,174 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "fileio.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-util.h"
+#include "util.h"
+#include "virt.h"
+
+int proc_cmdline(char **ret) {
+ assert(ret);
+
+ if (detect_container() > 0)
+ return get_process_cmdline(1, 0, false, ret);
+ else
+ return read_one_line_file("/proc/cmdline", ret);
+}
+
+int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
+ _cleanup_free_ char *line = NULL;
+ const char *p;
+ int r;
+
+ assert(parse_item);
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ p = line;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ char *value = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ /* Filter out arguments that are intended only for the
+ * initrd */
+ if (!in_initrd() && startswith(word, "rd."))
+ continue;
+
+ value = strchr(word, '=');
+ if (value)
+ *(value++) = 0;
+
+ r = parse_item(word, value);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int get_proc_cmdline_key(const char *key, char **value) {
+ _cleanup_free_ char *line = NULL, *ret = NULL;
+ bool found = false;
+ const char *p;
+ int r;
+
+ assert(key);
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ p = line;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ const char *e;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ /* Filter out arguments that are intended only for the
+ * initrd */
+ if (!in_initrd() && startswith(word, "rd."))
+ continue;
+
+ if (value) {
+ e = startswith(word, key);
+ if (!e)
+ continue;
+
+ r = free_and_strdup(&ret, e);
+ if (r < 0)
+ return r;
+
+ found = true;
+ } else {
+ if (streq(word, key))
+ found = true;
+ }
+ }
+
+ if (value) {
+ *value = ret;
+ ret = NULL;
+ }
+
+ return found;
+
+}
+
+int shall_restore_state(void) {
+ _cleanup_free_ char *value = NULL;
+ int r;
+
+ r = get_proc_cmdline_key("systemd.restore_state=", &value);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return true;
+
+ return parse_boolean(value);
+}
+
+static const char * const rlmap[] = {
+ "emergency", SPECIAL_EMERGENCY_TARGET,
+ "-b", SPECIAL_EMERGENCY_TARGET,
+ "rescue", SPECIAL_RESCUE_TARGET,
+ "single", SPECIAL_RESCUE_TARGET,
+ "-s", SPECIAL_RESCUE_TARGET,
+ "s", SPECIAL_RESCUE_TARGET,
+ "S", SPECIAL_RESCUE_TARGET,
+ "1", SPECIAL_RESCUE_TARGET,
+ "2", SPECIAL_MULTI_USER_TARGET,
+ "3", SPECIAL_MULTI_USER_TARGET,
+ "4", SPECIAL_MULTI_USER_TARGET,
+ "5", SPECIAL_GRAPHICAL_TARGET,
+};
+
+const char* runlevel_to_target(const char *word) {
+ size_t i;
+
+ if (!word)
+ return NULL;
+
+ for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
+ if (streq(word, rlmap[i]))
+ return rlmap[i+1];
+
+ return NULL;
+}
diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h
new file mode 100644
index 0000000000..ce6e84995a
--- /dev/null
+++ b/src/basic/proc-cmdline.h
@@ -0,0 +1,29 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int proc_cmdline(char **ret);
+int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
+int get_proc_cmdline_key(const char *parameter, char **value);
+
+int shall_restore_state(void);
+const char* runlevel_to_target(const char *rl);
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index cff2d2a034..7631928d5f 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -17,22 +17,33 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-#include <sys/types.h>
-#include <string.h>
-#include <stdio.h>
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
-#include <sys/wait.h>
+#include <sched.h>
#include <signal.h>
-#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "util.h"
+#include "fs-util.h"
+#include "ioprio.h"
#include "log.h"
-#include "signal-util.h"
#include "process-util.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
int get_process_state(pid_t pid) {
const char *p;
@@ -174,6 +185,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
return 0;
}
+void rename_process(const char name[8]) {
+ assert(name);
+
+ /* This is a like a poor man's setproctitle(). It changes the
+ * comm field, argv[0], and also the glibc's internally used
+ * name of the process. For the first one a limit of 16 chars
+ * applies, to the second one usually one of 10 (i.e. length
+ * of "/sbin/init"), to the third one one of 7 (i.e. length of
+ * "systemd"). If you pass a longer string it will be
+ * truncated */
+
+ prctl(PR_SET_NAME, name);
+
+ if (program_invocation_name)
+ strncpy(program_invocation_name, name, strlen(program_invocation_name));
+
+ if (saved_argc > 0) {
+ int i;
+
+ if (saved_argv[0])
+ strncpy(saved_argv[0], name, strlen(saved_argv[0]));
+
+ for (i = 1; i < saved_argc; i++) {
+ if (!saved_argv[i])
+ break;
+
+ memzero(saved_argv[i], strlen(saved_argv[i]));
+ }
+ }
+}
+
int is_kernel_thread(pid_t pid) {
const char *p;
size_t count;
@@ -215,7 +257,7 @@ int get_process_capeff(pid_t pid, char **capeff) {
p = procfs_file_alloca(pid, "status");
- r = get_status_field(p, "\nCapEff:", capeff);
+ r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
if (r == -ENOENT)
return -ESRCH;
@@ -364,7 +406,7 @@ int get_process_environ(pid_t pid, char **env) {
return 0;
}
-int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+int get_process_ppid(pid_t pid, pid_t *_ppid) {
int r;
_cleanup_free_ char *line = NULL;
long unsigned ppid;
@@ -476,6 +518,16 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
return -EPROTO;
}
+void sigkill_wait(pid_t *pid) {
+ if (!pid)
+ return;
+ if (*pid <= 1)
+ return;
+
+ if (kill(*pid, SIGKILL) > 0)
+ (void) wait_for_terminate(*pid, NULL);
+}
+
int kill_and_sigcont(pid_t pid, int sig) {
int r;
@@ -547,9 +599,12 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
bool pid_is_unwaited(pid_t pid) {
/* Checks whether a PID is still valid at all, including a zombie */
- if (pid <= 0)
+ if (pid < 0)
return false;
+ if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */
+ return true;
+
if (kill(pid, 0) >= 0)
return true;
@@ -561,12 +616,141 @@ bool pid_is_alive(pid_t pid) {
/* Checks whether a PID is still valid and not a zombie */
- if (pid <= 0)
+ if (pid < 0)
return false;
+ if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */
+ return true;
+
r = get_process_state(pid);
if (r == -ESRCH || r == 'Z')
return false;
return true;
}
+
+bool is_main_thread(void) {
+ static thread_local int cached = 0;
+
+ if (_unlikely_(cached == 0))
+ cached = getpid() == gettid() ? 1 : -1;
+
+ return cached > 0;
+}
+
+noreturn void freeze(void) {
+
+ /* Make sure nobody waits for us on a socket anymore */
+ close_all_fds(NULL, 0);
+
+ sync();
+
+ for (;;)
+ pause();
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+ return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}
+
+unsigned long personality_from_string(const char *p) {
+
+ /* Parse a personality specifier. We introduce our own
+ * identifiers that indicate specific ABIs, rather than just
+ * hints regarding the register size, since we want to keep
+ * things open for multiple locally supported ABIs for the
+ * same register size. We try to reuse the ABI identifiers
+ * used by libseccomp. */
+
+#if defined(__x86_64__)
+
+ if (streq(p, "x86"))
+ return PER_LINUX32;
+
+ if (streq(p, "x86-64"))
+ return PER_LINUX;
+
+#elif defined(__i386__)
+
+ if (streq(p, "x86"))
+ return PER_LINUX;
+
+#elif defined(__s390x__)
+
+ if (streq(p, "s390"))
+ return PER_LINUX32;
+
+ if (streq(p, "s390x"))
+ return PER_LINUX;
+
+#elif defined(__s390__)
+
+ if (streq(p, "s390"))
+ return PER_LINUX;
+#endif
+
+ return PERSONALITY_INVALID;
+}
+
+const char* personality_to_string(unsigned long p) {
+
+#if defined(__x86_64__)
+
+ if (p == PER_LINUX32)
+ return "x86";
+
+ if (p == PER_LINUX)
+ return "x86-64";
+
+#elif defined(__i386__)
+
+ if (p == PER_LINUX)
+ return "x86";
+
+#elif defined(__s390x__)
+
+ if (p == PER_LINUX)
+ return "s390x";
+
+ if (p == PER_LINUX32)
+ return "s390";
+
+#elif defined(__s390__)
+
+ if (p == PER_LINUX)
+ return "s390";
+
+#endif
+
+ return NULL;
+}
+
+static const char *const ioprio_class_table[] = {
+ [IOPRIO_CLASS_NONE] = "none",
+ [IOPRIO_CLASS_RT] = "realtime",
+ [IOPRIO_CLASS_BE] = "best-effort",
+ [IOPRIO_CLASS_IDLE] = "idle"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
+
+static const char *const sigchld_code_table[] = {
+ [CLD_EXITED] = "exited",
+ [CLD_KILLED] = "killed",
+ [CLD_DUMPED] = "dumped",
+ [CLD_TRAPPED] = "trapped",
+ [CLD_STOPPED] = "stopped",
+ [CLD_CONTINUED] = "continued",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
+
+static const char* const sched_policy_table[] = {
+ [SCHED_OTHER] = "other",
+ [SCHED_BATCH] = "batch",
+ [SCHED_IDLE] = "idle",
+ [SCHED_FIFO] = "fifo",
+ [SCHED_RR] = "rr"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index 07431d043b..72633ebf70 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -27,6 +27,7 @@
#include <signal.h>
#include "formats-util.h"
+#include "macro.h"
#define procfs_file_alloca(pid, field) \
({ \
@@ -51,15 +52,48 @@ int get_process_capeff(pid_t pid, char **capeff);
int get_process_cwd(pid_t pid, char **cwd);
int get_process_root(pid_t pid, char **root);
int get_process_environ(pid_t pid, char **environ);
+int get_process_ppid(pid_t pid, pid_t *ppid);
int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
+void sigkill_wait(pid_t *pid);
+#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+
int kill_and_sigcont(pid_t pid, int sig);
-pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
+
void rename_process(const char name[8]);
int is_kernel_thread(pid_t pid);
+
int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
bool pid_is_unwaited(pid_t pid);
+
+bool is_main_thread(void);
+
+noreturn void freeze(void);
+
+bool oom_score_adjust_is_valid(int oa);
+
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
+unsigned long personality_from_string(const char *p);
+const char *personality_to_string(unsigned long);
+
+int ioprio_class_to_string_alloc(int i, char **s);
+int ioprio_class_from_string(const char *s);
+
+const char *sigchld_code_to_string(int i) _const_;
+int sigchld_code_from_string(const char *s) _pure_;
+
+int sched_policy_to_string_alloc(int i, char **s);
+int sched_policy_from_string(const char *s);
+
+#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
+#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index b230044f50..2f5c16e2af 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -17,20 +17,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdint.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <fcntl.h>
-#include <time.h>
+#include <linux/random.h>
+#include <stdint.h>
#ifdef HAVE_SYS_AUXV_H
#include <sys/auxv.h>
#endif
-#include <linux/random.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include "fd-util.h"
+#include "io-util.h"
+#include "missing.h"
#include "random-util.h"
#include "time-util.h"
-#include "missing.h"
#include "util.h"
int dev_urandom(void *p, size_t n) {
diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c
index 478fc43a38..bf757cbc48 100644
--- a/src/basic/replace-var.c
+++ b/src/basic/replace-var.c
@@ -21,10 +21,11 @@
#include <string.h>
+#include "alloc-util.h"
#include "macro.h"
-#include "util.h"
#include "replace-var.h"
-#include "def.h"
+#include "string-util.h"
+#include "util.h"
/*
* Generic infrastructure for replacing @FOO@ style variables in
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
new file mode 100644
index 0000000000..2627c813fc
--- /dev/null
+++ b/src/basic/rlimit-util.c
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "missing.h"
+#include "rlimit-util.h"
+#include "string-table.h"
+#include "util.h"
+
+int setrlimit_closest(int resource, const struct rlimit *rlim) {
+ struct rlimit highest, fixed;
+
+ assert(rlim);
+
+ if (setrlimit(resource, rlim) >= 0)
+ return 0;
+
+ if (errno != EPERM)
+ return -errno;
+
+ /* So we failed to set the desired setrlimit, then let's try
+ * to get as close as we can */
+ assert_se(getrlimit(resource, &highest) == 0);
+
+ fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
+ fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
+
+ if (setrlimit(resource, &fixed) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static const char* const rlimit_table[_RLIMIT_MAX] = {
+ [RLIMIT_CPU] = "LimitCPU",
+ [RLIMIT_FSIZE] = "LimitFSIZE",
+ [RLIMIT_DATA] = "LimitDATA",
+ [RLIMIT_STACK] = "LimitSTACK",
+ [RLIMIT_CORE] = "LimitCORE",
+ [RLIMIT_RSS] = "LimitRSS",
+ [RLIMIT_NOFILE] = "LimitNOFILE",
+ [RLIMIT_AS] = "LimitAS",
+ [RLIMIT_NPROC] = "LimitNPROC",
+ [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
+ [RLIMIT_LOCKS] = "LimitLOCKS",
+ [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
+ [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
+ [RLIMIT_NICE] = "LimitNICE",
+ [RLIMIT_RTPRIO] = "LimitRTPRIO",
+ [RLIMIT_RTTIME] = "LimitRTTIME"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h
new file mode 100644
index 0000000000..262f86dd04
--- /dev/null
+++ b/src/basic/rlimit-util.h
@@ -0,0 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/resource.h>
+
+#include "macro.h"
+
+const char *rlimit_to_string(int i) _const_;
+int rlimit_from_string(const char *s) _pure_;
+
+int setrlimit_closest(int resource, const struct rlimit *rlim);
+
+#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index dbbe817684..8ec7dd75ee 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -19,10 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "path-util.h"
#include "btrfs-util.h"
+#include "fd-util.h"
+#include "mount-util.h"
+#include "path-util.h"
#include "rm-rf.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
_cleanup_closedir_ DIR *d = NULL;
@@ -120,7 +124,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
/* This could be a subvolume, try to remove it */
- r = btrfs_subvol_remove_fd(fd, de->d_name, true);
+ r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
if (r != -ENOTTY && r != -EINVAL) {
if (ret == 0)
@@ -178,7 +182,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
/* Try to remove as subvolume first */
- r = btrfs_subvol_remove(path, true);
+ r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r >= 0)
return r;
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index a39a0f775a..a821a3d5bb 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -29,6 +29,7 @@
#include <selinux/context.h>
#endif
+#include "alloc-util.h"
#include "strv.h"
#include "path-util.h"
#include "selinux-util.h"
@@ -171,15 +172,15 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
int mac_selinux_apply(const char *path, const char *label) {
#ifdef HAVE_SELINUX
- assert(path);
- assert(label);
-
if (!mac_selinux_use())
return 0;
+ assert(path);
+ assert(label);
+
if (setfilecon(path, (security_context_t) label) < 0) {
log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
- if (security_getenforce() == 1)
+ if (security_getenforce() > 0)
return -errno;
}
#endif
@@ -295,21 +296,27 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
return r;
}
-void mac_selinux_free(char *label) {
+char* mac_selinux_free(char *label) {
#ifdef HAVE_SELINUX
+ if (!label)
+ return NULL;
+
if (!mac_selinux_use())
- return;
+ return NULL;
+
freecon((security_context_t) label);
#endif
+
+ return NULL;
}
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
- int r = 0;
#ifdef HAVE_SELINUX
_cleanup_security_context_free_ security_context_t filecon = NULL;
+ int r;
assert(path);
@@ -319,34 +326,33 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
if (path_is_absolute(path))
r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
else {
- _cleanup_free_ char *newpath;
+ _cleanup_free_ char *newpath = NULL;
- newpath = path_make_absolute_cwd(path);
- if (!newpath)
- return -ENOMEM;
+ r = path_make_absolute_cwd(path, &newpath);
+ if (r < 0)
+ return r;
r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
}
- /* No context specified by the policy? Proceed without setting it. */
- if (r < 0 && errno == ENOENT)
- return 0;
+ if (r < 0) {
+ /* No context specified by the policy? Proceed without setting it. */
+ if (errno == ENOENT)
+ return 0;
- if (r < 0)
- r = -errno;
- else {
- r = setfscreatecon(filecon);
- if (r < 0) {
- log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
- r = -errno;
- }
+ log_enforcing("Failed to determine SELinux security context for %s: %m", path);
+ } else {
+ if (setfscreatecon(filecon) >= 0)
+ return 0; /* Success! */
+
+ log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
}
- if (r < 0 && security_getenforce() == 0)
- r = 0;
-#endif
+ if (security_getenforce() > 0)
+ return -errno;
- return r;
+#endif
+ return 0;
}
void mac_selinux_create_file_clear(void) {
@@ -399,6 +405,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
#ifdef HAVE_SELINUX
_cleanup_security_context_free_ security_context_t fcon = NULL;
const struct sockaddr_un *un;
+ bool context_changed = false;
char *path;
int r;
@@ -414,7 +421,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
goto skipped;
/* Filter out anonymous sockets */
- if (addrlen < sizeof(sa_family_t) + 1)
+ if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1)
goto skipped;
/* Filter out abstract namespace sockets */
@@ -427,36 +434,44 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
if (path_is_absolute(path))
r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
else {
- _cleanup_free_ char *newpath;
+ _cleanup_free_ char *newpath = NULL;
- newpath = path_make_absolute_cwd(path);
- if (!newpath)
- return -ENOMEM;
+ r = path_make_absolute_cwd(path, &newpath);
+ if (r < 0)
+ return r;
r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
}
- if (r == 0)
- r = setfscreatecon(fcon);
+ if (r < 0) {
+ /* No context specified by the policy? Proceed without setting it */
+ if (errno == ENOENT)
+ goto skipped;
- if (r < 0 && errno != ENOENT) {
- log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
+ log_enforcing("Failed to determine SELinux security context for %s: %m", path);
+ if (security_getenforce() > 0)
+ return -errno;
- if (security_getenforce() == 1) {
- r = -errno;
- goto finish;
- }
+ } else {
+ if (setfscreatecon(fcon) < 0) {
+ log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
+ if (security_getenforce() > 0)
+ return -errno;
+ } else
+ context_changed = true;
}
- r = bind(fd, addr, addrlen);
- if (r < 0)
- r = -errno;
+ r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
+
+ if (context_changed)
+ setfscreatecon(NULL);
-finish:
- setfscreatecon(NULL);
return r;
skipped:
#endif
- return bind(fd, addr, addrlen) < 0 ? -errno : 0;
+ if (bind(fd, addr, addrlen) < 0)
+ return -errno;
+
+ return 0;
}
diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
index 8467185291..2afcaec183 100644
--- a/src/basic/selinux-util.h
+++ b/src/basic/selinux-util.h
@@ -24,6 +24,8 @@
#include <sys/socket.h>
#include <stdbool.h>
+#include "macro.h"
+
bool mac_selinux_use(void);
void mac_selinux_retest(void);
@@ -36,7 +38,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 *exe, const char *exec_label, char **label);
-void mac_selinux_free(char *label);
+char* mac_selinux_free(char *label);
int mac_selinux_create_file_prepare(const char *path, mode_t mode);
void mac_selinux_create_file_clear(void);
@@ -45,3 +47,5 @@ int mac_selinux_create_socket_prepare(const char *label);
void mac_selinux_create_socket_clear(void);
int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, mac_selinux_free);
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index 90abe8af81..8038bc891d 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -19,8 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "parse-util.h"
#include "signal-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
int reset_all_signal_handlers(void) {
static const struct sigaction sa = {
@@ -266,3 +269,7 @@ int signal_from_string_try_harder(const char *s) {
return signo;
}
+
+void nop_signal_handler(int sig) {
+ /* nothing here */
+}
diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h
index 5e6eb50b07..e7393e2dac 100644
--- a/src/basic/signal-util.h
+++ b/src/basic/signal-util.h
@@ -39,3 +39,5 @@ const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_;
int signal_from_string_try_harder(const char *s);
+
+void nop_signal_handler(int sig);
diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c
index f68bd283a1..3b61961389 100644
--- a/src/basic/siphash24.c
+++ b/src/basic/siphash24.c
@@ -13,123 +13,170 @@
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
(Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
+ (Refactored by Tom Gundersen to split up in several functions and follow systemd
+ coding style)
*/
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
+
+#include "sparse-endian.h"
#include "siphash24.h"
+#include "util.h"
-typedef uint64_t u64;
-typedef uint32_t u32;
-typedef uint8_t u8;
-
-#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
-
-#define U32TO8_LE(p, v) \
- (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \
- (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24);
-
-#define U64TO8_LE(p, v) \
- U32TO8_LE((p), (u32)((v) )); \
- U32TO8_LE((p) + 4, (u32)((v) >> 32));
-
-#define U8TO64_LE(p) \
- (((u64)((p)[0]) ) | \
- ((u64)((p)[1]) << 8) | \
- ((u64)((p)[2]) << 16) | \
- ((u64)((p)[3]) << 24) | \
- ((u64)((p)[4]) << 32) | \
- ((u64)((p)[5]) << 40) | \
- ((u64)((p)[6]) << 48) | \
- ((u64)((p)[7]) << 56))
-
-#define SIPROUND \
- do { \
- v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
- v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
- v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
- v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
- } while(0)
+static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
+ assert(b < 64);
+
+ return (x << b) | (x >> (64 - b));
+}
+
+static inline void sipround(struct siphash *state) {
+ assert(state);
+
+ state->v0 += state->v1;
+ state->v1 = rotate_left(state->v1, 13);
+ state->v1 ^= state->v0;
+ state->v0 = rotate_left(state->v0, 32);
+ state->v2 += state->v3;
+ state->v3 = rotate_left(state->v3, 16);
+ state->v3 ^= state->v2;
+ state->v0 += state->v3;
+ state->v3 = rotate_left(state->v3, 21);
+ state->v3 ^= state->v0;
+ state->v2 += state->v1;
+ state->v1 = rotate_left(state->v1, 17);
+ state->v1 ^= state->v2;
+ state->v2 = rotate_left(state->v2, 32);
+}
+
+void siphash24_init(struct siphash *state, const uint8_t k[16]) {
+ uint64_t k0, k1;
+
+ assert(state);
+ assert(k);
+
+ k0 = le64toh(*(le64_t*) k);
+ k1 = le64toh(*(le64_t*) (k + 8));
+
+ /* "somepseudorandomlygeneratedbytes" */
+ state->v0 = 0x736f6d6570736575ULL ^ k0;
+ state->v1 = 0x646f72616e646f6dULL ^ k1;
+ state->v2 = 0x6c7967656e657261ULL ^ k0;
+ state->v3 = 0x7465646279746573ULL ^ k1;
+ state->padding = 0;
+ state->inlen = 0;
+}
+
+void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
+ uint64_t m;
+ const uint8_t *in = _in;
+ const uint8_t *end = in + inlen;
+ unsigned left = state->inlen & 7;
+
+ assert(in);
+ assert(state);
+
+ /* update total length */
+ state->inlen += inlen;
+
+ /* if padding exists, fill it out */
+ if (left > 0) {
+ for ( ; in < end && left < 8; in ++, left ++ )
+ state->padding |= ( ( uint64_t )*in ) << (left * 8);
+
+ if (in == end && left < 8)
+ /* we did not have enough input to fill out the padding completely */
+ return;
-/* SipHash-2-4 */
-void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16])
-{
- /* "somepseudorandomlygeneratedbytes" */
- u64 v0 = 0x736f6d6570736575ULL;
- u64 v1 = 0x646f72616e646f6dULL;
- u64 v2 = 0x6c7967656e657261ULL;
- u64 v3 = 0x7465646279746573ULL;
- u64 b;
- u64 k0 = U8TO64_LE( k );
- u64 k1 = U8TO64_LE( k + 8 );
- u64 m;
- const u8 *in = _in;
- const u8 *end = in + inlen - ( inlen % sizeof( u64 ) );
- const int left = inlen & 7;
- b = ( ( u64 )inlen ) << 56;
- v3 ^= k1;
- v2 ^= k0;
- v1 ^= k1;
- v0 ^= k0;
-
- for ( ; in != end; in += 8 )
- {
- m = U8TO64_LE( in );
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
- printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
+ printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
#endif
- v3 ^= m;
- SIPROUND;
- SIPROUND;
- v0 ^= m;
- }
+ state->v3 ^= state->padding;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= state->padding;
- switch( left )
- {
- case 7: b |= ( ( u64 )in[ 6] ) << 48;
+ state->padding = 0;
+ }
- case 6: b |= ( ( u64 )in[ 5] ) << 40;
+ end -= ( state->inlen % sizeof (uint64_t) );
- case 5: b |= ( ( u64 )in[ 4] ) << 32;
+ for ( ; in < end; in += 8 ) {
+ m = le64toh(*(le64_t*) in);
+#ifdef DEBUG
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
+ printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
+#endif
+ state->v3 ^= m;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= m;
+ }
+
+ left = state->inlen & 7;
+
+ switch(left)
+ {
+ case 7: state->padding |= ((uint64_t) in[6]) << 48;
- case 4: b |= ( ( u64 )in[ 3] ) << 24;
+ case 6: state->padding |= ((uint64_t) in[5]) << 40;
- case 3: b |= ( ( u64 )in[ 2] ) << 16;
+ case 5: state->padding |= ((uint64_t) in[4]) << 32;
- case 2: b |= ( ( u64 )in[ 1] ) << 8;
+ case 4: state->padding |= ((uint64_t) in[3]) << 24;
- case 1: b |= ( ( u64 )in[ 0] ); break;
+ case 3: state->padding |= ((uint64_t) in[2]) << 16;
+
+ case 2: state->padding |= ((uint64_t) in[1]) << 8;
+
+ case 1: state->padding |= ((uint64_t) in[0]); break;
+
+ case 0: break;
+ }
+}
- case 0: break;
- }
+void siphash24_finalize(uint8_t out[8], struct siphash *state) {
+ uint64_t b;
+ b = state->padding | (( ( uint64_t )state->inlen ) << 56);
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
- printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3);
+ printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
#endif
- v3 ^= b;
- SIPROUND;
- SIPROUND;
- v0 ^= b;
+ state->v3 ^= b;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= b;
+
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
#endif
- v2 ^= 0xff;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- b = v0 ^ v1 ^ v2 ^ v3;
- U64TO8_LE( out, b );
+ state->v2 ^= 0xff;
+
+ sipround(state);
+ sipround(state);
+ sipround(state);
+ sipround(state);
+
+ *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3);
+}
+
+/* SipHash-2-4 */
+void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) {
+ struct siphash state;
+
+ siphash24_init(&state, k);
+ siphash24_compress(_in, inlen, &state);
+ siphash24_finalize(out, &state);
}
diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h
index 62e1168a79..6c5cd98ee8 100644
--- a/src/basic/siphash24.h
+++ b/src/basic/siphash24.h
@@ -3,4 +3,17 @@
#include <inttypes.h>
#include <sys/types.h>
+struct siphash {
+ uint64_t v0;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ uint64_t padding;
+ size_t inlen;
+};
+
+void siphash24_init(struct siphash *state, const uint8_t k[16]);
+void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
+void siphash24_finalize(uint8_t out[8], struct siphash *state);
+
void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]);
diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
index 9e221d6eab..fcc046098d 100644
--- a/src/basic/smack-util.c
+++ b/src/basic/smack-util.c
@@ -23,14 +23,14 @@
#include <sys/xattr.h>
-#include "util.h"
-#include "process-util.h"
-#include "path-util.h"
+#include "alloc-util.h"
#include "fileio.h"
+#include "path-util.h"
+#include "process-util.h"
#include "smack-util.h"
-
-#define SMACK_FLOOR_LABEL "_"
-#define SMACK_STAR_LABEL "*"
+#include "string-table.h"
+#include "util.h"
+#include "xattr-util.h"
#ifdef HAVE_SMACK
bool mac_smack_use(void) {
diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h
index b3aa55eb8a..e756dc8c28 100644
--- a/src/basic/smack-util.h
+++ b/src/basic/smack-util.h
@@ -27,6 +27,9 @@
#include "macro.h"
+#define SMACK_FLOOR_LABEL "_"
+#define SMACK_STAR_LABEL "*"
+
typedef enum SmackAttr {
SMACK_ATTR_ACCESS = 0,
SMACK_ATTR_EXEC = 1,
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index 144e6fd86e..e5d4efc719 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -19,18 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
#include <errno.h>
-#include <sys/stat.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
#include "missing.h"
+#include "mkdir.h"
#include "selinux-util.h"
#include "socket-util.h"
+#include "util.h"
int socket_address_listen(
const SocketAddress *a,
@@ -146,11 +148,8 @@ int make_socket_fd(int log_level, const char* address, int flags) {
int fd, r;
r = socket_address_parse(&a, address);
- if (r < 0) {
- log_error("Failed to parse socket address \"%s\": %s",
- address, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
NULL, false, false, false, 0755, 0644, NULL);
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 8fd3149276..1acab1ef95 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -19,23 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
#include <arpa/inet.h>
-#include <stdio.h>
+#include <errno.h>
#include <net/if.h>
-#include <sys/types.h>
-#include <stddef.h>
#include <netdb.h>
+#include <netinet/ip.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
#include "macro.h"
+#include "missing.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "util.h"
#include "socket-util.h"
-#include "missing.h"
-#include "fileio.h"
-#include "formats-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
@@ -749,21 +756,182 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b
return false;
}
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
- assert(addr);
- assert(buffer);
+int fd_inc_sndbuf(int fd, size_t n) {
+ int r, value;
+ socklen_t l = sizeof(value);
- /* Like ether_ntoa() but uses %02x instead of %x to print
- * ethernet addresses, which makes them look less funny. Also,
- * doesn't use a static buffer. */
+ r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
+ if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+ return 0;
- sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x",
- addr->ether_addr_octet[0],
- addr->ether_addr_octet[1],
- addr->ether_addr_octet[2],
- addr->ether_addr_octet[3],
- addr->ether_addr_octet[4],
- addr->ether_addr_octet[5]);
+ /* If we have the privileges we will ignore the kernel limit. */
+
+ value = (int) n;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+ return -errno;
+
+ return 1;
+}
+
+int fd_inc_rcvbuf(int fd, size_t n) {
+ int r, value;
+ socklen_t l = sizeof(value);
+
+ r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
+ if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
+ return 0;
+
+ /* If we have the privileges we will ignore the kernel limit. */
+
+ value = (int) n;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+ return -errno;
+ return 1;
+}
+
+static const char* const ip_tos_table[] = {
+ [IPTOS_LOWDELAY] = "low-delay",
+ [IPTOS_THROUGHPUT] = "throughput",
+ [IPTOS_RELIABILITY] = "reliability",
+ [IPTOS_LOWCOST] = "low-cost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
+
+int getpeercred(int fd, struct ucred *ucred) {
+ socklen_t n = sizeof(struct ucred);
+ struct ucred u;
+ int r;
+
+ assert(fd >= 0);
+ assert(ucred);
+
+ r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
+ if (r < 0)
+ return -errno;
+
+ if (n != sizeof(struct ucred))
+ return -EIO;
+
+ /* Check if the data is actually useful and not suppressed due
+ * to namespacing issues */
+ if (u.pid <= 0)
+ return -ENODATA;
+ if (u.uid == UID_INVALID)
+ return -ENODATA;
+ if (u.gid == GID_INVALID)
+ return -ENODATA;
+
+ *ucred = u;
+ return 0;
+}
+
+int getpeersec(int fd, char **ret) {
+ socklen_t n = 64;
+ char *s;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ s = new0(char, n);
+ if (!s)
+ return -ENOMEM;
+
+ r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+ if (r < 0) {
+ free(s);
+
+ if (errno != ERANGE)
+ return -errno;
+
+ s = new0(char, n);
+ if (!s)
+ return -ENOMEM;
+
+ r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+ if (r < 0) {
+ free(s);
+ return -errno;
+ }
+ }
+
+ if (isempty(s)) {
+ free(s);
+ return -EOPNOTSUPP;
+ }
+
+ *ret = s;
+ return 0;
+}
+
+int send_one_fd(int transport_fd, int fd, int flags) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+
+ assert(transport_fd >= 0);
+ assert(fd >= 0);
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+ mh.msg_controllen = CMSG_SPACE(sizeof(int));
+ if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int receive_one_fd(int transport_fd, int flags) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg, *found = NULL;
+
+ assert(transport_fd >= 0);
+
+ /*
+ * Receive a single FD via @transport_fd. We don't care for
+ * the transport-type. We retrieve a single FD at most, so for
+ * packet-based transports, the caller must ensure to send
+ * only a single FD per packet. This is best used in
+ * combination with send_one_fd().
+ */
+
+ if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
+ return -errno;
+
+ CMSG_FOREACH(cmsg, &mh) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ assert(!found);
+ found = cmsg;
+ break;
+ }
+ }
+
+ if (!found) {
+ cmsg_close_all(&mh);
+ return -EIO;
+ }
- return buffer;
+ return *(int*) CMSG_DATA(found);
}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 6b0ce7836f..c60f2556af 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -116,6 +116,17 @@ int netlink_family_from_string(const char *s) _pure_;
bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b);
-#define ETHER_ADDR_TO_STRING_MAX (3*6)
+int fd_inc_sndbuf(int fd, size_t n);
+int fd_inc_rcvbuf(int fd, size_t n);
-char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
+int ip_tos_to_string_alloc(int i, char **s);
+int ip_tos_from_string(const char *s);
+
+int getpeercred(int fd, struct ucred *ucred);
+int getpeersec(int fd, char **ret);
+
+int send_one_fd(int transport_fd, int fd, int flags);
+int receive_one_fd(int transport_fd, int flags);
+
+#define CMSG_FOREACH(cmsg, mh) \
+ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
new file mode 100644
index 0000000000..3bc66b3be7
--- /dev/null
+++ b/src/basic/stat-util.c
@@ -0,0 +1,216 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <linux/magic.h>
+#include <sys/statvfs.h>
+#include <unistd.h>
+
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "stat-util.h"
+#include "string-util.h"
+
+int is_symlink(const char *path) {
+ struct stat info;
+
+ assert(path);
+
+ if (lstat(path, &info) < 0)
+ return -errno;
+
+ return !!S_ISLNK(info.st_mode);
+}
+
+int is_dir(const char* path, bool follow) {
+ struct stat st;
+ int r;
+
+ assert(path);
+
+ if (follow)
+ r = stat(path, &st);
+ else
+ r = lstat(path, &st);
+ if (r < 0)
+ return -errno;
+
+ return !!S_ISDIR(st.st_mode);
+}
+
+int is_device_node(const char *path) {
+ struct stat info;
+
+ assert(path);
+
+ if (lstat(path, &info) < 0)
+ return -errno;
+
+ return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
+}
+
+int dir_is_empty(const char *path) {
+ _cleanup_closedir_ DIR *d;
+ struct dirent *de;
+
+ d = opendir(path);
+ if (!d)
+ return -errno;
+
+ FOREACH_DIRENT(de, d, return -errno)
+ return 0;
+
+ return 1;
+}
+
+bool null_or_empty(struct stat *st) {
+ assert(st);
+
+ if (S_ISREG(st->st_mode) && st->st_size <= 0)
+ return true;
+
+ /* We don't want to hardcode the major/minor of /dev/null,
+ * hence we do a simpler "is this a device node?" check. */
+
+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
+ return true;
+
+ return false;
+}
+
+int null_or_empty_path(const char *fn) {
+ struct stat st;
+
+ assert(fn);
+
+ if (stat(fn, &st) < 0)
+ return -errno;
+
+ return null_or_empty(&st);
+}
+
+int null_or_empty_fd(int fd) {
+ struct stat st;
+
+ assert(fd >= 0);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ return null_or_empty(&st);
+}
+
+int path_is_read_only_fs(const char *path) {
+ struct statvfs st;
+
+ assert(path);
+
+ if (statvfs(path, &st) < 0)
+ return -errno;
+
+ if (st.f_flag & ST_RDONLY)
+ return true;
+
+ /* On NFS, statvfs() might not reflect whether we can actually
+ * write to the remote share. Let's try again with
+ * access(W_OK) which is more reliable, at least sometimes. */
+ if (access(path, W_OK) < 0 && errno == EROFS)
+ return true;
+
+ return false;
+}
+
+int path_is_os_tree(const char *path) {
+ char *p;
+ int r;
+
+ assert(path);
+
+ /* We use /usr/lib/os-release as flag file if something is an OS */
+ p = strjoina(path, "/usr/lib/os-release");
+ r = access(p, F_OK);
+ if (r >= 0)
+ return 1;
+
+ /* Also check for the old location in /etc, just in case. */
+ p = strjoina(path, "/etc/os-release");
+ r = access(p, F_OK);
+
+ return r >= 0;
+}
+
+int files_same(const char *filea, const char *fileb) {
+ struct stat a, b;
+
+ assert(filea);
+ assert(fileb);
+
+ if (stat(filea, &a) < 0)
+ return -errno;
+
+ if (stat(fileb, &b) < 0)
+ return -errno;
+
+ return a.st_dev == b.st_dev &&
+ a.st_ino == b.st_ino;
+}
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
+ assert(s);
+ assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
+
+ return F_TYPE_EQUAL(s->f_type, magic_value);
+}
+
+int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_fs_type(&s, magic_value);
+}
+
+int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ return fd_check_fstype(fd, magic_value);
+}
+
+bool is_temporary_fs(const struct statfs *s) {
+ return is_fs_type(s, TMPFS_MAGIC) ||
+ is_fs_type(s, RAMFS_MAGIC);
+}
+
+int fd_is_temporary_fs(int fd) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_temporary_fs(&s);
+}
diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
new file mode 100644
index 0000000000..909b220a24
--- /dev/null
+++ b/src/basic/stat-util.h
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#include "macro.h"
+
+int is_symlink(const char *path);
+int is_dir(const char *path, bool follow);
+int is_device_node(const char *path);
+
+int dir_is_empty(const char *path);
+
+static inline int dir_is_populated(const char *path) {
+ int r;
+ r = dir_is_empty(path);
+ if (r < 0)
+ return r;
+ return !r;
+}
+
+bool null_or_empty(struct stat *st) _pure_;
+int null_or_empty_path(const char *fn);
+int null_or_empty_fd(int fd);
+
+int path_is_read_only_fs(const char *path);
+int path_is_os_tree(const char *path);
+
+int files_same(const char *filea, const char *fileb);
+
+/* The .f_type field of struct statfs is really weird defined on
+ * different archs. Let's use our own type we know is sufficiently
+ * larger to store the possible values. */
+typedef long statfs_f_type_t;
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
+int fd_check_fstype(int fd, statfs_f_type_t magic_value);
+int path_check_fstype(const char *path, statfs_f_type_t magic_value);
+
+bool is_temporary_fs(const struct statfs *s) _pure_;
+int fd_is_temporary_fs(int fd);
+
+/* Because statfs.t_type can be int on some architectures, we have to cast
+ * the const magic to the type, otherwise the compiler warns about
+ * signed/unsigned comparison, because the magic can be 32 bit unsigned.
+ */
+#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h
new file mode 100644
index 0000000000..b36e8a947e
--- /dev/null
+++ b/src/basic/stdio-util.h
@@ -0,0 +1,78 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <printf.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+#define xsprintf(buf, fmt, ...) \
+ assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough")
+
+
+#define VA_FORMAT_ADVANCE(format, ap) \
+do { \
+ int _argtypes[128]; \
+ size_t _i, _k; \
+ _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \
+ assert(_k < ELEMENTSOF(_argtypes)); \
+ for (_i = 0; _i < _k; _i++) { \
+ if (_argtypes[_i] & PA_FLAG_PTR) { \
+ (void) va_arg(ap, void*); \
+ continue; \
+ } \
+ \
+ switch (_argtypes[_i]) { \
+ case PA_INT: \
+ case PA_INT|PA_FLAG_SHORT: \
+ case PA_CHAR: \
+ (void) va_arg(ap, int); \
+ break; \
+ case PA_INT|PA_FLAG_LONG: \
+ (void) va_arg(ap, long int); \
+ break; \
+ case PA_INT|PA_FLAG_LONG_LONG: \
+ (void) va_arg(ap, long long int); \
+ break; \
+ case PA_WCHAR: \
+ (void) va_arg(ap, wchar_t); \
+ break; \
+ case PA_WSTRING: \
+ case PA_STRING: \
+ case PA_POINTER: \
+ (void) va_arg(ap, void*); \
+ break; \
+ case PA_FLOAT: \
+ case PA_DOUBLE: \
+ (void) va_arg(ap, double); \
+ break; \
+ case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \
+ (void) va_arg(ap, long double); \
+ break; \
+ default: \
+ assert_not_reached("Unknown format string argument."); \
+ } \
+ } \
+} while(false)
diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c
index 01a076c2ba..f4f702a05a 100644
--- a/src/basic/strbuf.c
+++ b/src/basic/strbuf.c
@@ -22,8 +22,9 @@
#include <stdlib.h>
#include <string.h>
-#include "util.h"
+#include "alloc-util.h"
#include "strbuf.h"
+#include "util.h"
/*
* Strbuf stores given strings in a single continuous allocated memory
diff --git a/src/basic/string-table.c b/src/basic/string-table.c
new file mode 100644
index 0000000000..a860324fc9
--- /dev/null
+++ b/src/basic/string-table.c
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "string-table.h"
+
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
+ size_t i;
+
+ if (!key)
+ return -1;
+
+ for (i = 0; i < len; ++i)
+ if (streq_ptr(table[i], key))
+ return (ssize_t) i;
+
+ return -1;
+}
diff --git a/src/basic/string-table.h b/src/basic/string-table.h
new file mode 100644
index 0000000000..51b6007214
--- /dev/null
+++ b/src/basic/string-table.h
@@ -0,0 +1,88 @@
+
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "macro.h"
+#include "parse-util.h"
+#include "string-util.h"
+
+ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
+
+/* For basic lookup tables with strictly enumerated entries */
+#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ scope const char *name##_to_string(type i) { \
+ if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
+ return NULL; \
+ return name##_table[i]; \
+ }
+
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
+ scope type name##_from_string(const char *s) { \
+ return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+ }
+
+#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
+
+/* For string conversions where numbers are also acceptable */
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
+ int name##_to_string_alloc(type i, char **str) { \
+ char *s; \
+ if (i < 0 || i > max) \
+ return -ERANGE; \
+ if (i < (type) ELEMENTSOF(name##_table)) { \
+ s = strdup(name##_table[i]); \
+ if (!s) \
+ return -ENOMEM; \
+ } else { \
+ if (asprintf(&s, "%i", i) < 0) \
+ return -ENOMEM; \
+ } \
+ *str = s; \
+ return 0; \
+ } \
+ type name##_from_string(const char *s) { \
+ type i; \
+ unsigned u = 0; \
+ if (!s) \
+ return (type) -1; \
+ for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
+ if (streq_ptr(name##_table[i], s)) \
+ return i; \
+ if (safe_atou(s, &u) >= 0 && u <= max) \
+ return (type) u; \
+ return (type) -1; \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
new file mode 100644
index 0000000000..6006767daa
--- /dev/null
+++ b/src/basic/string-util.c
@@ -0,0 +1,800 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "gunicode.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int strcmp_ptr(const char *a, const char *b) {
+
+ /* Like strcmp(), but tries to make sense of NULL pointers */
+ if (a && b)
+ return strcmp(a, b);
+
+ if (!a && b)
+ return -1;
+
+ if (a && !b)
+ return 1;
+
+ return 0;
+}
+
+char* endswith(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (memcmp(s + sl - pl, postfix, pl) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
+char* endswith_no_case(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcasecmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
+char* first_word(const char *s, const char *word) {
+ size_t sl, wl;
+ const char *p;
+
+ assert(s);
+ assert(word);
+
+ /* Checks if the string starts with the specified word, either
+ * followed by NUL or by whitespace. Returns a pointer to the
+ * NUL or the first character after the whitespace. */
+
+ sl = strlen(s);
+ wl = strlen(word);
+
+ if (sl < wl)
+ return NULL;
+
+ if (wl == 0)
+ return (char*) s;
+
+ if (memcmp(s, word, wl) != 0)
+ return NULL;
+
+ p = s + wl;
+ if (*p == 0)
+ return (char*) p;
+
+ if (!strchr(WHITESPACE, *p))
+ return NULL;
+
+ p += strspn(p, WHITESPACE);
+ return (char*) p;
+}
+
+static size_t strcspn_escaped(const char *s, const char *reject) {
+ bool escaped = false;
+ int n;
+
+ for (n=0; s[n]; n++) {
+ if (escaped)
+ escaped = false;
+ else if (s[n] == '\\')
+ escaped = true;
+ else if (strchr(reject, s[n]))
+ break;
+ }
+
+ /* if s ends in \, return index of previous char */
+ return n - escaped;
+}
+
+/* Split a string into words. */
+const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
+ const char *current;
+
+ current = *state;
+
+ if (!*current) {
+ assert(**state == '\0');
+ return NULL;
+ }
+
+ current += strspn(current, separator);
+ if (!*current) {
+ *state = current;
+ return NULL;
+ }
+
+ if (quoted && strchr("\'\"", *current)) {
+ char quotechars[2] = {*current, '\0'};
+
+ *l = strcspn_escaped(current + 1, quotechars);
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
+ (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
+ /* right quote missing or garbage at the end */
+ *state = current;
+ return NULL;
+ }
+ *state = current++ + *l + 2;
+ } else if (quoted) {
+ *l = strcspn_escaped(current, separator);
+ if (current[*l] && !strchr(separator, current[*l])) {
+ /* unfinished escape */
+ *state = current;
+ return NULL;
+ }
+ *state = current + *l;
+ } else {
+ *l = strcspn(current, separator);
+ *state = current + *l;
+ }
+
+ return current;
+}
+
+char *strnappend(const char *s, const char *suffix, size_t b) {
+ size_t a;
+ char *r;
+
+ if (!s && !suffix)
+ return strdup("");
+
+ if (!s)
+ return strndup(suffix, b);
+
+ if (!suffix)
+ return strdup(s);
+
+ assert(s);
+ assert(suffix);
+
+ a = strlen(s);
+ if (b > ((size_t) -1) - a)
+ return NULL;
+
+ r = new(char, a+b+1);
+ if (!r)
+ return NULL;
+
+ memcpy(r, s, a);
+ memcpy(r+a, suffix, b);
+ r[a+b] = 0;
+
+ return r;
+}
+
+char *strappend(const char *s, const char *suffix) {
+ return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
+}
+
+char *strjoin(const char *x, ...) {
+ va_list ap;
+ size_t l;
+ char *r, *p;
+
+ va_start(ap, x);
+
+ if (x) {
+ l = strlen(x);
+
+ for (;;) {
+ const char *t;
+ size_t n;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ n = strlen(t);
+ if (n > ((size_t) -1) - l) {
+ va_end(ap);
+ return NULL;
+ }
+
+ l += n;
+ }
+ } else
+ l = 0;
+
+ va_end(ap);
+
+ r = new(char, l+1);
+ if (!r)
+ return NULL;
+
+ if (x) {
+ p = stpcpy(r, x);
+
+ va_start(ap, x);
+
+ for (;;) {
+ const char *t;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ p = stpcpy(p, t);
+ }
+
+ va_end(ap);
+ } else
+ r[0] = 0;
+
+ return r;
+}
+
+char *strstrip(char *s) {
+ char *e;
+
+ /* Drops trailing whitespace. Modifies the string in
+ * place. Returns pointer to first non-space character */
+
+ s += strspn(s, WHITESPACE);
+
+ for (e = strchr(s, 0); e > s; e --)
+ if (!strchr(WHITESPACE, e[-1]))
+ break;
+
+ *e = 0;
+
+ return s;
+}
+
+char *delete_chars(char *s, const char *bad) {
+ char *f, *t;
+
+ /* Drops all whitespace, regardless where in the string */
+
+ for (f = s, t = s; *f; f++) {
+ if (strchr(bad, *f))
+ continue;
+
+ *(t++) = *f;
+ }
+
+ *t = 0;
+
+ return s;
+}
+
+char *truncate_nl(char *s) {
+ assert(s);
+
+ s[strcspn(s, NEWLINE)] = 0;
+ return s;
+}
+
+char *ascii_strlower(char *t) {
+ char *p;
+
+ assert(t);
+
+ for (p = t; *p; p++)
+ if (*p >= 'A' && *p <= 'Z')
+ *p = *p - 'A' + 'a';
+
+ return t;
+}
+
+bool chars_intersect(const char *a, const char *b) {
+ const char *p;
+
+ /* Returns true if any of the chars in a are in b. */
+ for (p = a; *p; p++)
+ if (strchr(b, *p))
+ return true;
+
+ return false;
+}
+
+bool string_has_cc(const char *p, const char *ok) {
+ const char *t;
+
+ assert(p);
+
+ /*
+ * Check if a string contains control characters. If 'ok' is
+ * non-NULL it may be a string containing additional CCs to be
+ * considered OK.
+ */
+
+ for (t = p; *t; t++) {
+ if (ok && strchr(ok, *t))
+ continue;
+
+ if (*t > 0 && *t < ' ')
+ return true;
+
+ if (*t == 127)
+ return true;
+ }
+
+ return false;
+}
+
+static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+ size_t x;
+ char *r;
+
+ assert(s);
+ assert(percent <= 100);
+ assert(new_length >= 3);
+
+ if (old_length <= 3 || old_length <= new_length)
+ return strndup(s, old_length);
+
+ r = new0(char, new_length+1);
+ if (!r)
+ return NULL;
+
+ x = (new_length * percent) / 100;
+
+ if (x > new_length - 3)
+ x = new_length - 3;
+
+ memcpy(r, s, x);
+ r[x] = '.';
+ r[x+1] = '.';
+ r[x+2] = '.';
+ memcpy(r + x + 3,
+ s + old_length - (new_length - x - 3),
+ new_length - x - 3);
+
+ return r;
+}
+
+char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
+ size_t x;
+ char *e;
+ const char *i, *j;
+ unsigned k, len, len2;
+
+ assert(s);
+ assert(percent <= 100);
+ assert(new_length >= 3);
+
+ /* if no multibyte characters use ascii_ellipsize_mem for speed */
+ if (ascii_is_valid(s))
+ return ascii_ellipsize_mem(s, old_length, new_length, percent);
+
+ if (old_length <= 3 || old_length <= new_length)
+ return strndup(s, old_length);
+
+ x = (new_length * percent) / 100;
+
+ if (x > new_length - 3)
+ x = new_length - 3;
+
+ k = 0;
+ for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
+ int c;
+
+ c = utf8_encoded_to_unichar(i);
+ if (c < 0)
+ return NULL;
+ k += unichar_iswide(c) ? 2 : 1;
+ }
+
+ if (k > x) /* last character was wide and went over quota */
+ x ++;
+
+ for (j = s + old_length; k < new_length && j > i; ) {
+ int c;
+
+ j = utf8_prev_char(j);
+ c = utf8_encoded_to_unichar(j);
+ if (c < 0)
+ return NULL;
+ k += unichar_iswide(c) ? 2 : 1;
+ }
+ assert(i <= j);
+
+ /* we don't actually need to ellipsize */
+ if (i == j)
+ return memdup(s, old_length + 1);
+
+ /* make space for ellipsis */
+ j = utf8_next_char(j);
+
+ len = i - s;
+ len2 = s + old_length - j;
+ e = new(char, len + 3 + len2 + 1);
+ if (!e)
+ return NULL;
+
+ /*
+ printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
+ old_length, new_length, x, len, len2, k);
+ */
+
+ memcpy(e, s, len);
+ e[len] = 0xe2; /* tri-dot ellipsis: … */
+ e[len + 1] = 0x80;
+ e[len + 2] = 0xa6;
+
+ memcpy(e + len + 3, j, len2 + 1);
+
+ return e;
+}
+
+char *ellipsize(const char *s, size_t length, unsigned percent) {
+ return ellipsize_mem(s, strlen(s), length, percent);
+}
+
+bool nulstr_contains(const char*nulstr, const char *needle) {
+ const char *i;
+
+ if (!nulstr)
+ return false;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return true;
+
+ return false;
+}
+
+char* strshorten(char *s, size_t l) {
+ assert(s);
+
+ if (l < strlen(s))
+ s[l] = 0;
+
+ return s;
+}
+
+char *strreplace(const char *text, const char *old_string, const char *new_string) {
+ const char *f;
+ char *t, *r;
+ size_t l, old_len, new_len;
+
+ assert(text);
+ assert(old_string);
+ assert(new_string);
+
+ old_len = strlen(old_string);
+ new_len = strlen(new_string);
+
+ l = strlen(text);
+ r = new(char, l+1);
+ if (!r)
+ return NULL;
+
+ f = text;
+ t = r;
+ while (*f) {
+ char *a;
+ size_t d, nl;
+
+ if (!startswith(f, old_string)) {
+ *(t++) = *(f++);
+ continue;
+ }
+
+ d = t - r;
+ nl = l - old_len + new_len;
+ a = realloc(r, nl + 1);
+ if (!a)
+ goto oom;
+
+ l = nl;
+ r = a;
+ t = r + d;
+
+ t = stpcpy(t, new_string);
+ f += old_len;
+ }
+
+ *t = 0;
+ return r;
+
+oom:
+ free(r);
+ return NULL;
+}
+
+char *strip_tab_ansi(char **ibuf, size_t *_isz) {
+ const char *i, *begin = NULL;
+ enum {
+ STATE_OTHER,
+ STATE_ESCAPE,
+ STATE_BRACKET
+ } state = STATE_OTHER;
+ char *obuf = NULL;
+ size_t osz = 0, isz;
+ FILE *f;
+
+ assert(ibuf);
+ assert(*ibuf);
+
+ /* Strips ANSI color and replaces TABs by 8 spaces */
+
+ isz = _isz ? *_isz : strlen(*ibuf);
+
+ f = open_memstream(&obuf, &osz);
+ if (!f)
+ return NULL;
+
+ for (i = *ibuf; i < *ibuf + isz + 1; i++) {
+
+ switch (state) {
+
+ case STATE_OTHER:
+ if (i >= *ibuf + isz) /* EOT */
+ break;
+ else if (*i == '\x1B')
+ state = STATE_ESCAPE;
+ else if (*i == '\t')
+ fputs(" ", f);
+ else
+ fputc(*i, f);
+ break;
+
+ case STATE_ESCAPE:
+ if (i >= *ibuf + isz) { /* EOT */
+ fputc('\x1B', f);
+ break;
+ } else if (*i == '[') {
+ state = STATE_BRACKET;
+ begin = i + 1;
+ } else {
+ fputc('\x1B', f);
+ fputc(*i, f);
+ state = STATE_OTHER;
+ }
+
+ break;
+
+ case STATE_BRACKET:
+
+ if (i >= *ibuf + isz || /* EOT */
+ (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
+ fputc('\x1B', f);
+ fputc('[', f);
+ state = STATE_OTHER;
+ i = begin-1;
+ } else if (*i == 'm')
+ state = STATE_OTHER;
+ break;
+ }
+ }
+
+ if (ferror(f)) {
+ fclose(f);
+ free(obuf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ free(*ibuf);
+ *ibuf = obuf;
+
+ if (_isz)
+ *_isz = osz;
+
+ return obuf;
+}
+
+char *strextend(char **x, ...) {
+ va_list ap;
+ size_t f, l;
+ char *r, *p;
+
+ assert(x);
+
+ l = f = *x ? strlen(*x) : 0;
+
+ va_start(ap, x);
+ for (;;) {
+ const char *t;
+ size_t n;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ n = strlen(t);
+ if (n > ((size_t) -1) - l) {
+ va_end(ap);
+ return NULL;
+ }
+
+ l += n;
+ }
+ va_end(ap);
+
+ r = realloc(*x, l+1);
+ if (!r)
+ return NULL;
+
+ p = r + f;
+
+ va_start(ap, x);
+ for (;;) {
+ const char *t;
+
+ t = va_arg(ap, const char *);
+ if (!t)
+ break;
+
+ p = stpcpy(p, t);
+ }
+ va_end(ap);
+
+ *p = 0;
+ *x = r;
+
+ return r + l;
+}
+
+char *strrep(const char *s, unsigned n) {
+ size_t l;
+ char *r, *p;
+ unsigned i;
+
+ assert(s);
+
+ l = strlen(s);
+ p = r = malloc(l * n + 1);
+ if (!r)
+ return NULL;
+
+ for (i = 0; i < n; i++)
+ p = stpcpy(p, s);
+
+ *p = 0;
+ return r;
+}
+
+int split_pair(const char *s, const char *sep, char **l, char **r) {
+ char *x, *a, *b;
+
+ assert(s);
+ assert(sep);
+ assert(l);
+ assert(r);
+
+ if (isempty(sep))
+ return -EINVAL;
+
+ x = strstr(s, sep);
+ if (!x)
+ return -EINVAL;
+
+ a = strndup(s, x - s);
+ if (!a)
+ return -ENOMEM;
+
+ b = strdup(x + strlen(sep));
+ if (!b) {
+ free(a);
+ return -ENOMEM;
+ }
+
+ *l = a;
+ *r = b;
+
+ return 0;
+}
+
+int free_and_strdup(char **p, const char *s) {
+ char *t;
+
+ assert(p);
+
+ /* Replaces a string pointer with an strdup()ed new string,
+ * possibly freeing the old one. */
+
+ if (streq_ptr(*p, s))
+ return 0;
+
+ if (s) {
+ t = strdup(s);
+ if (!t)
+ return -ENOMEM;
+ } else
+ t = NULL;
+
+ free(*p);
+ *p = t;
+
+ return 1;
+}
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+
+void* memory_erase(void *p, size_t l) {
+ volatile uint8_t* x = (volatile uint8_t*) p;
+
+ /* This basically does what memset() does, but hopefully isn't
+ * optimized away by the compiler. One of those days, when
+ * glibc learns memset_s() we should replace this call by
+ * memset_s(), but until then this has to do. */
+
+ for (; l > 0; l--)
+ *(x++) = 'x';
+
+ return p;
+}
+
+#pragma GCC pop_options
+
+char* string_erase(char *x) {
+
+ if (!x)
+ return NULL;
+
+ /* A delicious drop of snake-oil! To be called on memory where
+ * we stored passphrases or so, after we used them. */
+
+ return memory_erase(x, strlen(x));
+}
+
+char *string_free_erase(char *s) {
+ return mfree(string_erase(s));
+}
+
+bool string_is_safe(const char *p) {
+ const char *t;
+
+ if (!p)
+ return false;
+
+ for (t = p; *t; t++) {
+ if (*t > 0 && *t < ' ') /* no control characters */
+ return false;
+
+ if (strchr(QUOTES "\\\x7f", *t))
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
new file mode 100644
index 0000000000..54f9d3058c
--- /dev/null
+++ b/src/basic/string-util.h
@@ -0,0 +1,184 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "macro.h"
+
+/* What is interpreted as whitespace? */
+#define WHITESPACE " \t\n\r"
+#define NEWLINE "\n\r"
+#define QUOTES "\"\'"
+#define COMMENTS "#;"
+#define GLOB_CHARS "*?["
+#define DIGITS "0123456789"
+#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
+#define ALPHANUMERICAL LETTERS DIGITS
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
+#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
+#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
+
+int strcmp_ptr(const char *a, const char *b) _pure_;
+
+static inline bool streq_ptr(const char *a, const char *b) {
+ return strcmp_ptr(a, b) == 0;
+}
+
+static inline const char* strempty(const char *s) {
+ return s ? s : "";
+}
+
+static inline const char* strnull(const char *s) {
+ return s ? s : "(null)";
+}
+
+static inline const char *strna(const char *s) {
+ return s ? s : "n/a";
+}
+
+static inline bool isempty(const char *p) {
+ return !p || !p[0];
+}
+
+static inline char *startswith(const char *s, const char *prefix) {
+ size_t l;
+
+ l = strlen(prefix);
+ if (strncmp(s, prefix, l) == 0)
+ return (char*) s + l;
+
+ return NULL;
+}
+
+static inline char *startswith_no_case(const char *s, const char *prefix) {
+ size_t l;
+
+ l = strlen(prefix);
+ if (strncasecmp(s, prefix, l) == 0)
+ return (char*) s + l;
+
+ return NULL;
+}
+
+char *endswith(const char *s, const char *postfix) _pure_;
+char *endswith_no_case(const char *s, const char *postfix) _pure_;
+
+char *first_word(const char *s, const char *word) _pure_;
+
+const char* split(const char **state, size_t *l, const char *separator, bool quoted);
+
+#define FOREACH_WORD(word, length, s, state) \
+ _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
+
+#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
+ _FOREACH_WORD(word, length, s, separator, false, state)
+
+#define FOREACH_WORD_QUOTED(word, length, s, state) \
+ _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
+
+#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
+ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
+
+char *strappend(const char *s, const char *suffix);
+char *strnappend(const char *s, const char *suffix, size_t length);
+
+char *strjoin(const char *x, ...) _sentinel_;
+
+#define strjoina(a, ...) \
+ ({ \
+ const char *_appendees_[] = { a, __VA_ARGS__ }; \
+ char *_d_, *_p_; \
+ int _len_ = 0; \
+ unsigned _i_; \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _len_ += strlen(_appendees_[_i_]); \
+ _p_ = _d_ = alloca(_len_ + 1); \
+ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
+ _p_ = stpcpy(_p_, _appendees_[_i_]); \
+ *_p_ = 0; \
+ _d_; \
+ })
+
+char *strstrip(char *s);
+char *delete_chars(char *s, const char *bad);
+char *truncate_nl(char *s);
+
+char *ascii_strlower(char *path);
+
+bool chars_intersect(const char *a, const char *b) _pure_;
+
+static inline bool _pure_ in_charset(const char *s, const char* charset) {
+ assert(s);
+ assert(charset);
+ return s[strspn(s, charset)] == '\0';
+}
+
+bool string_has_cc(const char *p, const char *ok) _pure_;
+
+char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent);
+char *ellipsize(const char *s, size_t length, unsigned percent);
+
+bool nulstr_contains(const char*nulstr, const char *needle);
+
+char* strshorten(char *s, size_t l);
+
+char *strreplace(const char *text, const char *old_string, const char *new_string);
+
+char *strip_tab_ansi(char **p, size_t *l);
+
+char *strextend(char **x, ...) _sentinel_;
+
+char *strrep(const char *s, unsigned n);
+
+int split_pair(const char *s, const char *sep, char **l, char **r);
+
+int free_and_strdup(char **p, const char *s);
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+ if (needlelen <= 0)
+ return (void*) haystack;
+
+ if (haystacklen < needlelen)
+ return NULL;
+
+ assert(haystack);
+ assert(needle);
+
+ return memmem(haystack, haystacklen, needle, needlelen);
+}
+
+void* memory_erase(void *p, size_t l);
+char *string_erase(char *x);
+
+char *string_free_erase(char *s);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
+#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)
+
+bool string_is_safe(const char *p) _pure_;
diff --git a/src/basic/strv.c b/src/basic/strv.c
index b9aef64b15..ba6df716a7 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <errno.h>
#include <stdarg.h>
+#include <stdlib.h>
#include <string.h>
-#include <errno.h>
+#include "alloc-util.h"
+#include "escape.h"
+#include "string-util.h"
#include "util.h"
#include "strv.h"
@@ -86,6 +89,15 @@ char **strv_free(char **l) {
return NULL;
}
+char **strv_free_erase(char **l) {
+ char **i;
+
+ STRV_FOREACH(i, l)
+ string_erase(*i);
+
+ return strv_free(l);
+}
+
char **strv_copy(char * const *l) {
char **r, **k;
@@ -188,17 +200,48 @@ char **strv_new(const char *x, ...) {
return r;
}
-int strv_extend_strv(char ***a, char **b) {
- int r;
- char **s;
+int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
+ char **s, **t;
+ size_t p, q, i = 0, j;
+
+ assert(a);
+
+ if (strv_isempty(b))
+ return 0;
+
+ p = strv_length(*a);
+ q = strv_length(b);
+
+ t = realloc(*a, sizeof(char*) * (p + q + 1));
+ if (!t)
+ return -ENOMEM;
+
+ t[p] = NULL;
+ *a = t;
STRV_FOREACH(s, b) {
- r = strv_extend(a, *s);
- if (r < 0)
- return r;
+
+ if (filter_duplicates && strv_contains(t, *s))
+ continue;
+
+ t[p+i] = strdup(*s);
+ if (!t[p+i])
+ goto rollback;
+
+ i++;
+ t[p+i] = NULL;
}
- return 0;
+ assert(i <= q);
+
+ return (int) i;
+
+rollback:
+ for (j = 0; j < i; j++)
+ free(t[p + j]);
+
+ t[p] = NULL;
+ return -ENOMEM;
}
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
@@ -277,8 +320,8 @@ char **strv_split_newlines(const char *s) {
}
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
- size_t n = 0, allocated = 0;
_cleanup_strv_free_ char **l = NULL;
+ size_t n = 0, allocated = 0;
int r;
assert(t);
@@ -302,13 +345,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
l[n] = NULL;
}
- if (!l)
+ if (!l) {
l = new0(char*, 1);
+ if (!l)
+ return -ENOMEM;
+ }
*t = l;
l = NULL;
- return 0;
+ return (int) n;
}
char *strv_join(char **l, const char *separator) {
@@ -615,6 +661,41 @@ char **strv_split_nulstr(const char *s) {
return r;
}
+int strv_make_nulstr(char **l, char **p, size_t *q) {
+ size_t n_allocated = 0, n = 0;
+ _cleanup_free_ char *m = NULL;
+ char **i;
+
+ assert(p);
+ assert(q);
+
+ STRV_FOREACH(i, l) {
+ size_t z;
+
+ z = strlen(*i);
+
+ if (!GREEDY_REALLOC(m, n_allocated, n + z + 1))
+ return -ENOMEM;
+
+ memcpy(m + n, *i, z + 1);
+ n += z + 1;
+ }
+
+ if (!m) {
+ m = new0(char, 1);
+ if (!m)
+ return -ENOMEM;
+ n = 0;
+ }
+
+ *p = m;
+ *q = n;
+
+ m = NULL;
+
+ return 0;
+}
+
bool strv_overlap(char **a, char **b) {
char **i;
@@ -641,8 +722,12 @@ char **strv_sort(char **l) {
}
bool strv_equal(char **a, char **b) {
- if (!a || !b)
- return a == b;
+
+ if (strv_isempty(a))
+ return strv_isempty(b);
+
+ if (strv_isempty(b))
+ return false;
for ( ; *a || *b; ++a, ++b)
if (!streq_ptr(*a, *b))
@@ -720,3 +805,66 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
return false;
}
+
+char ***strv_free_free(char ***l) {
+ char ***i;
+
+ if (!l)
+ return NULL;
+
+ for (i = l; *i; i++)
+ strv_free(*i);
+
+ free(l);
+ return NULL;
+}
+
+char **strv_skip(char **l, size_t n) {
+
+ while (n > 0) {
+ if (strv_isempty(l))
+ return l;
+
+ l++, n--;
+ }
+
+ return l;
+}
+
+int strv_extend_n(char ***l, const char *value, size_t n) {
+ size_t i, j, k;
+ char **nl;
+
+ assert(l);
+
+ if (!value)
+ return 0;
+ if (n == 0)
+ return 0;
+
+ /* Adds the value value n times to l */
+
+ k = strv_length(*l);
+
+ nl = realloc(*l, sizeof(char*) * (k + n + 1));
+ if (!nl)
+ return -ENOMEM;
+
+ *l = nl;
+
+ for (i = k; i < k + n; i++) {
+ nl[i] = strdup(value);
+ if (!nl[i])
+ goto rollback;
+ }
+
+ nl[i] = NULL;
+ return 0;
+
+rollback:
+ for (j = k; j < i; j++)
+ free(nl[j]);
+
+ nl[k] = NULL;
+ return -ENOMEM;
+}
diff --git a/src/basic/strv.h b/src/basic/strv.h
index f07da8cdf3..e66794fc34 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -21,10 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fnmatch.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <fnmatch.h>
+#include "extract-word.h"
#include "util.h"
char *strv_find(char **l, const char *name) _pure_;
@@ -35,12 +36,16 @@ char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
+char **strv_free_erase(char **l);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
+#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
+
void strv_clear(char **l);
char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_;
-int strv_extend_strv(char ***a, char **b);
+int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
@@ -80,6 +85,7 @@ char *strv_join_quoted(char **l);
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
+int strv_make_nulstr(char **l, char **p, size_t *n);
bool strv_overlap(char **a, char **b) _pure_;
@@ -154,3 +160,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
return strv_isempty(patterns) ||
strv_fnmatch(patterns, s, flags);
}
+
+char ***strv_free_free(char ***l);
+
+char **strv_skip(char **l, size_t n);
+
+int strv_extend_n(char ***l, const char *value, size_t n);
diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c
new file mode 100644
index 0000000000..01577941a0
--- /dev/null
+++ b/src/basic/syslog-util.c
@@ -0,0 +1,115 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <syslog.h>
+
+#include "assert.h"
+#include "hexdecoct.h"
+#include "string-table.h"
+#include "syslog-util.h"
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
+ int a = 0, b = 0, c = 0;
+ int k;
+
+ assert(p);
+ assert(*p);
+ assert(priority);
+
+ if ((*p)[0] != '<')
+ return 0;
+
+ if (!strchr(*p, '>'))
+ return 0;
+
+ if ((*p)[2] == '>') {
+ c = undecchar((*p)[1]);
+ k = 3;
+ } else if ((*p)[3] == '>') {
+ b = undecchar((*p)[1]);
+ c = undecchar((*p)[2]);
+ k = 4;
+ } else if ((*p)[4] == '>') {
+ a = undecchar((*p)[1]);
+ b = undecchar((*p)[2]);
+ c = undecchar((*p)[3]);
+ k = 5;
+ } else
+ return 0;
+
+ if (a < 0 || b < 0 || c < 0 ||
+ (!with_facility && (a || b || c > 7)))
+ return 0;
+
+ if (with_facility)
+ *priority = a*100 + b*10 + c;
+ else
+ *priority = (*priority & LOG_FACMASK) | c;
+
+ *p += k;
+ return 1;
+}
+
+static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
+ [LOG_FAC(LOG_KERN)] = "kern",
+ [LOG_FAC(LOG_USER)] = "user",
+ [LOG_FAC(LOG_MAIL)] = "mail",
+ [LOG_FAC(LOG_DAEMON)] = "daemon",
+ [LOG_FAC(LOG_AUTH)] = "auth",
+ [LOG_FAC(LOG_SYSLOG)] = "syslog",
+ [LOG_FAC(LOG_LPR)] = "lpr",
+ [LOG_FAC(LOG_NEWS)] = "news",
+ [LOG_FAC(LOG_UUCP)] = "uucp",
+ [LOG_FAC(LOG_CRON)] = "cron",
+ [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
+ [LOG_FAC(LOG_FTP)] = "ftp",
+ [LOG_FAC(LOG_LOCAL0)] = "local0",
+ [LOG_FAC(LOG_LOCAL1)] = "local1",
+ [LOG_FAC(LOG_LOCAL2)] = "local2",
+ [LOG_FAC(LOG_LOCAL3)] = "local3",
+ [LOG_FAC(LOG_LOCAL4)] = "local4",
+ [LOG_FAC(LOG_LOCAL5)] = "local5",
+ [LOG_FAC(LOG_LOCAL6)] = "local6",
+ [LOG_FAC(LOG_LOCAL7)] = "local7"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
+
+bool log_facility_unshifted_is_valid(int facility) {
+ return facility >= 0 && facility <= LOG_FAC(~0);
+}
+
+static const char *const log_level_table[] = {
+ [LOG_EMERG] = "emerg",
+ [LOG_ALERT] = "alert",
+ [LOG_CRIT] = "crit",
+ [LOG_ERR] = "err",
+ [LOG_WARNING] = "warning",
+ [LOG_NOTICE] = "notice",
+ [LOG_INFO] = "info",
+ [LOG_DEBUG] = "debug"
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
+
+bool log_level_is_valid(int level) {
+ return level >= 0 && level <= LOG_DEBUG;
+}
diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h
new file mode 100644
index 0000000000..eb79c6dbd8
--- /dev/null
+++ b/src/basic/syslog-util.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+int log_facility_unshifted_to_string_alloc(int i, char **s);
+int log_facility_unshifted_from_string(const char *s);
+bool log_facility_unshifted_is_valid(int faciliy);
+
+int log_level_to_string_alloc(int i, char **s);
+int log_level_from_string(const char *s);
+bool log_level_is_valid(int level);
+
+int syslog_parse_priority(const char **p, int *priority, bool with_facility);
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index dd3d525854..3931b03bc2 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -17,26 +17,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/kd.h>
+#include <linux/tiocl.h>
+#include <linux/vt.h>
+#include <poll.h>
+#include <signal.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <termios.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
#include <time.h>
-#include <assert.h>
-#include <poll.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <linux/kd.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "socket-util.h"
+#include "stat-util.h"
+#include "string-util.h"
#include "terminal-util.h"
#include "time-util.h"
-#include "process-util.h"
#include "util.h"
-#include "fileio.h"
-#include "path-util.h"
static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0;
@@ -48,7 +56,7 @@ int chvt(int vt) {
if (fd < 0)
return -errno;
- if (vt < 0) {
+ if (vt <= 0) {
int tiocl[2] = {
TIOCL_GETKMSGREDIRECT,
0
@@ -412,7 +420,7 @@ int acquire_terminal(
assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
- /* Sometimes it makes sense to ignore TIOCSCTTY
+ /* Sometimes, it makes sense to ignore TIOCSCTTY
* returning EPERM, i.e. when very likely we already
* are have this controlling terminal. */
if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
@@ -480,10 +488,6 @@ int acquire_terminal(
safe_close(notify);
- r = reset_terminal_fd(fd, true);
- if (r < 0)
- log_warning_errno(r, "Failed to reset terminal: %m");
-
return fd;
fail:
@@ -539,8 +543,9 @@ int terminal_vhangup(const char *name) {
}
int vt_disallocate(const char *name) {
- int fd, r;
+ _cleanup_close_ int fd = -1;
unsigned u;
+ int r;
/* Deallocate the VT if possible. If not possible
* (i.e. because it is the active one), at least clear it
@@ -562,8 +567,6 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[2J", /* clear screen */
10, false);
- safe_close(fd);
-
return 0;
}
@@ -583,7 +586,7 @@ int vt_disallocate(const char *name) {
return fd;
r = ioctl(fd, VT_DISALLOCATE, u);
- safe_close(fd);
+ fd = safe_close(fd);
if (r >= 0)
return 0;
@@ -602,32 +605,9 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
10, false);
- safe_close(fd);
-
return 0;
}
-void warn_melody(void) {
- _cleanup_close_ int fd = -1;
-
- fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return;
-
- /* Yeah, this is synchronous. Kinda sucks. But well... */
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/440));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, 0);
-}
-
int make_console_stdio(void) {
int fd, r;
@@ -637,6 +617,10 @@ int make_console_stdio(void) {
if (fd < 0)
return log_error_errno(fd, "Failed to acquire terminal: %m");
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
+
r = make_stdio(fd);
if (r < 0)
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
@@ -644,84 +628,6 @@ int make_console_stdio(void) {
return 0;
}
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
- static const char status_indent[] = " "; /* "[" STATUS "] " */
- _cleanup_free_ char *s = NULL;
- _cleanup_close_ int fd = -1;
- struct iovec iovec[6] = {};
- int n = 0;
- static bool prev_ephemeral;
-
- assert(format);
-
- /* This is independent of logging, as status messages are
- * optional and go exclusively to the console. */
-
- if (vasprintf(&s, format, ap) < 0)
- return log_oom();
-
- fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- if (ellipse) {
- char *e;
- size_t emax, sl;
- int c;
-
- c = fd_columns(fd);
- if (c <= 0)
- c = 80;
-
- sl = status ? sizeof(status_indent)-1 : 0;
-
- emax = c - sl - 1;
- if (emax < 3)
- emax = 3;
-
- e = ellipsize(s, emax, 50);
- if (e) {
- free(s);
- s = e;
- }
- }
-
- if (prev_ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
- prev_ephemeral = ephemeral;
-
- if (status) {
- if (!isempty(status)) {
- IOVEC_SET_STRING(iovec[n++], "[");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "] ");
- } else
- IOVEC_SET_STRING(iovec[n++], status_indent);
- }
-
- IOVEC_SET_STRING(iovec[n++], s);
- if (!ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\n");
-
- if (writev(fd, iovec, n) < 0)
- return -errno;
-
- return 0;
-}
-
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
- va_list ap;
- int r;
-
- assert(format);
-
- va_start(ap, format);
- r = status_vprintf(status, ellipse, ephemeral, format, ap);
- va_end(ap);
-
- return r;
-}
-
bool tty_is_vc(const char *tty) {
assert(tty);
@@ -1075,6 +981,33 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
+int ptsname_malloc(int fd, char **ret) {
+ size_t l = 100;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ for (;;) {
+ char *c;
+
+ c = new(char, l);
+ if (!c)
+ return -ENOMEM;
+
+ if (ptsname_r(fd, c, l) == 0) {
+ *ret = c;
+ return 0;
+ }
+ if (errno != ERANGE) {
+ free(c);
+ return -errno;
+ }
+
+ free(c);
+ l *= 2;
+ }
+}
+
int ptsname_namespace(int pty, char **ret) {
int no = -1, r;
@@ -1093,3 +1026,104 @@ int ptsname_namespace(int pty, char **ret) {
return 0;
}
+
+int openpt_in_namespace(pid_t pid, int flags) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ siginfo_t si;
+ pid_t child;
+ int r;
+
+ assert(pid > 0);
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ int master;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
+ if (master < 0)
+ _exit(EXIT_FAILURE);
+
+ if (unlockpt(master) < 0)
+ _exit(EXIT_FAILURE);
+
+ if (send_one_fd(pair[1], master, 0) < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return -EIO;
+
+ return receive_one_fd(pair[0], 0);
+}
+
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ siginfo_t si;
+ pid_t child;
+ int r;
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ int master;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
+ if (master < 0)
+ _exit(EXIT_FAILURE);
+
+ if (send_one_fd(pair[1], master, 0) < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return -EIO;
+
+ return receive_one_fd(pair[0], 0);
+}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index a9e325ccb3..f2185c1c11 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -67,15 +67,10 @@ bool tty_is_console(const char *tty) _pure_;
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
-void warn_melody(void);
-
int make_stdio(int fd);
int make_null_stdio(void);
int make_console_stdio(void);
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
-
int fd_columns(int fd);
unsigned columns(void);
int fd_lines(int fd);
@@ -122,4 +117,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);
+int ptsname_malloc(int fd, char **ret);
int ptsname_namespace(int pty, char **ret);
+
+int openpt_in_namespace(pid_t pid, int flags);
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 531931f6e1..e629d91cb2 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -19,15 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <time.h>
#include <string.h>
-#include <sys/timex.h>
#include <sys/timerfd.h>
+#include <sys/timex.h>
-#include "util.h"
-#include "time-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "time-util.h"
+#include "util.h"
usec_t now(clockid_t clock_id) {
struct timespec ts;
@@ -205,11 +209,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
+ localtime_or_gmtime_r(&sec, &tm, utc);
- if (utc)
- gmtime_r(&sec, &tm);
- else
- localtime_r(&sec, &tm);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
return NULL;
@@ -235,10 +236,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
- if (utc)
- gmtime_r(&sec, &tm);
- else
- localtime_r(&sec, &tm);
+ localtime_or_gmtime_r(&sec, &tm, utc);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
return NULL;
@@ -484,9 +482,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
};
const char *k;
+ const char *utc;
struct tm tm, copy;
time_t x;
- usec_t plus = 0, minus = 0, ret;
+ usec_t x_usec, plus = 0, minus = 0, ret;
int r, weekday = -1;
unsigned i;
@@ -511,28 +510,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
assert(t);
assert(usec);
- x = time(NULL);
- assert_se(localtime_r(&x, &tm));
- tm.tm_isdst = -1;
-
- if (streq(t, "now"))
- goto finish;
-
- else if (streq(t, "today")) {
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ if (t[0] == '@')
+ return parse_sec(t + 1, usec);
- } else if (streq(t, "yesterday")) {
- tm.tm_mday --;
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ ret = now(CLOCK_REALTIME);
- } else if (streq(t, "tomorrow")) {
- tm.tm_mday ++;
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ if (streq(t, "now"))
goto finish;
- } else if (t[0] == '+') {
+ else if (t[0] == '+') {
r = parse_sec(t+1, &plus);
if (r < 0)
return r;
@@ -546,35 +532,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto finish;
- } else if (t[0] == '@')
- return parse_sec(t + 1, usec);
-
- else if (endswith(t, " ago")) {
- _cleanup_free_ char *z;
+ } else if ((k = endswith(t, " ago"))) {
+ t = strndupa(t, k - t);
- z = strndup(t, strlen(t) - 4);
- if (!z)
- return -ENOMEM;
-
- r = parse_sec(z, &minus);
+ r = parse_sec(t, &minus);
if (r < 0)
return r;
goto finish;
- } else if (endswith(t, " left")) {
- _cleanup_free_ char *z;
- z = strndup(t, strlen(t) - 4);
- if (!z)
- return -ENOMEM;
+ } else if ((k = endswith(t, " left"))) {
+ t = strndupa(t, k - t);
- r = parse_sec(z, &plus);
+ r = parse_sec(t, &plus);
if (r < 0)
return r;
goto finish;
}
+ utc = endswith_no_case(t, " UTC");
+ if (utc)
+ t = strndupa(t, utc - t);
+
+ x = ret / USEC_PER_SEC;
+ x_usec = 0;
+
+ assert_se(localtime_or_gmtime_r(&x, &tm, utc));
+ tm.tm_isdst = -1;
+
+ if (streq(t, "today")) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+
+ } else if (streq(t, "yesterday")) {
+ tm.tm_mday --;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+
+ } else if (streq(t, "tomorrow")) {
+ tm.tm_mday ++;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+ }
+
+
for (i = 0; i < ELEMENTSOF(day_nr); i++) {
size_t skip;
@@ -592,66 +594,106 @@ int parse_timestamp(const char *t, usec_t *usec) {
copy = tm;
k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%y-%m-%d %H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%y-%m-%d", &tm);
if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%Y-%m-%d", &tm);
if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
return -EINVAL;
-finish:
- x = mktime(&tm);
+parse_usec:
+ {
+ char *end;
+ unsigned long long val;
+ size_t l;
+
+ k++;
+ if (*k < '0' || *k > '9')
+ return -EINVAL;
+
+ /* base 10 instead of base 0, .09 is not base 8 */
+ errno = 0;
+ val = strtoull(k, &end, 10);
+ if (*end || errno)
+ return -EINVAL;
+
+ l = end-k;
+
+ /* val has l digits, make them 6 */
+ for (; l < 6; l++)
+ val *= 10;
+ for (; l > 6; l--)
+ val /= 10;
+
+ x_usec = val;
+ }
+
+from_tm:
+ x = mktime_or_timegm(&tm, utc);
if (x == (time_t) -1)
return -EINVAL;
if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
- ret = (usec_t) x * USEC_PER_SEC;
+ ret = (usec_t) x * USEC_PER_SEC + x_usec;
+finish:
ret += plus;
if (ret > minus)
ret -= minus;
@@ -1072,3 +1114,25 @@ int get_timezone(char **tz) {
*tz = z;
return 0;
}
+
+time_t mktime_or_timegm(struct tm *tm, bool utc) {
+ return utc ? timegm(tm) : mktime(tm);
+}
+
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
+ return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
+}
+
+unsigned long usec_to_jiffies(usec_t u) {
+ static thread_local unsigned long hz = 0;
+ long r;
+
+ if (hz == 0) {
+ r = sysconf(_SC_CLK_TCK);
+
+ assert(r > 0);
+ hz = (unsigned long) r;
+ }
+
+ return DIV_ROUND_UP(u , USEC_PER_SEC / hz);
+}
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 1af01541fc..925bf18eb2 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -21,8 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <inttypes.h>
+#include <stdio.h>
+#include <time.h>
typedef uint64_t usec_t;
typedef uint64_t nsec_t;
@@ -117,3 +118,8 @@ clockid_t clock_boottime_or_monotonic(void);
"xstrftime: " #buf "[] must be big enough")
int get_timezone(char **timezone);
+
+time_t mktime_or_timegm(struct tm *tm, bool utc);
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
+
+unsigned long usec_to_jiffies(usec_t usec);
diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h
new file mode 100644
index 0000000000..8ed34658b4
--- /dev/null
+++ b/src/basic/umask-util.h
@@ -0,0 +1,48 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+static inline void umaskp(mode_t *u) {
+ umask(*u);
+}
+
+#define _cleanup_umask_ _cleanup_(umaskp)
+
+struct _umask_struct_ {
+ mode_t mask;
+ bool quit;
+};
+
+static inline void _reset_umask_(struct _umask_struct_ *s) {
+ umask(s->mask);
+};
+
+#define RUN_WITH_UMASK(mask) \
+ for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
+ !_saved_umask_.quit ; \
+ _saved_umask_.quit = true)
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 8742ee757f..710421508c 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -22,12 +22,16 @@
#include <errno.h>
#include <string.h>
-#include "path-util.h"
+#include "alloc-util.h"
#include "bus-label.h"
-#include "util.h"
-#include "unit-name.h"
#include "def.h"
+#include "hexdecoct.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
+#include "unit-name.h"
+#include "util.h"
#define VALID_CHARS \
DIGITS LETTERS \
@@ -651,7 +655,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t
* /blah/blah is converted to blah-blah.mount, anything else is left alone,
* except that @suffix is appended if a valid unit suffix is not present.
*
- * If @allow_globs, globs characters are preserved. Otherwise they are escaped.
+ * If @allow_globs, globs characters are preserved. Otherwise, they are escaped.
*/
int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
char *s, *t;
@@ -839,6 +843,170 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
+ [UNIT_ACTIVE] = "active",
+ [UNIT_RELOADING] = "reloading",
+ [UNIT_INACTIVE] = "inactive",
+ [UNIT_FAILED] = "failed",
+ [UNIT_ACTIVATING] = "activating",
+ [UNIT_DEACTIVATING] = "deactivating"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
+
+static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
+ [AUTOMOUNT_DEAD] = "dead",
+ [AUTOMOUNT_WAITING] = "waiting",
+ [AUTOMOUNT_RUNNING] = "running",
+ [AUTOMOUNT_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
+
+static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
+ [BUSNAME_DEAD] = "dead",
+ [BUSNAME_MAKING] = "making",
+ [BUSNAME_REGISTERED] = "registered",
+ [BUSNAME_LISTENING] = "listening",
+ [BUSNAME_RUNNING] = "running",
+ [BUSNAME_SIGTERM] = "sigterm",
+ [BUSNAME_SIGKILL] = "sigkill",
+ [BUSNAME_FAILED] = "failed",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
+
+static const char* const device_state_table[_DEVICE_STATE_MAX] = {
+ [DEVICE_DEAD] = "dead",
+ [DEVICE_TENTATIVE] = "tentative",
+ [DEVICE_PLUGGED] = "plugged",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
+
+static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
+ [MOUNT_DEAD] = "dead",
+ [MOUNT_MOUNTING] = "mounting",
+ [MOUNT_MOUNTING_DONE] = "mounting-done",
+ [MOUNT_MOUNTED] = "mounted",
+ [MOUNT_REMOUNTING] = "remounting",
+ [MOUNT_UNMOUNTING] = "unmounting",
+ [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
+ [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
+ [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
+ [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
+ [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
+ [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
+ [MOUNT_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
+
+static const char* const path_state_table[_PATH_STATE_MAX] = {
+ [PATH_DEAD] = "dead",
+ [PATH_WAITING] = "waiting",
+ [PATH_RUNNING] = "running",
+ [PATH_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
+
+static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
+ [SCOPE_DEAD] = "dead",
+ [SCOPE_RUNNING] = "running",
+ [SCOPE_ABANDONED] = "abandoned",
+ [SCOPE_STOP_SIGTERM] = "stop-sigterm",
+ [SCOPE_STOP_SIGKILL] = "stop-sigkill",
+ [SCOPE_FAILED] = "failed",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
+
+static const char* const service_state_table[_SERVICE_STATE_MAX] = {
+ [SERVICE_DEAD] = "dead",
+ [SERVICE_START_PRE] = "start-pre",
+ [SERVICE_START] = "start",
+ [SERVICE_START_POST] = "start-post",
+ [SERVICE_RUNNING] = "running",
+ [SERVICE_EXITED] = "exited",
+ [SERVICE_RELOAD] = "reload",
+ [SERVICE_STOP] = "stop",
+ [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
+ [SERVICE_STOP_SIGTERM] = "stop-sigterm",
+ [SERVICE_STOP_SIGKILL] = "stop-sigkill",
+ [SERVICE_STOP_POST] = "stop-post",
+ [SERVICE_FINAL_SIGTERM] = "final-sigterm",
+ [SERVICE_FINAL_SIGKILL] = "final-sigkill",
+ [SERVICE_FAILED] = "failed",
+ [SERVICE_AUTO_RESTART] = "auto-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
+
+static const char* const slice_state_table[_SLICE_STATE_MAX] = {
+ [SLICE_DEAD] = "dead",
+ [SLICE_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
+
+static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
+ [SNAPSHOT_DEAD] = "dead",
+ [SNAPSHOT_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
+
+static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
+ [SOCKET_DEAD] = "dead",
+ [SOCKET_START_PRE] = "start-pre",
+ [SOCKET_START_CHOWN] = "start-chown",
+ [SOCKET_START_POST] = "start-post",
+ [SOCKET_LISTENING] = "listening",
+ [SOCKET_RUNNING] = "running",
+ [SOCKET_STOP_PRE] = "stop-pre",
+ [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
+ [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
+ [SOCKET_STOP_POST] = "stop-post",
+ [SOCKET_FINAL_SIGTERM] = "final-sigterm",
+ [SOCKET_FINAL_SIGKILL] = "final-sigkill",
+ [SOCKET_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+
+static const char* const swap_state_table[_SWAP_STATE_MAX] = {
+ [SWAP_DEAD] = "dead",
+ [SWAP_ACTIVATING] = "activating",
+ [SWAP_ACTIVATING_DONE] = "activating-done",
+ [SWAP_ACTIVE] = "active",
+ [SWAP_DEACTIVATING] = "deactivating",
+ [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
+ [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
+ [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
+ [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
+ [SWAP_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
+
+static const char* const target_state_table[_TARGET_STATE_MAX] = {
+ [TARGET_DEAD] = "dead",
+ [TARGET_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
+
+static const char* const timer_state_table[_TIMER_STATE_MAX] = {
+ [TIMER_DEAD] = "dead",
+ [TIMER_WAITING] = "waiting",
+ [TIMER_RUNNING] = "running",
+ [TIMER_ELAPSED] = "elapsed",
+ [TIMER_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
+
static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
[UNIT_REQUIRES] = "Requires",
[UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index 28b3a555f3..65b55d9554 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -27,11 +27,7 @@
#define UNIT_NAME_MAX 256
-typedef enum UnitType UnitType;
-typedef enum UnitLoadState UnitLoadState;
-typedef enum UnitDependency UnitDependency;
-
-enum UnitType {
+typedef enum UnitType {
UNIT_SERVICE = 0,
UNIT_SOCKET,
UNIT_BUSNAME,
@@ -47,9 +43,9 @@ enum UnitType {
UNIT_SCOPE,
_UNIT_TYPE_MAX,
_UNIT_TYPE_INVALID = -1
-};
+} UnitType;
-enum UnitLoadState {
+typedef enum UnitLoadState {
UNIT_STUB = 0,
UNIT_LOADED,
UNIT_NOT_FOUND,
@@ -58,9 +54,176 @@ enum UnitLoadState {
UNIT_MASKED,
_UNIT_LOAD_STATE_MAX,
_UNIT_LOAD_STATE_INVALID = -1
-};
-
-enum UnitDependency {
+} UnitLoadState;
+
+typedef enum UnitActiveState {
+ UNIT_ACTIVE,
+ UNIT_RELOADING,
+ UNIT_INACTIVE,
+ UNIT_FAILED,
+ UNIT_ACTIVATING,
+ UNIT_DEACTIVATING,
+ _UNIT_ACTIVE_STATE_MAX,
+ _UNIT_ACTIVE_STATE_INVALID = -1
+} UnitActiveState;
+
+typedef enum AutomountState {
+ AUTOMOUNT_DEAD,
+ AUTOMOUNT_WAITING,
+ AUTOMOUNT_RUNNING,
+ AUTOMOUNT_FAILED,
+ _AUTOMOUNT_STATE_MAX,
+ _AUTOMOUNT_STATE_INVALID = -1
+} AutomountState;
+
+typedef enum BusNameState {
+ BUSNAME_DEAD,
+ BUSNAME_MAKING,
+ BUSNAME_REGISTERED,
+ BUSNAME_LISTENING,
+ BUSNAME_RUNNING,
+ BUSNAME_SIGTERM,
+ BUSNAME_SIGKILL,
+ BUSNAME_FAILED,
+ _BUSNAME_STATE_MAX,
+ _BUSNAME_STATE_INVALID = -1
+} BusNameState;
+
+/* We simply watch devices, we cannot plug/unplug them. That
+ * simplifies the state engine greatly */
+typedef enum DeviceState {
+ DEVICE_DEAD,
+ DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
+ DEVICE_PLUGGED, /* announced by udev */
+ _DEVICE_STATE_MAX,
+ _DEVICE_STATE_INVALID = -1
+} DeviceState;
+
+typedef enum MountState {
+ MOUNT_DEAD,
+ MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
+ MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
+ MOUNT_MOUNTED,
+ MOUNT_REMOUNTING,
+ MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM,
+ MOUNT_MOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_FAILED,
+ _MOUNT_STATE_MAX,
+ _MOUNT_STATE_INVALID = -1
+} MountState;
+
+typedef enum PathState {
+ PATH_DEAD,
+ PATH_WAITING,
+ PATH_RUNNING,
+ PATH_FAILED,
+ _PATH_STATE_MAX,
+ _PATH_STATE_INVALID = -1
+} PathState;
+
+typedef enum ScopeState {
+ SCOPE_DEAD,
+ SCOPE_RUNNING,
+ SCOPE_ABANDONED,
+ SCOPE_STOP_SIGTERM,
+ SCOPE_STOP_SIGKILL,
+ SCOPE_FAILED,
+ _SCOPE_STATE_MAX,
+ _SCOPE_STATE_INVALID = -1
+} ScopeState;
+
+typedef enum ServiceState {
+ SERVICE_DEAD,
+ SERVICE_START_PRE,
+ SERVICE_START,
+ SERVICE_START_POST,
+ SERVICE_RUNNING,
+ SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
+ SERVICE_RELOAD,
+ SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
+ SERVICE_STOP_SIGABRT, /* Watchdog timeout */
+ SERVICE_STOP_SIGTERM,
+ SERVICE_STOP_SIGKILL,
+ SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
+ SERVICE_FINAL_SIGKILL,
+ SERVICE_FAILED,
+ SERVICE_AUTO_RESTART,
+ _SERVICE_STATE_MAX,
+ _SERVICE_STATE_INVALID = -1
+} ServiceState;
+
+typedef enum SliceState {
+ SLICE_DEAD,
+ SLICE_ACTIVE,
+ _SLICE_STATE_MAX,
+ _SLICE_STATE_INVALID = -1
+} SliceState;
+
+typedef enum SnapshotState {
+ SNAPSHOT_DEAD,
+ SNAPSHOT_ACTIVE,
+ _SNAPSHOT_STATE_MAX,
+ _SNAPSHOT_STATE_INVALID = -1
+} SnapshotState;
+
+typedef enum SocketState {
+ SOCKET_DEAD,
+ SOCKET_START_PRE,
+ SOCKET_START_CHOWN,
+ SOCKET_START_POST,
+ SOCKET_LISTENING,
+ SOCKET_RUNNING,
+ SOCKET_STOP_PRE,
+ SOCKET_STOP_PRE_SIGTERM,
+ SOCKET_STOP_PRE_SIGKILL,
+ SOCKET_STOP_POST,
+ SOCKET_FINAL_SIGTERM,
+ SOCKET_FINAL_SIGKILL,
+ SOCKET_FAILED,
+ _SOCKET_STATE_MAX,
+ _SOCKET_STATE_INVALID = -1
+} SocketState;
+
+typedef enum SwapState {
+ SWAP_DEAD,
+ SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
+ SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
+ SWAP_ACTIVE,
+ SWAP_DEACTIVATING,
+ SWAP_ACTIVATING_SIGTERM,
+ SWAP_ACTIVATING_SIGKILL,
+ SWAP_DEACTIVATING_SIGTERM,
+ SWAP_DEACTIVATING_SIGKILL,
+ SWAP_FAILED,
+ _SWAP_STATE_MAX,
+ _SWAP_STATE_INVALID = -1
+} SwapState;
+
+
+typedef enum TargetState {
+ TARGET_DEAD,
+ TARGET_ACTIVE,
+ _TARGET_STATE_MAX,
+ _TARGET_STATE_INVALID = -1
+} TargetState;
+
+typedef enum TimerState {
+ TIMER_DEAD,
+ TIMER_WAITING,
+ TIMER_RUNNING,
+ TIMER_ELAPSED,
+ TIMER_FAILED,
+ _TIMER_STATE_MAX,
+ _TIMER_STATE_INVALID = -1
+} TimerState;
+
+typedef enum UnitDependency {
/* Positive dependencies */
UNIT_REQUIRES,
UNIT_REQUIRES_OVERRIDABLE,
@@ -107,7 +270,7 @@ enum UnitDependency {
_UNIT_DEPENDENCY_MAX,
_UNIT_DEPENDENCY_INVALID = -1
-};
+} UnitDependency;
typedef enum UnitNameFlags {
UNIT_NAME_PLAIN = 1, /* Allow foo.service */
@@ -176,5 +339,47 @@ UnitType unit_type_from_string(const char *s) _pure_;
const char *unit_load_state_to_string(UnitLoadState i) _const_;
UnitLoadState unit_load_state_from_string(const char *s) _pure_;
+const char *unit_active_state_to_string(UnitActiveState i) _const_;
+UnitActiveState unit_active_state_from_string(const char *s) _pure_;
+
+const char* automount_state_to_string(AutomountState i) _const_;
+AutomountState automount_state_from_string(const char *s) _pure_;
+
+const char* busname_state_to_string(BusNameState i) _const_;
+BusNameState busname_state_from_string(const char *s) _pure_;
+
+const char* device_state_to_string(DeviceState i) _const_;
+DeviceState device_state_from_string(const char *s) _pure_;
+
+const char* mount_state_to_string(MountState i) _const_;
+MountState mount_state_from_string(const char *s) _pure_;
+
+const char* path_state_to_string(PathState i) _const_;
+PathState path_state_from_string(const char *s) _pure_;
+
+const char* scope_state_to_string(ScopeState i) _const_;
+ScopeState scope_state_from_string(const char *s) _pure_;
+
+const char* service_state_to_string(ServiceState i) _const_;
+ServiceState service_state_from_string(const char *s) _pure_;
+
+const char* slice_state_to_string(SliceState i) _const_;
+SliceState slice_state_from_string(const char *s) _pure_;
+
+const char* snapshot_state_to_string(SnapshotState i) _const_;
+SnapshotState snapshot_state_from_string(const char *s) _pure_;
+
+const char* socket_state_to_string(SocketState i) _const_;
+SocketState socket_state_from_string(const char *s) _pure_;
+
+const char* swap_state_to_string(SwapState i) _const_;
+SwapState swap_state_from_string(const char *s) _pure_;
+
+const char* target_state_to_string(TargetState i) _const_;
+TargetState target_state_from_string(const char *s) _pure_;
+
+const char *timer_state_to_string(TimerState i) _const_;
+TimerState timer_state_from_string(const char *s) _pure_;
+
const char *unit_dependency_to_string(UnitDependency i) _const_;
UnitDependency unit_dependency_from_string(const char *s) _pure_;
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
new file mode 100644
index 0000000000..d6c936db37
--- /dev/null
+++ b/src/basic/user-util.c
@@ -0,0 +1,472 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <pwd.h>
+#include <grp.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+bool uid_is_valid(uid_t uid) {
+
+ /* Some libc APIs use UID_INVALID as special placeholder */
+ if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
+ return false;
+
+ /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
+ if (uid == (uid_t) UINT32_C(0xFFFF))
+ return false;
+
+ return true;
+}
+
+int parse_uid(const char *s, uid_t *ret) {
+ uint32_t uid = 0;
+ int r;
+
+ assert(s);
+
+ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
+ r = safe_atou32(s, &uid);
+ if (r < 0)
+ return r;
+
+ if (!uid_is_valid(uid))
+ return -ENXIO; /* we return ENXIO instead of EINVAL
+ * here, to make it easy to distuingish
+ * invalid numeric uids invalid
+ * strings. */
+
+ if (ret)
+ *ret = uid;
+
+ return 0;
+}
+
+char* getlogname_malloc(void) {
+ uid_t uid;
+ struct stat st;
+
+ if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
+ uid = st.st_uid;
+ else
+ uid = getuid();
+
+ return uid_to_name(uid);
+}
+
+char *getusername_malloc(void) {
+ const char *e;
+
+ e = getenv("USER");
+ if (e)
+ return strdup(e);
+
+ return uid_to_name(getuid());
+}
+
+int get_user_creds(
+ const char **username,
+ uid_t *uid, gid_t *gid,
+ const char **home,
+ const char **shell) {
+
+ struct passwd *p;
+ uid_t u;
+
+ assert(username);
+ assert(*username);
+
+ /* We enforce some special rules for uid=0: in order to avoid
+ * NSS lookups for root we hardcode its data. */
+
+ if (streq(*username, "root") || streq(*username, "0")) {
+ *username = "root";
+
+ if (uid)
+ *uid = 0;
+
+ if (gid)
+ *gid = 0;
+
+ if (home)
+ *home = "/root";
+
+ if (shell)
+ *shell = "/bin/sh";
+
+ return 0;
+ }
+
+ if (parse_uid(*username, &u) >= 0) {
+ errno = 0;
+ p = getpwuid(u);
+
+ /* If there are multiple users with the same id, make
+ * sure to leave $USER to the configured value instead
+ * of the first occurrence in the database. However if
+ * the uid was configured by a numeric uid, then let's
+ * pick the real username from /etc/passwd. */
+ if (p)
+ *username = p->pw_name;
+ } else {
+ errno = 0;
+ p = getpwnam(*username);
+ }
+
+ if (!p)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (uid) {
+ if (!uid_is_valid(p->pw_uid))
+ return -EBADMSG;
+
+ *uid = p->pw_uid;
+ }
+
+ if (gid) {
+ if (!gid_is_valid(p->pw_gid))
+ return -EBADMSG;
+
+ *gid = p->pw_gid;
+ }
+
+ if (home)
+ *home = p->pw_dir;
+
+ if (shell)
+ *shell = p->pw_shell;
+
+ return 0;
+}
+
+int get_group_creds(const char **groupname, gid_t *gid) {
+ struct group *g;
+ gid_t id;
+
+ assert(groupname);
+
+ /* We enforce some special rules for gid=0: in order to avoid
+ * NSS lookups for root we hardcode its data. */
+
+ if (streq(*groupname, "root") || streq(*groupname, "0")) {
+ *groupname = "root";
+
+ if (gid)
+ *gid = 0;
+
+ return 0;
+ }
+
+ if (parse_gid(*groupname, &id) >= 0) {
+ errno = 0;
+ g = getgrgid(id);
+
+ if (g)
+ *groupname = g->gr_name;
+ } else {
+ errno = 0;
+ g = getgrnam(*groupname);
+ }
+
+ if (!g)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (gid) {
+ if (!gid_is_valid(g->gr_gid))
+ return -EBADMSG;
+
+ *gid = g->gr_gid;
+ }
+
+ return 0;
+}
+
+char* uid_to_name(uid_t uid) {
+ char *ret;
+ int r;
+
+ /* Shortcut things to avoid NSS lookups */
+ if (uid == 0)
+ return strdup("root");
+
+ if (uid_is_valid(uid)) {
+ long bufsize;
+
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize <= 0)
+ bufsize = 4096;
+
+ for (;;) {
+ struct passwd pwbuf, *pw = NULL;
+ _cleanup_free_ char *buf = NULL;
+
+ buf = malloc(bufsize);
+ if (!buf)
+ return NULL;
+
+ r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
+ if (r == 0 && pw)
+ return strdup(pw->pw_name);
+ if (r != ERANGE)
+ break;
+
+ bufsize *= 2;
+ }
+ }
+
+ if (asprintf(&ret, UID_FMT, uid) < 0)
+ return NULL;
+
+ return ret;
+}
+
+char* gid_to_name(gid_t gid) {
+ char *ret;
+ int r;
+
+ if (gid == 0)
+ return strdup("root");
+
+ if (gid_is_valid(gid)) {
+ long bufsize;
+
+ bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
+ if (bufsize <= 0)
+ bufsize = 4096;
+
+ for (;;) {
+ struct group grbuf, *gr = NULL;
+ _cleanup_free_ char *buf = NULL;
+
+ buf = malloc(bufsize);
+ if (!buf)
+ return NULL;
+
+ r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
+ if (r == 0 && gr)
+ return strdup(gr->gr_name);
+ if (r != ERANGE)
+ break;
+
+ bufsize *= 2;
+ }
+ }
+
+ if (asprintf(&ret, GID_FMT, gid) < 0)
+ return NULL;
+
+ return ret;
+}
+
+int in_gid(gid_t gid) {
+ gid_t *gids;
+ int ngroups_max, r, i;
+
+ if (getgid() == gid)
+ return 1;
+
+ if (getegid() == gid)
+ return 1;
+
+ if (!gid_is_valid(gid))
+ return -EINVAL;
+
+ ngroups_max = sysconf(_SC_NGROUPS_MAX);
+ assert(ngroups_max > 0);
+
+ gids = alloca(sizeof(gid_t) * ngroups_max);
+
+ r = getgroups(ngroups_max, gids);
+ if (r < 0)
+ return -errno;
+
+ for (i = 0; i < r; i++)
+ if (gids[i] == gid)
+ return 1;
+
+ return 0;
+}
+
+int in_group(const char *name) {
+ int r;
+ gid_t gid;
+
+ r = get_group_creds(&name, &gid);
+ if (r < 0)
+ return r;
+
+ return in_gid(gid);
+}
+
+int get_home_dir(char **_h) {
+ struct passwd *p;
+ const char *e;
+ char *h;
+ uid_t u;
+
+ assert(_h);
+
+ /* Take the user specified one */
+ e = secure_getenv("HOME");
+ if (e && path_is_absolute(e)) {
+ h = strdup(e);
+ if (!h)
+ return -ENOMEM;
+
+ *_h = h;
+ return 0;
+ }
+
+ /* Hardcode home directory for root to avoid NSS */
+ u = getuid();
+ if (u == 0) {
+ h = strdup("/root");
+ if (!h)
+ return -ENOMEM;
+
+ *_h = h;
+ return 0;
+ }
+
+ /* Check the database... */
+ errno = 0;
+ p = getpwuid(u);
+ if (!p)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (!path_is_absolute(p->pw_dir))
+ return -EINVAL;
+
+ h = strdup(p->pw_dir);
+ if (!h)
+ return -ENOMEM;
+
+ *_h = h;
+ return 0;
+}
+
+int get_shell(char **_s) {
+ struct passwd *p;
+ const char *e;
+ char *s;
+ uid_t u;
+
+ assert(_s);
+
+ /* Take the user specified one */
+ e = getenv("SHELL");
+ if (e) {
+ s = strdup(e);
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+ }
+
+ /* Hardcode home directory for root to avoid NSS */
+ u = getuid();
+ if (u == 0) {
+ s = strdup("/bin/sh");
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+ }
+
+ /* Check the database... */
+ errno = 0;
+ p = getpwuid(u);
+ if (!p)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (!path_is_absolute(p->pw_shell))
+ return -EINVAL;
+
+ s = strdup(p->pw_shell);
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+}
+
+int reset_uid_gid(void) {
+
+ if (setgroups(0, NULL) < 0)
+ return -errno;
+
+ if (setresgid(0, 0, 0) < 0)
+ return -errno;
+
+ if (setresuid(0, 0, 0) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int take_etc_passwd_lock(const char *root) {
+
+ struct flock flock = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0,
+ };
+
+ const char *path;
+ int fd, r;
+
+ /* This is roughly the same as lckpwdf(), but not as awful. We
+ * don't want to use alarm() and signals, hence we implement
+ * our own trivial version of this.
+ *
+ * Note that shadow-utils also takes per-database locks in
+ * addition to lckpwdf(). However, we don't given that they
+ * are redundant as they they invoke lckpwdf() first and keep
+ * it during everything they do. The per-database locks are
+ * awfully racy, and thus we just won't do them. */
+
+ if (root)
+ path = prefix_roota(root, "/etc/.pwd.lock");
+ else
+ path = "/etc/.pwd.lock";
+
+ fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
+ if (fd < 0)
+ return -errno;
+
+ r = fcntl(fd, F_SETLKW, &flock);
+ if (r < 0) {
+ safe_close(fd);
+ return -errno;
+ }
+
+ return fd;
+}
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
new file mode 100644
index 0000000000..11ff6674cf
--- /dev/null
+++ b/src/basic/user-util.h
@@ -0,0 +1,67 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+bool uid_is_valid(uid_t uid);
+
+static inline bool gid_is_valid(gid_t gid) {
+ return uid_is_valid((uid_t) gid);
+}
+
+int parse_uid(const char *s, uid_t* ret_uid);
+
+static inline int parse_gid(const char *s, gid_t *ret_gid) {
+ return parse_uid(s, (uid_t*) ret_gid);
+}
+
+char* getlogname_malloc(void);
+char* getusername_malloc(void);
+
+int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
+int get_group_creds(const char **groupname, gid_t *gid);
+
+char* uid_to_name(uid_t uid);
+char* gid_to_name(gid_t gid);
+
+int in_gid(gid_t gid);
+int in_group(const char *name);
+
+int get_home_dir(char **ret);
+int get_shell(char **_ret);
+
+int reset_uid_gid(void);
+
+int take_etc_passwd_lock(const char *root);
+
+#define UID_INVALID ((uid_t) -1)
+#define GID_INVALID ((gid_t) -1)
+
+/* The following macros add 1 when converting things, since UID 0 is a
+ * valid UID, while the pointer NULL is special */
+#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1))
+#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
+#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 800884ffee..7600d99903 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -49,6 +49,8 @@
#include <string.h>
#include <stdbool.h>
+#include "alloc-util.h"
+#include "hexdecoct.h"
#include "utf8.h"
#include "util.h"
diff --git a/src/basic/util.c b/src/basic/util.c
index bc61ec0115..08bdcd28f2 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -23,15 +23,14 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <glob.h>
#include <grp.h>
#include <langinfo.h>
#include <libintl.h>
#include <limits.h>
#include <linux/magic.h>
+#include <linux/oom.h>
#include <linux/sched.h>
#include <locale.h>
-#include <netinet/ip.h>
#include <poll.h>
#include <pwd.h>
#include <sched.h>
@@ -46,7 +45,6 @@
#include <sys/mount.h>
#include <sys/personality.h>
#include <sys/prctl.h>
-#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/time.h>
@@ -54,7 +52,6 @@
#include <sys/utsname.h>
#include <sys/vfs.h>
#include <sys/wait.h>
-#include <sys/xattr.h>
#include <syslog.h>
#include <unistd.h>
@@ -72,10 +69,14 @@
* otherwise conflicts with sys/mount.h. Yay, Linux is great! */
#include <linux/fs.h>
+#include "alloc-util.h"
+#include "build.h"
#include "def.h"
#include "device-nodes.h"
#include "env-util.h"
+#include "escape.h"
#include "exit-status.h"
+#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
#include "gunicode.h"
@@ -86,16 +87,23 @@
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "sparse-endian.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "user-util.h"
#include "utf8.h"
#include "util.h"
#include "virt.h"
+#include "dirent-util.h"
+#include "stat-util.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -117,2847 +125,6 @@ size_t page_size(void) {
return pgsz;
}
-int strcmp_ptr(const char *a, const char *b) {
-
- /* Like strcmp(), but tries to make sense of NULL pointers */
- if (a && b)
- return strcmp(a, b);
-
- if (!a && b)
- return -1;
-
- if (a && !b)
- return 1;
-
- return 0;
-}
-
-bool streq_ptr(const char *a, const char *b) {
- return strcmp_ptr(a, b) == 0;
-}
-
-char* endswith(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (memcmp(s + sl - pl, postfix, pl) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (strcasecmp(s + sl - pl, postfix) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* first_word(const char *s, const char *word) {
- size_t sl, wl;
- const char *p;
-
- assert(s);
- assert(word);
-
- /* Checks if the string starts with the specified word, either
- * followed by NUL or by whitespace. Returns a pointer to the
- * NUL or the first character after the whitespace. */
-
- sl = strlen(s);
- wl = strlen(word);
-
- if (sl < wl)
- return NULL;
-
- if (wl == 0)
- return (char*) s;
-
- if (memcmp(s, word, wl) != 0)
- return NULL;
-
- p = s + wl;
- if (*p == 0)
- return (char*) p;
-
- if (!strchr(WHITESPACE, *p))
- return NULL;
-
- p += strspn(p, WHITESPACE);
- return (char*) p;
-}
-
-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);
-
- if (close(fd) >= 0)
- return 0;
-
- /*
- * Just ignore EINTR; a retry loop is the wrong thing to do on
- * Linux.
- *
- * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
- * https://bugzilla.gnome.org/show_bug.cgi?id=682819
- * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
- * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
- */
- if (errno == EINTR)
- return 0;
-
- return -errno;
-}
-
-int safe_close(int fd) {
-
- /*
- * Like close_nointr() but cannot fail. Guarantees errno is
- * unchanged. Is a NOP with negative fds passed, and returns
- * -1, so that it can be used in this syntax:
- *
- * fd = safe_close(fd);
- */
-
- if (fd >= 0) {
- PROTECT_ERRNO;
-
- /* The kernel might return pretty much any error code
- * via close(), but the fd will be closed anyway. The
- * only condition we want to check for here is whether
- * the fd was invalid at all... */
-
- assert_se(close_nointr(fd) != -EBADF);
- }
-
- return -1;
-}
-
-void close_many(const int fds[], unsigned n_fd) {
- unsigned i;
-
- assert(fds || n_fd <= 0);
-
- for (i = 0; i < n_fd; i++)
- safe_close(fds[i]);
-}
-
-int fclose_nointr(FILE *f) {
- assert(f);
-
- /* Same as close_nointr(), but for fclose() */
-
- if (fclose(f) == 0)
- return 0;
-
- if (errno == EINTR)
- return 0;
-
- return -errno;
-}
-
-FILE* safe_fclose(FILE *f) {
-
- /* Same as safe_close(), but for fclose() */
-
- if (f) {
- PROTECT_ERRNO;
-
- assert_se(fclose_nointr(f) != EBADF);
- }
-
- return NULL;
-}
-
-DIR* safe_closedir(DIR *d) {
-
- if (d) {
- PROTECT_ERRNO;
-
- assert_se(closedir(d) >= 0 || errno != EBADF);
- }
-
- return NULL;
-}
-
-int unlink_noerrno(const char *path) {
- PROTECT_ERRNO;
- int r;
-
- r = unlink(path);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int parse_boolean(const char *v) {
- assert(v);
-
- if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on"))
- return 1;
- else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off"))
- return 0;
-
- return -EINVAL;
-}
-
-int parse_pid(const char *s, pid_t* ret_pid) {
- unsigned long ul = 0;
- pid_t pid;
- int r;
-
- assert(s);
- assert(ret_pid);
-
- r = safe_atolu(s, &ul);
- if (r < 0)
- return r;
-
- pid = (pid_t) ul;
-
- if ((unsigned long) pid != ul)
- return -ERANGE;
-
- if (pid <= 0)
- return -ERANGE;
-
- *ret_pid = pid;
- return 0;
-}
-
-bool uid_is_valid(uid_t uid) {
-
- /* Some libc APIs use UID_INVALID as special placeholder */
- if (uid == (uid_t) 0xFFFFFFFF)
- return false;
-
- /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
- if (uid == (uid_t) 0xFFFF)
- return false;
-
- return true;
-}
-
-int parse_uid(const char *s, uid_t* ret_uid) {
- unsigned long ul = 0;
- uid_t uid;
- int r;
-
- assert(s);
-
- r = safe_atolu(s, &ul);
- if (r < 0)
- return r;
-
- uid = (uid_t) ul;
-
- if ((unsigned long) uid != ul)
- return -ERANGE;
-
- if (!uid_is_valid(uid))
- return -ENXIO; /* we return ENXIO instead of EINVAL
- * here, to make it easy to distuingish
- * invalid numeric uids invalid
- * strings. */
-
- if (ret_uid)
- *ret_uid = uid;
-
- return 0;
-}
-
-int safe_atou(const char *s, unsigned *ret_u) {
- char *x = NULL;
- unsigned long l;
-
- assert(s);
- assert(ret_u);
-
- errno = 0;
- l = strtoul(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
- if ((unsigned long) (unsigned) l != l)
- return -ERANGE;
-
- *ret_u = (unsigned) l;
- return 0;
-}
-
-int safe_atoi(const char *s, int *ret_i) {
- char *x = NULL;
- long l;
-
- assert(s);
- assert(ret_i);
-
- errno = 0;
- l = strtol(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
- if ((long) (int) l != l)
- return -ERANGE;
-
- *ret_i = (int) l;
- return 0;
-}
-
-int safe_atou8(const char *s, uint8_t *ret) {
- char *x = NULL;
- unsigned long l;
-
- assert(s);
- assert(ret);
-
- errno = 0;
- l = strtoul(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
- if ((unsigned long) (uint8_t) l != l)
- return -ERANGE;
-
- *ret = (uint8_t) l;
- return 0;
-}
-
-int safe_atou16(const char *s, uint16_t *ret) {
- char *x = NULL;
- unsigned long l;
-
- assert(s);
- assert(ret);
-
- errno = 0;
- l = strtoul(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
- if ((unsigned long) (uint16_t) l != l)
- return -ERANGE;
-
- *ret = (uint16_t) l;
- return 0;
-}
-
-int safe_atoi16(const char *s, int16_t *ret) {
- char *x = NULL;
- long l;
-
- assert(s);
- assert(ret);
-
- errno = 0;
- l = strtol(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno > 0 ? -errno : -EINVAL;
-
- if ((long) (int16_t) l != l)
- return -ERANGE;
-
- *ret = (int16_t) l;
- return 0;
-}
-
-int safe_atollu(const char *s, long long unsigned *ret_llu) {
- char *x = NULL;
- unsigned long long l;
-
- assert(s);
- assert(ret_llu);
-
- errno = 0;
- l = strtoull(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno ? -errno : -EINVAL;
-
- *ret_llu = l;
- return 0;
-}
-
-int safe_atolli(const char *s, long long int *ret_lli) {
- char *x = NULL;
- long long l;
-
- assert(s);
- assert(ret_lli);
-
- errno = 0;
- l = strtoll(s, &x, 0);
-
- if (!x || x == s || *x || errno)
- return errno ? -errno : -EINVAL;
-
- *ret_lli = l;
- return 0;
-}
-
-int safe_atod(const char *s, double *ret_d) {
- char *x = NULL;
- double d = 0;
- locale_t loc;
-
- assert(s);
- assert(ret_d);
-
- loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
- if (loc == (locale_t) 0)
- return -errno;
-
- errno = 0;
- d = strtod_l(s, &x, loc);
-
- if (!x || x == s || *x || errno) {
- freelocale(loc);
- return errno ? -errno : -EINVAL;
- }
-
- freelocale(loc);
- *ret_d = (double) d;
- return 0;
-}
-
-static size_t strcspn_escaped(const char *s, const char *reject) {
- bool escaped = false;
- int n;
-
- for (n=0; s[n]; n++) {
- if (escaped)
- escaped = false;
- else if (s[n] == '\\')
- escaped = true;
- else if (strchr(reject, s[n]))
- break;
- }
-
- /* if s ends in \, return index of previous char */
- return n - escaped;
-}
-
-/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
- const char *current;
-
- current = *state;
-
- if (!*current) {
- assert(**state == '\0');
- return NULL;
- }
-
- current += strspn(current, separator);
- if (!*current) {
- *state = current;
- return NULL;
- }
-
- if (quoted && strchr("\'\"", *current)) {
- char quotechars[2] = {*current, '\0'};
-
- *l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
- (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
- /* right quote missing or garbage at the end */
- *state = current;
- return NULL;
- }
- *state = current++ + *l + 2;
- } else if (quoted) {
- *l = strcspn_escaped(current, separator);
- if (current[*l] && !strchr(separator, current[*l])) {
- /* unfinished escape */
- *state = current;
- return NULL;
- }
- *state = current + *l;
- } else {
- *l = strcspn(current, separator);
- *state = current + *l;
- }
-
- return current;
-}
-
-int fchmod_umask(int fd, mode_t m) {
- mode_t u;
- int r;
-
- u = umask(0777);
- r = fchmod(fd, m & (~u)) < 0 ? -errno : 0;
- umask(u);
-
- return r;
-}
-
-char *truncate_nl(char *s) {
- assert(s);
-
- s[strcspn(s, NEWLINE)] = 0;
- return s;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
- size_t a;
- char *r;
-
- if (!s && !suffix)
- return strdup("");
-
- if (!s)
- return strndup(suffix, b);
-
- if (!suffix)
- return strdup(s);
-
- assert(s);
- assert(suffix);
-
- a = strlen(s);
- if (b > ((size_t) -1) - a)
- return NULL;
-
- r = new(char, a+b+1);
- if (!r)
- return NULL;
-
- memcpy(r, s, a);
- memcpy(r+a, suffix, b);
- r[a+b] = 0;
-
- return r;
-}
-
-char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
-}
-
-int readlinkat_malloc(int fd, const char *p, char **ret) {
- size_t l = 100;
- int r;
-
- assert(p);
- assert(ret);
-
- for (;;) {
- char *c;
- ssize_t n;
-
- c = new(char, l);
- if (!c)
- return -ENOMEM;
-
- n = readlinkat(fd, p, c, l-1);
- if (n < 0) {
- r = -errno;
- free(c);
- return r;
- }
-
- if ((size_t) n < l-1) {
- c[n] = 0;
- *ret = c;
- return 0;
- }
-
- free(c);
- l *= 2;
- }
-}
-
-int readlink_malloc(const char *p, char **ret) {
- return readlinkat_malloc(AT_FDCWD, p, ret);
-}
-
-int readlink_value(const char *p, char **ret) {
- _cleanup_free_ char *link = NULL;
- char *value;
- int r;
-
- r = readlink_malloc(p, &link);
- if (r < 0)
- return r;
-
- value = basename(link);
- if (!value)
- return -ENOENT;
-
- value = strdup(value);
- if (!value)
- return -ENOMEM;
-
- *ret = value;
-
- return 0;
-}
-
-int readlink_and_make_absolute(const char *p, char **r) {
- _cleanup_free_ char *target = NULL;
- char *k;
- int j;
-
- assert(p);
- assert(r);
-
- j = readlink_malloc(p, &target);
- if (j < 0)
- return j;
-
- k = file_in_same_dir(p, target);
- if (!k)
- return -ENOMEM;
-
- *r = k;
- return 0;
-}
-
-int readlink_and_canonicalize(const char *p, char **r) {
- char *t, *s;
- int j;
-
- assert(p);
- assert(r);
-
- j = readlink_and_make_absolute(p, &t);
- if (j < 0)
- return j;
-
- s = canonicalize_file_name(t);
- if (s) {
- free(t);
- *r = s;
- } else
- *r = t;
-
- path_kill_slashes(*r);
-
- return 0;
-}
-
-char *strstrip(char *s) {
- char *e;
-
- /* Drops trailing whitespace. Modifies the string in
- * place. Returns pointer to first non-space character */
-
- s += strspn(s, WHITESPACE);
-
- for (e = strchr(s, 0); e > s; e --)
- if (!strchr(WHITESPACE, e[-1]))
- break;
-
- *e = 0;
-
- return s;
-}
-
-char *delete_chars(char *s, const char *bad) {
- char *f, *t;
-
- /* Drops all whitespace, regardless where in the string */
-
- for (f = s, t = s; *f; f++) {
- if (strchr(bad, *f))
- continue;
-
- *(t++) = *f;
- }
-
- *t = 0;
-
- return s;
-}
-
-char *file_in_same_dir(const char *path, const char *filename) {
- char *e, *ret;
- size_t k;
-
- assert(path);
- assert(filename);
-
- /* This removes the last component of path and appends
- * filename, unless the latter is absolute anyway or the
- * former isn't */
-
- if (path_is_absolute(filename))
- return strdup(filename);
-
- e = strrchr(path, '/');
- if (!e)
- return strdup(filename);
-
- k = strlen(filename);
- ret = new(char, (e + 1 - path) + k + 1);
- if (!ret)
- return NULL;
-
- memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
- return ret;
-}
-
-int rmdir_parents(const char *path, const char *stop) {
- size_t l;
- int r = 0;
-
- assert(path);
- assert(stop);
-
- l = strlen(path);
-
- /* Skip trailing slashes */
- while (l > 0 && path[l-1] == '/')
- l--;
-
- while (l > 0) {
- char *t;
-
- /* Skip last component */
- while (l > 0 && path[l-1] != '/')
- l--;
-
- /* Skip trailing slashes */
- while (l > 0 && path[l-1] == '/')
- l--;
-
- if (l <= 0)
- break;
-
- if (!(t = strndup(path, l)))
- return -ENOMEM;
-
- if (path_startswith(stop, t)) {
- free(t);
- return 0;
- }
-
- r = rmdir(t);
- free(t);
-
- if (r < 0)
- if (errno != ENOENT)
- return -errno;
- }
-
- return 0;
-}
-
-char hexchar(int x) {
- static const char table[16] = "0123456789abcdef";
-
- return table[x & 15];
-}
-
-int unhexchar(char c) {
-
- if (c >= '0' && c <= '9')
- return c - '0';
-
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
-
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
-
- return -EINVAL;
-}
-
-char *hexmem(const void *p, size_t l) {
- char *r, *z;
- const uint8_t *x;
-
- z = r = malloc(l * 2 + 1);
- if (!r)
- return NULL;
-
- for (x = p; x < (const uint8_t*) p + l; x++) {
- *(z++) = hexchar(*x >> 4);
- *(z++) = hexchar(*x & 15);
- }
-
- *z = 0;
- return r;
-}
-
-int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
- _cleanup_free_ uint8_t *r = NULL;
- uint8_t *z;
- const char *x;
-
- assert(mem);
- assert(len);
- assert(p);
-
- z = r = malloc((l + 1) / 2 + 1);
- if (!r)
- return -ENOMEM;
-
- for (x = p; x < p + l; x += 2) {
- int a, b;
-
- a = unhexchar(x[0]);
- if (a < 0)
- return a;
- else if (x+1 < p + l) {
- b = unhexchar(x[1]);
- if (b < 0)
- return b;
- } else
- b = 0;
-
- *(z++) = (uint8_t) a << 4 | (uint8_t) b;
- }
-
- *z = 0;
-
- *mem = r;
- r = NULL;
- *len = (l + 1) / 2;
-
- return 0;
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-6
- * Notice that base32hex differs from base32 in the alphabet it uses.
- * The distinction is that the base32hex representation preserves the
- * order of the underlying data when compared as bytestrings, this is
- * useful when representing NSEC3 hashes, as one can then verify the
- * order of hashes directly from their representation. */
-char base32hexchar(int x) {
- static const char table[32] = "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUV";
-
- return table[x & 31];
-}
-
-int unbase32hexchar(char c) {
- unsigned offset;
-
- if (c >= '0' && c <= '9')
- return c - '0';
-
- offset = '9' - '0' + 1;
-
- if (c >= 'A' && c <= 'V')
- return c - 'A' + offset;
-
- return -EINVAL;
-}
-
-char *base32hexmem(const void *p, size_t l, bool padding) {
- char *r, *z;
- const uint8_t *x;
- size_t len;
-
- if (padding)
- /* five input bytes makes eight output bytes, padding is added so we must round up */
- len = 8 * (l + 4) / 5;
- else {
- /* same, but round down as there is no padding */
- len = 8 * l / 5;
-
- switch (l % 5) {
- case 4:
- len += 7;
- break;
- case 3:
- len += 5;
- break;
- case 2:
- len += 4;
- break;
- case 1:
- len += 2;
- break;
- }
- }
-
- z = r = malloc(len + 1);
- if (!r)
- return NULL;
-
- for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
- /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
- x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
- *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
- *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
- *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
- *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
- *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
- *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
- *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
- *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
- }
-
- switch (l % 5) {
- case 4:
- *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
- *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
- *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
- *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
- *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
- *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
- *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
- if (padding)
- *(z++) = '=';
-
- break;
-
- case 3:
- *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
- *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
- *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
- *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
- *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
- if (padding) {
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- }
-
- break;
-
- case 2:
- *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
- *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
- *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
- *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
- if (padding) {
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- }
-
- break;
-
- case 1:
- *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
- *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
- if (padding) {
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- *(z++) = '=';
- }
-
- break;
- }
-
- *z = 0;
- return r;
-}
-
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
- _cleanup_free_ uint8_t *r = NULL;
- int a, b, c, d, e, f, g, h;
- uint8_t *z;
- const char *x;
- size_t len;
- unsigned pad = 0;
-
- assert(p);
-
- /* padding ensures any base32hex input has input divisible by 8 */
- if (padding && l % 8 != 0)
- return -EINVAL;
-
- if (padding) {
- /* strip the padding */
- while (l > 0 && p[l - 1] == '=' && pad < 7) {
- pad ++;
- l --;
- }
- }
-
- /* a group of eight input bytes needs five output bytes, in case of
- padding we need to add some extra bytes */
- len = (l / 8) * 5;
-
- switch (l % 8) {
- case 7:
- len += 4;
- break;
- case 5:
- len += 3;
- break;
- case 4:
- len += 2;
- break;
- case 2:
- len += 1;
- break;
- case 0:
- break;
- default:
- return -EINVAL;
- }
-
- z = r = malloc(len + 1);
- if (!r)
- return -ENOMEM;
-
- for (x = p; x < p + (l / 8) * 8; x += 8) {
- /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
- e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
- a = unbase32hexchar(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase32hexchar(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase32hexchar(x[2]);
- if (c < 0)
- return -EINVAL;
-
- d = unbase32hexchar(x[3]);
- if (d < 0)
- return -EINVAL;
-
- e = unbase32hexchar(x[4]);
- if (e < 0)
- return -EINVAL;
-
- f = unbase32hexchar(x[5]);
- if (f < 0)
- return -EINVAL;
-
- g = unbase32hexchar(x[6]);
- if (g < 0)
- return -EINVAL;
-
- h = unbase32hexchar(x[7]);
- if (h < 0)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
- *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
- *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
- *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
- *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
- }
-
- switch (l % 8) {
- case 7:
- a = unbase32hexchar(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase32hexchar(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase32hexchar(x[2]);
- if (c < 0)
- return -EINVAL;
-
- d = unbase32hexchar(x[3]);
- if (d < 0)
- return -EINVAL;
-
- e = unbase32hexchar(x[4]);
- if (e < 0)
- return -EINVAL;
-
- f = unbase32hexchar(x[5]);
- if (f < 0)
- return -EINVAL;
-
- g = unbase32hexchar(x[6]);
- if (g < 0)
- return -EINVAL;
-
- /* g == 000VV000 */
- if (g & 7)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
- *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
- *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
- *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
-
- break;
- case 5:
- a = unbase32hexchar(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase32hexchar(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase32hexchar(x[2]);
- if (c < 0)
- return -EINVAL;
-
- d = unbase32hexchar(x[3]);
- if (d < 0)
- return -EINVAL;
-
- e = unbase32hexchar(x[4]);
- if (e < 0)
- return -EINVAL;
-
- /* e == 000SSSS0 */
- if (e & 1)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
- *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
- *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
-
- break;
- case 4:
- a = unbase32hexchar(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase32hexchar(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase32hexchar(x[2]);
- if (c < 0)
- return -EINVAL;
-
- d = unbase32hexchar(x[3]);
- if (d < 0)
- return -EINVAL;
-
- /* d == 000W0000 */
- if (d & 15)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
- *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
-
- break;
- case 2:
- a = unbase32hexchar(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase32hexchar(x[1]);
- if (b < 0)
- return -EINVAL;
-
- /* b == 000YYY00 */
- if (b & 3)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
-
- break;
- case 0:
- break;
- default:
- return -EINVAL;
- }
-
- *z = 0;
-
- *mem = r;
- r = NULL;
- *_len = len;
-
- return 0;
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-4 */
-char base64char(int x) {
- static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
- return table[x & 63];
-}
-
-int unbase64char(char c) {
- unsigned offset;
-
- if (c >= 'A' && c <= 'Z')
- return c - 'A';
-
- offset = 'Z' - 'A' + 1;
-
- if (c >= 'a' && c <= 'z')
- return c - 'a' + offset;
-
- offset += 'z' - 'a' + 1;
-
- if (c >= '0' && c <= '9')
- return c - '0' + offset;
-
- offset += '9' - '0' + 1;
-
- if (c == '+')
- return offset;
-
- offset ++;
-
- if (c == '/')
- return offset;
-
- return -EINVAL;
-}
-
-char *base64mem(const void *p, size_t l) {
- char *r, *z;
- const uint8_t *x;
-
- /* three input bytes makes four output bytes, padding is added so we must round up */
- z = r = malloc(4 * (l + 2) / 3 + 1);
- if (!r)
- return NULL;
-
- for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
- /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
- *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
- *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
- *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
- }
-
- switch (l % 3) {
- case 2:
- *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
- *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
- *(z++) = '=';
-
- break;
- case 1:
- *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
- *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
- *(z++) = '=';
- *(z++) = '=';
-
- break;
- }
-
- *z = 0;
- return r;
-}
-
-int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
- _cleanup_free_ uint8_t *r = NULL;
- int a, b, c, d;
- uint8_t *z;
- const char *x;
- size_t len;
-
- assert(p);
-
- /* padding ensures any base63 input has input divisible by 4 */
- if (l % 4 != 0)
- return -EINVAL;
-
- /* strip the padding */
- if (l > 0 && p[l - 1] == '=')
- l --;
- if (l > 0 && p[l - 1] == '=')
- l --;
-
- /* a group of four input bytes needs three output bytes, in case of
- padding we need to add two or three extra bytes */
- len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
-
- z = r = malloc(len + 1);
- if (!r)
- return -ENOMEM;
-
- for (x = p; x < p + (l / 4) * 4; x += 4) {
- /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
- a = unbase64char(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase64char(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase64char(x[2]);
- if (c < 0)
- return -EINVAL;
-
- d = unbase64char(x[3]);
- if (d < 0)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
- *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
- *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
- }
-
- switch (l % 4) {
- case 3:
- a = unbase64char(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase64char(x[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unbase64char(x[2]);
- if (c < 0)
- return -EINVAL;
-
- /* c == 00ZZZZ00 */
- if (c & 3)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
- *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
-
- break;
- case 2:
- a = unbase64char(x[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unbase64char(x[1]);
- if (b < 0)
- return -EINVAL;
-
- /* b == 00YY0000 */
- if (b & 15)
- return -EINVAL;
-
- *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
-
- break;
- case 0:
-
- break;
- default:
- return -EINVAL;
- }
-
- *z = 0;
-
- *mem = r;
- r = NULL;
- *_len = len;
-
- return 0;
-}
-
-char octchar(int x) {
- return '0' + (x & 7);
-}
-
-int unoctchar(char c) {
-
- if (c >= '0' && c <= '7')
- return c - '0';
-
- return -EINVAL;
-}
-
-char decchar(int x) {
- return '0' + (x % 10);
-}
-
-int undecchar(char c) {
-
- if (c >= '0' && c <= '9')
- return c - '0';
-
- return -EINVAL;
-}
-
-char *cescape(const char *s) {
- char *r, *t;
- const char *f;
-
- assert(s);
-
- /* Does C style string escaping. May be reversed with
- * cunescape(). */
-
- r = new(char, strlen(s)*4 + 1);
- if (!r)
- return NULL;
-
- for (f = s, t = r; *f; f++)
- t += cescape_char(*f, t);
-
- *t = 0;
-
- return r;
-}
-
-static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
- int r = 1;
-
- assert(p);
- assert(*p);
- assert(ret);
-
- /* Unescapes C style. Returns the unescaped character in ret,
- * unless we encountered a \u sequence in which case the full
- * unicode character is returned in ret_unicode, instead. */
-
- if (length != (size_t) -1 && length < 1)
- return -EINVAL;
-
- switch (p[0]) {
-
- case 'a':
- *ret = '\a';
- break;
- case 'b':
- *ret = '\b';
- break;
- case 'f':
- *ret = '\f';
- break;
- case 'n':
- *ret = '\n';
- break;
- case 'r':
- *ret = '\r';
- break;
- case 't':
- *ret = '\t';
- break;
- case 'v':
- *ret = '\v';
- break;
- case '\\':
- *ret = '\\';
- break;
- case '"':
- *ret = '"';
- break;
- case '\'':
- *ret = '\'';
- break;
-
- case 's':
- /* This is an extension of the XDG syntax files */
- *ret = ' ';
- break;
-
- case 'x': {
- /* hexadecimal encoding */
- int a, b;
-
- if (length != (size_t) -1 && length < 3)
- return -EINVAL;
-
- a = unhexchar(p[1]);
- if (a < 0)
- return -EINVAL;
-
- b = unhexchar(p[2]);
- if (b < 0)
- return -EINVAL;
-
- /* Don't allow NUL bytes */
- if (a == 0 && b == 0)
- return -EINVAL;
-
- *ret = (char) ((a << 4U) | b);
- r = 3;
- break;
- }
-
- case 'u': {
- /* C++11 style 16bit unicode */
-
- int a[4];
- unsigned i;
- uint32_t c;
-
- if (length != (size_t) -1 && length < 5)
- return -EINVAL;
-
- for (i = 0; i < 4; i++) {
- a[i] = unhexchar(p[1 + i]);
- if (a[i] < 0)
- return a[i];
- }
-
- c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
-
- /* Don't allow 0 chars */
- if (c == 0)
- return -EINVAL;
-
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
- r = 5;
- break;
- }
-
- case 'U': {
- /* C++11 style 32bit unicode */
-
- int a[8];
- unsigned i;
- uint32_t c;
-
- if (length != (size_t) -1 && length < 9)
- return -EINVAL;
-
- for (i = 0; i < 8; i++) {
- a[i] = unhexchar(p[1 + i]);
- if (a[i] < 0)
- return a[i];
- }
-
- c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
- ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
-
- /* Don't allow 0 chars */
- if (c == 0)
- return -EINVAL;
-
- /* Don't allow invalid code points */
- if (!unichar_is_valid(c))
- return -EINVAL;
-
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
- r = 9;
- break;
- }
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- /* octal encoding */
- int a, b, c;
- uint32_t m;
-
- if (length != (size_t) -1 && length < 3)
- return -EINVAL;
-
- a = unoctchar(p[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unoctchar(p[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unoctchar(p[2]);
- if (c < 0)
- return -EINVAL;
-
- /* don't allow NUL bytes */
- if (a == 0 && b == 0 && c == 0)
- return -EINVAL;
-
- /* Don't allow bytes above 255 */
- m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
- if (m > 255)
- return -EINVAL;
-
- *ret = m;
- r = 3;
- break;
- }
-
- default:
- return -EINVAL;
- }
-
- return r;
-}
-
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
- char *r, *t;
- const char *f;
- size_t pl;
-
- assert(s);
- assert(ret);
-
- /* Undoes C style string escaping, and optionally prefixes it. */
-
- pl = prefix ? strlen(prefix) : 0;
-
- r = new(char, pl+length+1);
- if (!r)
- return -ENOMEM;
-
- if (prefix)
- memcpy(r, prefix, pl);
-
- for (f = s, t = r + pl; f < s + length; f++) {
- size_t remaining;
- uint32_t u;
- char c;
- int k;
-
- remaining = s + length - f;
- assert(remaining > 0);
-
- if (*f != '\\') {
- /* A literal literal, copy verbatim */
- *(t++) = *f;
- continue;
- }
-
- if (remaining == 1) {
- if (flags & UNESCAPE_RELAX) {
- /* A trailing backslash, copy verbatim */
- *(t++) = *f;
- continue;
- }
-
- free(r);
- return -EINVAL;
- }
-
- k = cunescape_one(f + 1, remaining - 1, &c, &u);
- if (k < 0) {
- if (flags & UNESCAPE_RELAX) {
- /* Invalid escape code, let's take it literal then */
- *(t++) = '\\';
- continue;
- }
-
- free(r);
- return k;
- }
-
- if (c != 0)
- /* Non-Unicode? Let's encode this directly */
- *(t++) = c;
- else
- /* Unicode? Then let's encode this in UTF-8 */
- t += utf8_encode_unichar(t, u);
-
- f += k;
- }
-
- *t = 0;
-
- *ret = r;
- return t - r;
-}
-
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
- return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret) {
- return cunescape_length(s, strlen(s), flags, ret);
-}
-
-char *xescape(const char *s, const char *bad) {
- char *r, *t;
- const char *f;
-
- /* Escapes all chars in bad, in addition to \ and all special
- * chars, in \xFF style escaping. May be reversed with
- * cunescape(). */
-
- r = new(char, strlen(s) * 4 + 1);
- if (!r)
- return NULL;
-
- for (f = s, t = r; *f; f++) {
-
- if ((*f < ' ') || (*f >= 127) ||
- (*f == '\\') || strchr(bad, *f)) {
- *(t++) = '\\';
- *(t++) = 'x';
- *(t++) = hexchar(*f >> 4);
- *(t++) = hexchar(*f);
- } else
- *(t++) = *f;
- }
-
- *t = 0;
-
- return r;
-}
-
-char *ascii_strlower(char *t) {
- char *p;
-
- assert(t);
-
- for (p = t; *p; p++)
- if (*p >= 'A' && *p <= 'Z')
- *p = *p - 'A' + 'a';
-
- return t;
-}
-
-_pure_ static bool hidden_file_allow_backup(const char *filename) {
- assert(filename);
-
- return
- filename[0] == '.' ||
- streq(filename, "lost+found") ||
- streq(filename, "aquota.user") ||
- streq(filename, "aquota.group") ||
- endswith(filename, ".rpmnew") ||
- endswith(filename, ".rpmsave") ||
- endswith(filename, ".rpmorig") ||
- endswith(filename, ".dpkg-old") ||
- endswith(filename, ".dpkg-new") ||
- endswith(filename, ".dpkg-tmp") ||
- endswith(filename, ".dpkg-dist") ||
- endswith(filename, ".dpkg-bak") ||
- endswith(filename, ".dpkg-backup") ||
- endswith(filename, ".dpkg-remove") ||
- endswith(filename, ".swp");
-}
-
-bool hidden_file(const char *filename) {
- assert(filename);
-
- if (endswith(filename, "~"))
- return true;
-
- return hidden_file_allow_backup(filename);
-}
-
-int fd_nonblock(int fd, bool nonblock) {
- int flags, nflags;
-
- assert(fd >= 0);
-
- flags = fcntl(fd, F_GETFL, 0);
- if (flags < 0)
- return -errno;
-
- if (nonblock)
- nflags = flags | O_NONBLOCK;
- else
- nflags = flags & ~O_NONBLOCK;
-
- if (nflags == flags)
- return 0;
-
- if (fcntl(fd, F_SETFL, nflags) < 0)
- return -errno;
-
- return 0;
-}
-
-int fd_cloexec(int fd, bool cloexec) {
- int flags, nflags;
-
- assert(fd >= 0);
-
- flags = fcntl(fd, F_GETFD, 0);
- if (flags < 0)
- return -errno;
-
- if (cloexec)
- nflags = flags | FD_CLOEXEC;
- else
- nflags = flags & ~FD_CLOEXEC;
-
- if (nflags == flags)
- return 0;
-
- if (fcntl(fd, F_SETFD, nflags) < 0)
- return -errno;
-
- return 0;
-}
-
-_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
- unsigned i;
-
- assert(n_fdset == 0 || fdset);
-
- for (i = 0; i < n_fdset; i++)
- if (fdset[i] == fd)
- return true;
-
- return false;
-}
-
-int close_all_fds(const int except[], unsigned n_except) {
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
- int r = 0;
-
- assert(n_except == 0 || except);
-
- d = opendir("/proc/self/fd");
- if (!d) {
- int fd;
- struct rlimit rl;
-
- /* When /proc isn't available (for example in chroots)
- * the fallback is brute forcing through the fd
- * table */
-
- assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0);
- for (fd = 3; fd < (int) rl.rlim_max; fd ++) {
-
- if (fd_in_set(fd, except, n_except))
- continue;
-
- if (close_nointr(fd) < 0)
- if (errno != EBADF && r == 0)
- r = -errno;
- }
-
- return r;
- }
-
- while ((de = readdir(d))) {
- int fd = -1;
-
- if (hidden_file(de->d_name))
- continue;
-
- if (safe_atoi(de->d_name, &fd) < 0)
- /* Let's better ignore this, just in case */
- continue;
-
- if (fd < 3)
- continue;
-
- if (fd == dirfd(d))
- continue;
-
- if (fd_in_set(fd, except, n_except))
- continue;
-
- if (close_nointr(fd) < 0) {
- /* Valgrind has its own FD and doesn't want to have it closed */
- if (errno != EBADF && r == 0)
- r = -errno;
- }
- }
-
- return r;
-}
-
-bool chars_intersect(const char *a, const char *b) {
- const char *p;
-
- /* Returns true if any of the chars in a are in b. */
- for (p = a; *p; p++)
- if (strchr(b, *p))
- return true;
-
- return false;
-}
-
-bool fstype_is_network(const char *fstype) {
- static const char table[] =
- "afs\0"
- "cifs\0"
- "smbfs\0"
- "sshfs\0"
- "ncpfs\0"
- "ncp\0"
- "nfs\0"
- "nfs4\0"
- "gfs\0"
- "gfs2\0"
- "glusterfs\0";
-
- const char *x;
-
- x = startswith(fstype, "fuse.");
- if (x)
- fstype = x;
-
- return nulstr_contains(table, fstype);
-}
-
-int flush_fd(int fd) {
- struct pollfd pollfd = {
- .fd = fd,
- .events = POLLIN,
- };
-
- for (;;) {
- char buf[LINE_MAX];
- ssize_t l;
- int r;
-
- r = poll(&pollfd, 1, 0);
- if (r < 0) {
- if (errno == EINTR)
- continue;
-
- return -errno;
-
- } else if (r == 0)
- return 0;
-
- l = read(fd, buf, sizeof(buf));
- if (l < 0) {
-
- if (errno == EINTR)
- continue;
-
- if (errno == EAGAIN)
- return 0;
-
- return -errno;
- } else if (l == 0)
- return 0;
- }
-}
-
-void safe_close_pair(int p[]) {
- assert(p);
-
- if (p[0] == p[1]) {
- /* Special case pairs which use the same fd in both
- * directions... */
- p[0] = p[1] = safe_close(p[0]);
- return;
- }
-
- p[0] = safe_close(p[0]);
- p[1] = safe_close(p[1]);
-}
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
- uint8_t *p = buf;
- ssize_t n = 0;
-
- assert(fd >= 0);
- assert(buf);
-
- /* If called with nbytes == 0, let's call read() at least
- * once, to validate the operation */
-
- if (nbytes > (size_t) SSIZE_MAX)
- return -EINVAL;
-
- do {
- ssize_t k;
-
- k = read(fd, p, nbytes);
- if (k < 0) {
- if (errno == EINTR)
- continue;
-
- if (errno == EAGAIN && do_poll) {
-
- /* We knowingly ignore any return value here,
- * and expect that any error/EOF is reported
- * via read() */
-
- (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
- continue;
- }
-
- return n > 0 ? n : -errno;
- }
-
- if (k == 0)
- return n;
-
- assert((size_t) k <= nbytes);
-
- p += k;
- nbytes -= k;
- n += k;
- } while (nbytes > 0);
-
- return n;
-}
-
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
- ssize_t n;
-
- n = loop_read(fd, buf, nbytes, do_poll);
- if (n < 0)
- return (int) n;
- if ((size_t) n != nbytes)
- return -EIO;
-
- return 0;
-}
-
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
- const uint8_t *p = buf;
-
- assert(fd >= 0);
- assert(buf);
-
- if (nbytes > (size_t) SSIZE_MAX)
- return -EINVAL;
-
- do {
- ssize_t k;
-
- k = write(fd, p, nbytes);
- if (k < 0) {
- if (errno == EINTR)
- continue;
-
- if (errno == EAGAIN && do_poll) {
- /* We knowingly ignore any return value here,
- * and expect that any error/EOF is reported
- * via write() */
-
- (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
- continue;
- }
-
- return -errno;
- }
-
- if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
- return -EIO;
-
- assert((size_t) k <= nbytes);
-
- p += k;
- nbytes -= k;
- } while (nbytes > 0);
-
- return 0;
-}
-
-int parse_size(const char *t, uint64_t base, uint64_t *size) {
-
- /* Soo, sometimes we want to parse IEC binary suffixes, and
- * sometimes SI decimal suffixes. This function can parse
- * both. Which one is the right way depends on the
- * context. Wikipedia suggests that SI is customary for
- * hardware metrics and network speeds, while IEC is
- * customary for most data sizes used by software and volatile
- * (RAM) memory. Hence be careful which one you pick!
- *
- * In either case we use just K, M, G as suffix, and not Ki,
- * Mi, Gi or so (as IEC would suggest). That's because that's
- * frickin' ugly. But this means you really need to make sure
- * to document which base you are parsing when you use this
- * call. */
-
- struct table {
- const char *suffix;
- unsigned long long factor;
- };
-
- static const struct table iec[] = {
- { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
- { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
- { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
- { "G", 1024ULL*1024ULL*1024ULL },
- { "M", 1024ULL*1024ULL },
- { "K", 1024ULL },
- { "B", 1ULL },
- { "", 1ULL },
- };
-
- static const struct table si[] = {
- { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
- { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
- { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
- { "G", 1000ULL*1000ULL*1000ULL },
- { "M", 1000ULL*1000ULL },
- { "K", 1000ULL },
- { "B", 1ULL },
- { "", 1ULL },
- };
-
- const struct table *table;
- const char *p;
- unsigned long long r = 0;
- unsigned n_entries, start_pos = 0;
-
- assert(t);
- assert(base == 1000 || base == 1024);
- assert(size);
-
- if (base == 1000) {
- table = si;
- n_entries = ELEMENTSOF(si);
- } else {
- table = iec;
- n_entries = ELEMENTSOF(iec);
- }
-
- p = t;
- do {
- unsigned long long l, tmp;
- double frac = 0;
- char *e;
- unsigned i;
-
- p += strspn(p, WHITESPACE);
- if (*p == '-')
- return -ERANGE;
-
- errno = 0;
- l = strtoull(p, &e, 10);
- if (errno > 0)
- return -errno;
- if (e == p)
- return -EINVAL;
-
- if (*e == '.') {
- e++;
-
- /* strtoull() itself would accept space/+/- */
- if (*e >= '0' && *e <= '9') {
- unsigned long long l2;
- char *e2;
-
- l2 = strtoull(e, &e2, 10);
- if (errno > 0)
- return -errno;
-
- /* Ignore failure. E.g. 10.M is valid */
- frac = l2;
- for (; e < e2; e++)
- frac /= 10;
- }
- }
-
- e += strspn(e, WHITESPACE);
-
- for (i = start_pos; i < n_entries; i++)
- if (startswith(e, table[i].suffix))
- break;
-
- if (i >= n_entries)
- return -EINVAL;
-
- if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
- return -ERANGE;
-
- tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
- if (tmp > ULLONG_MAX - r)
- return -ERANGE;
-
- r += tmp;
- if ((unsigned long long) (uint64_t) r != r)
- return -ERANGE;
-
- p = e + strlen(table[i].suffix);
-
- start_pos = i + 1;
-
- } while (*p);
-
- *size = r;
-
- return 0;
-}
-
-bool is_device_path(const char *path) {
-
- /* Returns true on paths that refer to a device, either in
- * sysfs or in /dev */
-
- return
- path_startswith(path, "/dev/") ||
- path_startswith(path, "/sys/");
-}
-
-int dir_is_empty(const char *path) {
- _cleanup_closedir_ DIR *d;
-
- d = opendir(path);
- if (!d)
- return -errno;
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- return 1;
-
- if (!hidden_file(de->d_name))
- return 0;
- }
-}
-
-char* dirname_malloc(const char *path) {
- char *d, *dir, *dir2;
-
- d = strdup(path);
- if (!d)
- return NULL;
- dir = dirname(d);
- assert(dir);
-
- if (dir != d) {
- dir2 = strdup(dir);
- free(d);
- return dir2;
- }
-
- return dir;
-}
-
-void rename_process(const char name[8]) {
- assert(name);
-
- /* This is a like a poor man's setproctitle(). It changes the
- * comm field, argv[0], and also the glibc's internally used
- * name of the process. For the first one a limit of 16 chars
- * applies, to the second one usually one of 10 (i.e. length
- * of "/sbin/init"), to the third one one of 7 (i.e. length of
- * "systemd"). If you pass a longer string it will be
- * truncated */
-
- prctl(PR_SET_NAME, name);
-
- if (program_invocation_name)
- strncpy(program_invocation_name, name, strlen(program_invocation_name));
-
- if (saved_argc > 0) {
- int i;
-
- if (saved_argv[0])
- strncpy(saved_argv[0], name, strlen(saved_argv[0]));
-
- for (i = 1; i < saved_argc; i++) {
- if (!saved_argv[i])
- break;
-
- memzero(saved_argv[i], strlen(saved_argv[i]));
- }
- }
-}
-
-char *lookup_uid(uid_t uid) {
- long bufsize;
- char *name;
- _cleanup_free_ char *buf = NULL;
- struct passwd pwbuf, *pw = NULL;
-
- /* Shortcut things to avoid NSS lookups */
- if (uid == 0)
- return strdup("root");
-
- bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (bufsize <= 0)
- bufsize = 4096;
-
- buf = malloc(bufsize);
- if (!buf)
- return NULL;
-
- if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw)
- return strdup(pw->pw_name);
-
- if (asprintf(&name, UID_FMT, uid) < 0)
- return NULL;
-
- return name;
-}
-
-char* getlogname_malloc(void) {
- uid_t uid;
- struct stat st;
-
- if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
- uid = st.st_uid;
- else
- uid = getuid();
-
- return lookup_uid(uid);
-}
-
-char *getusername_malloc(void) {
- const char *e;
-
- e = getenv("USER");
- if (e)
- return strdup(e);
-
- return lookup_uid(getuid());
-}
-
-bool is_temporary_fs(const struct statfs *s) {
- assert(s);
-
- return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
- F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
-}
-
-int fd_is_temporary_fs(int fd) {
- struct statfs s;
-
- if (fstatfs(fd, &s) < 0)
- return -errno;
-
- return is_temporary_fs(&s);
-}
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
- assert(path);
-
- /* Under the assumption that we are running privileged we
- * first change the access mode and only then hand out
- * ownership to avoid a window where access is too open. */
-
- if (mode != MODE_INVALID)
- if (chmod(path, mode) < 0)
- return -errno;
-
- if (uid != UID_INVALID || gid != GID_INVALID)
- if (chown(path, uid, gid) < 0)
- return -errno;
-
- return 0;
-}
-
-int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
- assert(fd >= 0);
-
- /* Under the assumption that we are running privileged we
- * first change the access mode and only then hand out
- * ownership to avoid a window where access is too open. */
-
- if (mode != MODE_INVALID)
- if (fchmod(fd, mode) < 0)
- return -errno;
-
- if (uid != UID_INVALID || gid != GID_INVALID)
- if (fchown(fd, uid, gid) < 0)
- return -errno;
-
- return 0;
-}
-
-cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
- cpu_set_t *r;
- unsigned n = 1024;
-
- /* Allocates the cpuset in the right size */
-
- for (;;) {
- if (!(r = CPU_ALLOC(n)))
- return NULL;
-
- if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
- CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
-
- if (ncpus)
- *ncpus = n;
-
- return r;
- }
-
- CPU_FREE(r);
-
- if (errno != EINVAL)
- return NULL;
-
- n *= 2;
- }
-}
-
-int parse_cpu_set(
- const char *rvalue,
- cpu_set_t **cpu_set,
- const char *unit,
- const char *filename,
- unsigned line,
- const char *lvalue) {
-
- const char *whole_rvalue = rvalue;
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
- unsigned ncpus = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- unsigned cpu;
- int r;
-
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Invalid value for %s: %s", lvalue, whole_rvalue);
- return r;
- }
- if (r == 0)
- break;
-
- r = safe_atou(word, &cpu);
-
- if (!c)
- if (!(c = cpu_set_malloc(&ncpus)))
- return log_oom();
-
- if (r < 0 || cpu >= ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU affinity '%s'", rvalue);
- return -EBADMSG;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
- }
- if (!isempty(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- /* On success, sets *cpu_set and returns ncpus for the system. */
- if (c) {
- *cpu_set = c;
- c = NULL;
- }
- return (int) ncpus;
-}
-
-int files_same(const char *filea, const char *fileb) {
- struct stat a, b;
-
- if (stat(filea, &a) < 0)
- return -errno;
-
- if (stat(fileb, &b) < 0)
- return -errno;
-
- return a.st_dev == b.st_dev &&
- a.st_ino == b.st_ino;
-}
-
-int running_in_chroot(void) {
- int ret;
-
- ret = files_same("/proc/1/root", "/");
- if (ret < 0)
- return ret;
-
- return ret == 0;
-}
-
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *r;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- r = new0(char, new_length+1);
- if (!r)
- return NULL;
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- memcpy(r, s, x);
- r[x] = '.';
- r[x+1] = '.';
- r[x+2] = '.';
- memcpy(r + x + 3,
- s + old_length - (new_length - x - 3),
- new_length - x - 3);
-
- return r;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *e;
- const char *i, *j;
- unsigned k, len, len2;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- /* if no multibyte characters use ascii_ellipsize_mem for speed */
- if (ascii_is_valid(s))
- return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- k = 0;
- for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
- int c;
-
- c = utf8_encoded_to_unichar(i);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
-
- if (k > x) /* last character was wide and went over quota */
- x ++;
-
- for (j = s + old_length; k < new_length && j > i; ) {
- int c;
-
- j = utf8_prev_char(j);
- c = utf8_encoded_to_unichar(j);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
- assert(i <= j);
-
- /* we don't actually need to ellipsize */
- if (i == j)
- return memdup(s, old_length + 1);
-
- /* make space for ellipsis */
- j = utf8_next_char(j);
-
- len = i - s;
- len2 = s + old_length - j;
- e = new(char, len + 3 + len2 + 1);
- if (!e)
- return NULL;
-
- /*
- printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
- old_length, new_length, x, len, len2, k);
- */
-
- memcpy(e, s, len);
- e[len] = 0xe2; /* tri-dot ellipsis: … */
- e[len + 1] = 0x80;
- e[len + 2] = 0xa6;
-
- memcpy(e + len + 3, j, len2 + 1);
-
- return e;
-}
-
-char *ellipsize(const char *s, size_t length, unsigned percent) {
- return ellipsize_mem(s, strlen(s), length, percent);
-}
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
- _cleanup_close_ int fd;
- int r;
-
- assert(path);
-
- if (parents)
- mkdir_parents(path, 0755);
-
- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
- if (fd < 0)
- return -errno;
-
- if (mode > 0) {
- r = fchmod(fd, mode);
- if (r < 0)
- return -errno;
- }
-
- if (uid != UID_INVALID || gid != GID_INVALID) {
- r = fchown(fd, uid, gid);
- if (r < 0)
- return -errno;
- }
-
- if (stamp != USEC_INFINITY) {
- struct timespec ts[2];
-
- timespec_store(&ts[0], stamp);
- ts[1] = ts[0];
- r = futimens(fd, ts);
- } else
- r = futimens(fd, NULL);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int touch(const char *path) {
- return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
-}
-
-static char *unquote(const char *s, const char* quotes) {
- size_t l;
- assert(s);
-
- /* This is rather stupid, simply removes the heading and
- * trailing quotes if there is one. Doesn't care about
- * escaping or anything.
- *
- * DON'T USE THIS FOR NEW CODE ANYMORE!*/
-
- l = strlen(s);
- if (l < 2)
- return strdup(s);
-
- if (strchr(quotes, s[0]) && s[l-1] == s[0])
- return strndup(s+1, l-2);
-
- return strdup(s);
-}
-
-noreturn void freeze(void) {
-
- /* Make sure nobody waits for us on a socket anymore */
- close_all_fds(NULL, 0);
-
- sync();
-
- for (;;)
- pause();
-}
-
-bool null_or_empty(struct stat *st) {
- assert(st);
-
- if (S_ISREG(st->st_mode) && st->st_size <= 0)
- return true;
-
- if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
- return true;
-
- return false;
-}
-
-int null_or_empty_path(const char *fn) {
- struct stat st;
-
- assert(fn);
-
- if (stat(fn, &st) < 0)
- return -errno;
-
- return null_or_empty(&st);
-}
-
-int null_or_empty_fd(int fd) {
- struct stat st;
-
- assert(fd >= 0);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- return null_or_empty(&st);
-}
-
-DIR *xopendirat(int fd, const char *name, int flags) {
- int nfd;
- DIR *d;
-
- assert(!(flags & O_CREAT));
-
- nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0);
- if (nfd < 0)
- return NULL;
-
- d = fdopendir(nfd);
- if (!d) {
- safe_close(nfd);
- return NULL;
- }
-
- return d;
-}
-
-static char *tag_to_udev_node(const char *tagvalue, const char *by) {
- _cleanup_free_ char *t = NULL, *u = NULL;
- size_t enc_len;
-
- u = unquote(tagvalue, QUOTES);
- if (!u)
- return NULL;
-
- enc_len = strlen(u) * 4 + 1;
- t = new(char, enc_len);
- if (!t)
- return NULL;
-
- if (encode_devnode_name(u, t, enc_len) < 0)
- return NULL;
-
- return strjoin("/dev/disk/by-", by, "/", t, NULL);
-}
-
-char *fstab_node_to_udev_node(const char *p) {
- assert(p);
-
- if (startswith(p, "LABEL="))
- return tag_to_udev_node(p+6, "label");
-
- if (startswith(p, "UUID="))
- return tag_to_udev_node(p+5, "uuid");
-
- if (startswith(p, "PARTUUID="))
- return tag_to_udev_node(p+9, "partuuid");
-
- if (startswith(p, "PARTLABEL="))
- return tag_to_udev_node(p+10, "partlabel");
-
- return strdup(p);
-}
-
-bool dirent_is_file(const struct dirent *de) {
- assert(de);
-
- if (hidden_file(de->d_name))
- return false;
-
- if (de->d_type != DT_REG &&
- de->d_type != DT_LNK &&
- de->d_type != DT_UNKNOWN)
- return false;
-
- return true;
-}
-
-bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
- assert(de);
-
- if (de->d_type != DT_REG &&
- de->d_type != DT_LNK &&
- de->d_type != DT_UNKNOWN)
- return false;
-
- if (hidden_file_allow_backup(de->d_name))
- return false;
-
- return endswith(de->d_name, suffix);
-}
-
static int do_execute(char **directories, usec_t timeout, char *argv[]) {
_cleanup_hashmap_free_free_ Hashmap *pids = NULL;
_cleanup_set_free_free_ Set *seen = NULL;
@@ -3098,189 +265,10 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
wait_for_terminate_and_warn(name, executor_pid, true);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
- const char *i;
-
- if (!nulstr)
- return false;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return true;
-
- return false;
-}
-
bool plymouth_running(void) {
return access("/run/plymouth/pid", F_OK) >= 0;
}
-char* strshorten(char *s, size_t l) {
- assert(s);
-
- if (l < strlen(s))
- s[l] = 0;
-
- return s;
-}
-
-int pipe_eof(int fd) {
- struct pollfd pollfd = {
- .fd = fd,
- .events = POLLIN|POLLHUP,
- };
-
- int r;
-
- r = poll(&pollfd, 1, 0);
- if (r < 0)
- return -errno;
-
- if (r == 0)
- return 0;
-
- return pollfd.revents & POLLHUP;
-}
-
-int fd_wait_for_event(int fd, int event, usec_t t) {
-
- struct pollfd pollfd = {
- .fd = fd,
- .events = event,
- };
-
- struct timespec ts;
- int r;
-
- r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
- if (r < 0)
- return -errno;
-
- if (r == 0)
- return 0;
-
- return pollfd.revents;
-}
-
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
- FILE *f;
- char *t;
- int r, fd;
-
- assert(path);
- assert(_f);
- assert(_temp_path);
-
- r = tempfn_xxxxxx(path, NULL, &t);
- if (r < 0)
- return r;
-
- fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
- if (fd < 0) {
- free(t);
- return -errno;
- }
-
- f = fdopen(fd, "we");
- if (!f) {
- unlink_noerrno(t);
- free(t);
- safe_close(fd);
- return -errno;
- }
-
- *_f = f;
- *_temp_path = t;
-
- return 0;
-}
-
-int symlink_atomic(const char *from, const char *to) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(from);
- assert(to);
-
- r = tempfn_random(to, NULL, &t);
- if (r < 0)
- return r;
-
- if (symlink(from, t) < 0)
- return -errno;
-
- if (rename(t, to) < 0) {
- unlink_noerrno(t);
- return -errno;
- }
-
- return 0;
-}
-
-int symlink_idempotent(const char *from, const char *to) {
- _cleanup_free_ char *p = NULL;
- int r;
-
- assert(from);
- assert(to);
-
- if (symlink(from, to) < 0) {
- if (errno != EEXIST)
- return -errno;
-
- r = readlink_malloc(to, &p);
- if (r < 0)
- return r;
-
- if (!streq(p, from))
- return -EINVAL;
- }
-
- return 0;
-}
-
-int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(path);
-
- r = tempfn_random(path, NULL, &t);
- if (r < 0)
- return r;
-
- if (mknod(t, mode, dev) < 0)
- return -errno;
-
- if (rename(t, path) < 0) {
- unlink_noerrno(t);
- return -errno;
- }
-
- return 0;
-}
-
-int mkfifo_atomic(const char *path, mode_t mode) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(path);
-
- r = tempfn_random(path, NULL, &t);
- if (r < 0)
- return r;
-
- if (mkfifo(t, mode) < 0)
- return -errno;
-
- if (rename(t, path) < 0) {
- unlink_noerrno(t);
- return -errno;
- }
-
- return 0;
-}
-
bool display_is_local(const char *display) {
assert(display);
@@ -3315,368 +303,6 @@ int socket_from_display(const char *display, char **path) {
return 0;
}
-int get_user_creds(
- const char **username,
- uid_t *uid, gid_t *gid,
- const char **home,
- const char **shell) {
-
- struct passwd *p;
- uid_t u;
-
- assert(username);
- assert(*username);
-
- /* We enforce some special rules for uid=0: in order to avoid
- * NSS lookups for root we hardcode its data. */
-
- if (streq(*username, "root") || streq(*username, "0")) {
- *username = "root";
-
- if (uid)
- *uid = 0;
-
- if (gid)
- *gid = 0;
-
- if (home)
- *home = "/root";
-
- if (shell)
- *shell = "/bin/sh";
-
- return 0;
- }
-
- if (parse_uid(*username, &u) >= 0) {
- errno = 0;
- p = getpwuid(u);
-
- /* If there are multiple users with the same id, make
- * sure to leave $USER to the configured value instead
- * of the first occurrence in the database. However if
- * the uid was configured by a numeric uid, then let's
- * pick the real username from /etc/passwd. */
- if (p)
- *username = p->pw_name;
- } else {
- errno = 0;
- p = getpwnam(*username);
- }
-
- if (!p)
- return errno > 0 ? -errno : -ESRCH;
-
- if (uid)
- *uid = p->pw_uid;
-
- if (gid)
- *gid = p->pw_gid;
-
- if (home)
- *home = p->pw_dir;
-
- if (shell)
- *shell = p->pw_shell;
-
- return 0;
-}
-
-char* uid_to_name(uid_t uid) {
- struct passwd *p;
- char *r;
-
- if (uid == 0)
- return strdup("root");
-
- p = getpwuid(uid);
- if (p)
- return strdup(p->pw_name);
-
- if (asprintf(&r, UID_FMT, uid) < 0)
- return NULL;
-
- return r;
-}
-
-char* gid_to_name(gid_t gid) {
- struct group *p;
- char *r;
-
- if (gid == 0)
- return strdup("root");
-
- p = getgrgid(gid);
- if (p)
- return strdup(p->gr_name);
-
- if (asprintf(&r, GID_FMT, gid) < 0)
- return NULL;
-
- return r;
-}
-
-int get_group_creds(const char **groupname, gid_t *gid) {
- struct group *g;
- gid_t id;
-
- assert(groupname);
-
- /* We enforce some special rules for gid=0: in order to avoid
- * NSS lookups for root we hardcode its data. */
-
- if (streq(*groupname, "root") || streq(*groupname, "0")) {
- *groupname = "root";
-
- if (gid)
- *gid = 0;
-
- return 0;
- }
-
- if (parse_gid(*groupname, &id) >= 0) {
- errno = 0;
- g = getgrgid(id);
-
- if (g)
- *groupname = g->gr_name;
- } else {
- errno = 0;
- g = getgrnam(*groupname);
- }
-
- if (!g)
- return errno > 0 ? -errno : -ESRCH;
-
- if (gid)
- *gid = g->gr_gid;
-
- return 0;
-}
-
-int in_gid(gid_t gid) {
- gid_t *gids;
- int ngroups_max, r, i;
-
- if (getgid() == gid)
- return 1;
-
- if (getegid() == gid)
- return 1;
-
- ngroups_max = sysconf(_SC_NGROUPS_MAX);
- assert(ngroups_max > 0);
-
- gids = alloca(sizeof(gid_t) * ngroups_max);
-
- r = getgroups(ngroups_max, gids);
- if (r < 0)
- return -errno;
-
- for (i = 0; i < r; i++)
- if (gids[i] == gid)
- return 1;
-
- return 0;
-}
-
-int in_group(const char *name) {
- int r;
- gid_t gid;
-
- r = get_group_creds(&name, &gid);
- if (r < 0)
- return r;
-
- return in_gid(gid);
-}
-
-int glob_exists(const char *path) {
- _cleanup_globfree_ glob_t g = {};
- int k;
-
- assert(path);
-
- errno = 0;
- k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
-
- if (k == GLOB_NOMATCH)
- return 0;
- else if (k == GLOB_NOSPACE)
- return -ENOMEM;
- else if (k == 0)
- return !strv_isempty(g.gl_pathv);
- else
- return errno ? -errno : -EIO;
-}
-
-int glob_extend(char ***strv, const char *path) {
- _cleanup_globfree_ glob_t g = {};
- int k;
- char **p;
-
- errno = 0;
- k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
-
- if (k == GLOB_NOMATCH)
- return -ENOENT;
- else if (k == GLOB_NOSPACE)
- return -ENOMEM;
- else if (k != 0 || strv_isempty(g.gl_pathv))
- return errno ? -errno : -EIO;
-
- STRV_FOREACH(p, g.gl_pathv) {
- k = strv_extend(strv, *p);
- if (k < 0)
- break;
- }
-
- return k;
-}
-
-int dirent_ensure_type(DIR *d, struct dirent *de) {
- struct stat st;
-
- assert(d);
- assert(de);
-
- if (de->d_type != DT_UNKNOWN)
- return 0;
-
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
- return -errno;
-
- de->d_type =
- S_ISREG(st.st_mode) ? DT_REG :
- S_ISDIR(st.st_mode) ? DT_DIR :
- S_ISLNK(st.st_mode) ? DT_LNK :
- S_ISFIFO(st.st_mode) ? DT_FIFO :
- S_ISSOCK(st.st_mode) ? DT_SOCK :
- S_ISCHR(st.st_mode) ? DT_CHR :
- S_ISBLK(st.st_mode) ? DT_BLK :
- DT_UNKNOWN;
-
- return 0;
-}
-
-int get_files_in_directory(const char *path, char ***list) {
- _cleanup_closedir_ DIR *d = NULL;
- size_t bufsize = 0, n = 0;
- _cleanup_strv_free_ char **l = NULL;
-
- assert(path);
-
- /* Returns all files in a directory in *list, and the number
- * of files as return value. If list is NULL returns only the
- * number. */
-
- d = opendir(path);
- if (!d)
- return -errno;
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
- if (!de)
- break;
-
- dirent_ensure_type(d, de);
-
- if (!dirent_is_file(de))
- continue;
-
- if (list) {
- /* one extra slot is needed for the terminating NULL */
- if (!GREEDY_REALLOC(l, bufsize, n + 2))
- return -ENOMEM;
-
- l[n] = strdup(de->d_name);
- if (!l[n])
- return -ENOMEM;
-
- l[++n] = NULL;
- } else
- n++;
- }
-
- if (list) {
- *list = l;
- l = NULL; /* avoid freeing */
- }
-
- return n;
-}
-
-char *strjoin(const char *x, ...) {
- va_list ap;
- size_t l;
- char *r, *p;
-
- va_start(ap, x);
-
- if (x) {
- l = strlen(x);
-
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- } else
- l = 0;
-
- va_end(ap);
-
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- if (x) {
- p = stpcpy(r, x);
-
- va_start(ap, x);
-
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
-
- va_end(ap);
- } else
- r[0] = 0;
-
- return r;
-}
-
-bool is_main_thread(void) {
- static thread_local int cached = 0;
-
- if (_unlikely_(cached == 0))
- cached = getpid() == gettid() ? 1 : -1;
-
- return cached > 0;
-}
-
int block_get_whole_disk(dev_t d, dev_t *ret) {
char *p, *s;
int r;
@@ -3737,104 +363,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
return -ENOENT;
}
-static const char *const ioprio_class_table[] = {
- [IOPRIO_CLASS_NONE] = "none",
- [IOPRIO_CLASS_RT] = "realtime",
- [IOPRIO_CLASS_BE] = "best-effort",
- [IOPRIO_CLASS_IDLE] = "idle"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
-
-static const char *const sigchld_code_table[] = {
- [CLD_EXITED] = "exited",
- [CLD_KILLED] = "killed",
- [CLD_DUMPED] = "dumped",
- [CLD_TRAPPED] = "trapped",
- [CLD_STOPPED] = "stopped",
- [CLD_CONTINUED] = "continued",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-
-static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
- [LOG_FAC(LOG_KERN)] = "kern",
- [LOG_FAC(LOG_USER)] = "user",
- [LOG_FAC(LOG_MAIL)] = "mail",
- [LOG_FAC(LOG_DAEMON)] = "daemon",
- [LOG_FAC(LOG_AUTH)] = "auth",
- [LOG_FAC(LOG_SYSLOG)] = "syslog",
- [LOG_FAC(LOG_LPR)] = "lpr",
- [LOG_FAC(LOG_NEWS)] = "news",
- [LOG_FAC(LOG_UUCP)] = "uucp",
- [LOG_FAC(LOG_CRON)] = "cron",
- [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
- [LOG_FAC(LOG_FTP)] = "ftp",
- [LOG_FAC(LOG_LOCAL0)] = "local0",
- [LOG_FAC(LOG_LOCAL1)] = "local1",
- [LOG_FAC(LOG_LOCAL2)] = "local2",
- [LOG_FAC(LOG_LOCAL3)] = "local3",
- [LOG_FAC(LOG_LOCAL4)] = "local4",
- [LOG_FAC(LOG_LOCAL5)] = "local5",
- [LOG_FAC(LOG_LOCAL6)] = "local6",
- [LOG_FAC(LOG_LOCAL7)] = "local7"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
-
-static const char *const log_level_table[] = {
- [LOG_EMERG] = "emerg",
- [LOG_ALERT] = "alert",
- [LOG_CRIT] = "crit",
- [LOG_ERR] = "err",
- [LOG_WARNING] = "warning",
- [LOG_NOTICE] = "notice",
- [LOG_INFO] = "info",
- [LOG_DEBUG] = "debug"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
-
-static const char* const sched_policy_table[] = {
- [SCHED_OTHER] = "other",
- [SCHED_BATCH] = "batch",
- [SCHED_IDLE] = "idle",
- [SCHED_FIFO] = "fifo",
- [SCHED_RR] = "rr"
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
-
-static const char* const rlimit_table[_RLIMIT_MAX] = {
- [RLIMIT_CPU] = "LimitCPU",
- [RLIMIT_FSIZE] = "LimitFSIZE",
- [RLIMIT_DATA] = "LimitDATA",
- [RLIMIT_STACK] = "LimitSTACK",
- [RLIMIT_CORE] = "LimitCORE",
- [RLIMIT_RSS] = "LimitRSS",
- [RLIMIT_NOFILE] = "LimitNOFILE",
- [RLIMIT_AS] = "LimitAS",
- [RLIMIT_NPROC] = "LimitNPROC",
- [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
- [RLIMIT_LOCKS] = "LimitLOCKS",
- [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
- [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
- [RLIMIT_NICE] = "LimitNICE",
- [RLIMIT_RTPRIO] = "LimitRTPRIO",
- [RLIMIT_RTTIME] = "LimitRTTIME"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(rlimit, int);
-
-static const char* const ip_tos_table[] = {
- [IPTOS_LOWDELAY] = "low-delay",
- [IPTOS_THROUGHPUT] = "throughput",
- [IPTOS_RELIABILITY] = "reliability",
- [IPTOS_LOWCOST] = "low-cost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-
bool kexec_loaded(void) {
bool loaded = false;
char *s;
@@ -3865,93 +393,6 @@ int prot_from_flags(int flags) {
}
}
-char *format_bytes(char *buf, size_t l, uint64_t t) {
- unsigned i;
-
- static const struct {
- const char *suffix;
- uint64_t factor;
- } table[] = {
- { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
- { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
- { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
- { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
- { "M", UINT64_C(1024)*UINT64_C(1024) },
- { "K", UINT64_C(1024) },
- };
-
- if (t == (uint64_t) -1)
- return NULL;
-
- for (i = 0; i < ELEMENTSOF(table); i++) {
-
- if (t >= table[i].factor) {
- snprintf(buf, l,
- "%" PRIu64 ".%" PRIu64 "%s",
- t / table[i].factor,
- ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
- table[i].suffix);
-
- goto finish;
- }
- }
-
- snprintf(buf, l, "%" PRIu64 "B", t);
-
-finish:
- buf[l-1] = 0;
- return buf;
-
-}
-
-void* memdup(const void *p, size_t l) {
- void *r;
-
- assert(p);
-
- r = malloc(l);
- if (!r)
- return NULL;
-
- memcpy(r, p, l);
- return r;
-}
-
-int fd_inc_sndbuf(int fd, size_t n) {
- int r, value;
- socklen_t l = sizeof(value);
-
- r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
- if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
- return 0;
-
- /* If we have the privileges we will ignore the kernel limit. */
-
- value = (int) n;
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
- return -errno;
-
- return 1;
-}
-
-int fd_inc_rcvbuf(int fd, size_t n) {
- int r, value;
- socklen_t l = sizeof(value);
-
- r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
- if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
- return 0;
-
- /* If we have the privileges we will ignore the kernel limit. */
-
- value = (int) n;
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
- return -errno;
- return 1;
-}
-
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
bool stdout_is_tty, stderr_is_tty;
pid_t parent_pid, agent_pid;
@@ -4054,82 +495,6 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
_exit(EXIT_FAILURE);
}
-int setrlimit_closest(int resource, const struct rlimit *rlim) {
- struct rlimit highest, fixed;
-
- assert(rlim);
-
- if (setrlimit(resource, rlim) >= 0)
- return 0;
-
- if (errno != EPERM)
- return -errno;
-
- /* So we failed to set the desired setrlimit, then let's try
- * to get as close as we can */
- assert_se(getrlimit(resource, &highest) == 0);
-
- fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max);
- fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max);
-
- if (setrlimit(resource, &fixed) < 0)
- return -errno;
-
- return 0;
-}
-
-bool http_etag_is_valid(const char *etag) {
- if (isempty(etag))
- return false;
-
- if (!endswith(etag, "\""))
- return false;
-
- if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
- return false;
-
- return true;
-}
-
-bool http_url_is_valid(const char *url) {
- const char *p;
-
- if (isempty(url))
- return false;
-
- p = startswith(url, "http://");
- if (!p)
- p = startswith(url, "https://");
- if (!p)
- return false;
-
- if (isempty(p))
- return false;
-
- return ascii_is_valid(p);
-}
-
-bool documentation_url_is_valid(const char *url) {
- const char *p;
-
- if (isempty(url))
- return false;
-
- if (http_url_is_valid(url))
- return true;
-
- p = startswith(url, "file:/");
- if (!p)
- p = startswith(url, "info:");
- if (!p)
- p = startswith(url, "man:");
-
- if (isempty(p))
- return false;
-
- return ascii_is_valid(p);
-}
-
bool in_initrd(void) {
static int saved = -1;
struct statfs s;
@@ -4154,181 +519,6 @@ bool in_initrd(void) {
return saved;
}
-int get_home_dir(char **_h) {
- struct passwd *p;
- const char *e;
- char *h;
- uid_t u;
-
- assert(_h);
-
- /* Take the user specified one */
- e = secure_getenv("HOME");
- if (e && path_is_absolute(e)) {
- h = strdup(e);
- if (!h)
- return -ENOMEM;
-
- *_h = h;
- return 0;
- }
-
- /* Hardcode home directory for root to avoid NSS */
- u = getuid();
- if (u == 0) {
- h = strdup("/root");
- if (!h)
- return -ENOMEM;
-
- *_h = h;
- return 0;
- }
-
- /* Check the database... */
- errno = 0;
- p = getpwuid(u);
- if (!p)
- return errno > 0 ? -errno : -ESRCH;
-
- if (!path_is_absolute(p->pw_dir))
- return -EINVAL;
-
- h = strdup(p->pw_dir);
- if (!h)
- return -ENOMEM;
-
- *_h = h;
- return 0;
-}
-
-int get_shell(char **_s) {
- struct passwd *p;
- const char *e;
- char *s;
- uid_t u;
-
- assert(_s);
-
- /* Take the user specified one */
- e = getenv("SHELL");
- if (e) {
- s = strdup(e);
- if (!s)
- return -ENOMEM;
-
- *_s = s;
- return 0;
- }
-
- /* Hardcode home directory for root to avoid NSS */
- u = getuid();
- if (u == 0) {
- s = strdup("/bin/sh");
- if (!s)
- return -ENOMEM;
-
- *_s = s;
- return 0;
- }
-
- /* Check the database... */
- errno = 0;
- p = getpwuid(u);
- if (!p)
- return errno > 0 ? -errno : -ESRCH;
-
- if (!path_is_absolute(p->pw_shell))
- return -EINVAL;
-
- s = strdup(p->pw_shell);
- if (!s)
- return -ENOMEM;
-
- *_s = s;
- return 0;
-}
-
-bool filename_is_valid(const char *p) {
-
- if (isempty(p))
- return false;
-
- if (strchr(p, '/'))
- return false;
-
- if (streq(p, "."))
- return false;
-
- if (streq(p, ".."))
- return false;
-
- if (strlen(p) > FILENAME_MAX)
- return false;
-
- return true;
-}
-
-bool string_is_safe(const char *p) {
- const char *t;
-
- if (!p)
- return false;
-
- for (t = p; *t; t++) {
- if (*t > 0 && *t < ' ')
- return false;
-
- if (strchr("\\\"\'\x7f", *t))
- return false;
- }
-
- return true;
-}
-
-/**
- * Check if a string contains control characters. If 'ok' is non-NULL
- * it may be a string containing additional CCs to be considered OK.
- */
-bool string_has_cc(const char *p, const char *ok) {
- const char *t;
-
- assert(p);
-
- for (t = p; *t; t++) {
- if (ok && strchr(ok, *t))
- continue;
-
- if (*t > 0 && *t < ' ')
- return true;
-
- if (*t == 127)
- return true;
- }
-
- return false;
-}
-
-bool path_is_safe(const char *p) {
-
- if (isempty(p))
- return false;
-
- if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
- return false;
-
- if (strlen(p)+1 > PATH_MAX)
- return false;
-
- /* The following two checks are not really dangerous, but hey, they still are confusing */
- if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
- return false;
-
- if (strstr(p, "//"))
- return false;
-
- return true;
-}
-
/* hey glibc, APIs with callbacks without a user pointer are so useless */
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *), void *arg) {
@@ -4352,216 +542,6 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
return NULL;
}
-void init_gettext(void) {
- setlocale(LC_ALL, "");
- textdomain(GETTEXT_PACKAGE);
-}
-
-bool is_locale_utf8(void) {
- const char *set;
- static int cached_answer = -1;
-
- if (cached_answer >= 0)
- goto out;
-
- if (!setlocale(LC_ALL, "")) {
- cached_answer = true;
- goto out;
- }
-
- set = nl_langinfo(CODESET);
- if (!set) {
- cached_answer = true;
- goto out;
- }
-
- if (streq(set, "UTF-8")) {
- cached_answer = true;
- goto out;
- }
-
- /* For LC_CTYPE=="C" return true, because CTYPE is effectly
- * unset and everything can do to UTF-8 nowadays. */
- set = setlocale(LC_CTYPE, NULL);
- if (!set) {
- cached_answer = true;
- goto out;
- }
-
- /* Check result, but ignore the result if C was set
- * explicitly. */
- cached_answer =
- STR_IN_SET(set, "C", "POSIX") &&
- !getenv("LC_ALL") &&
- !getenv("LC_CTYPE") &&
- !getenv("LANG");
-
-out:
- return (bool) cached_answer;
-}
-
-const char *draw_special_char(DrawSpecialChar ch) {
- static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
-
- /* UTF-8 */ {
- [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
- [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
- [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
- [DRAW_TREE_SPACE] = " ", /* */
- [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
- [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
- [DRAW_ARROW] = "\342\206\222", /* → */
- [DRAW_DASH] = "\342\200\223", /* – */
- },
-
- /* ASCII fallback */ {
- [DRAW_TREE_VERTICAL] = "| ",
- [DRAW_TREE_BRANCH] = "|-",
- [DRAW_TREE_RIGHT] = "`-",
- [DRAW_TREE_SPACE] = " ",
- [DRAW_TRIANGULAR_BULLET] = ">",
- [DRAW_BLACK_CIRCLE] = "*",
- [DRAW_ARROW] = "->",
- [DRAW_DASH] = "-",
- }
- };
-
- return draw_table[!is_locale_utf8()][ch];
-}
-
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
- const char *f;
- char *t, *r;
- size_t l, old_len, new_len;
-
- assert(text);
- assert(old_string);
- assert(new_string);
-
- old_len = strlen(old_string);
- new_len = strlen(new_string);
-
- l = strlen(text);
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- f = text;
- t = r;
- while (*f) {
- char *a;
- size_t d, nl;
-
- if (!startswith(f, old_string)) {
- *(t++) = *(f++);
- continue;
- }
-
- d = t - r;
- nl = l - old_len + new_len;
- a = realloc(r, nl + 1);
- if (!a)
- goto oom;
-
- l = nl;
- r = a;
- t = r + d;
-
- t = stpcpy(t, new_string);
- f += old_len;
- }
-
- *t = 0;
- return r;
-
-oom:
- free(r);
- return NULL;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
- const char *i, *begin = NULL;
- enum {
- STATE_OTHER,
- STATE_ESCAPE,
- STATE_BRACKET
- } state = STATE_OTHER;
- char *obuf = NULL;
- size_t osz = 0, isz;
- FILE *f;
-
- assert(ibuf);
- assert(*ibuf);
-
- /* Strips ANSI color and replaces TABs by 8 spaces */
-
- isz = _isz ? *_isz : strlen(*ibuf);
-
- f = open_memstream(&obuf, &osz);
- if (!f)
- return NULL;
-
- for (i = *ibuf; i < *ibuf + isz + 1; i++) {
-
- switch (state) {
-
- case STATE_OTHER:
- if (i >= *ibuf + isz) /* EOT */
- break;
- else if (*i == '\x1B')
- state = STATE_ESCAPE;
- else if (*i == '\t')
- fputs(" ", f);
- else
- fputc(*i, f);
- break;
-
- case STATE_ESCAPE:
- if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
- break;
- } else if (*i == '[') {
- state = STATE_BRACKET;
- begin = i + 1;
- } else {
- fputc('\x1B', f);
- fputc(*i, f);
- state = STATE_OTHER;
- }
-
- break;
-
- case STATE_BRACKET:
-
- if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
- state = STATE_OTHER;
- i = begin-1;
- } else if (*i == 'm')
- state = STATE_OTHER;
- break;
- }
- }
-
- if (ferror(f)) {
- fclose(f);
- free(obuf);
- return NULL;
- }
-
- fclose(f);
-
- free(*ibuf);
- *ibuf = obuf;
-
- if (_isz)
- *_isz = osz;
-
- return obuf;
-}
-
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
@@ -4638,204 +618,6 @@ int on_ac_power(void) {
return found_online || !found_offline;
}
-static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
- char **i;
-
- assert(path);
- assert(mode);
- assert(_f);
-
- if (!path_strv_resolve_uniq(search, root))
- return -ENOMEM;
-
- STRV_FOREACH(i, search) {
- _cleanup_free_ char *p = NULL;
- FILE *f;
-
- if (root)
- p = strjoin(root, *i, "/", path, NULL);
- else
- p = strjoin(*i, "/", path, NULL);
- if (!p)
- return -ENOMEM;
-
- f = fopen(p, mode);
- if (f) {
- *_f = f;
- return 0;
- }
-
- if (errno != ENOENT)
- return -errno;
- }
-
- return -ENOENT;
-}
-
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
- _cleanup_strv_free_ char **copy = NULL;
-
- assert(path);
- assert(mode);
- assert(_f);
-
- if (path_is_absolute(path)) {
- FILE *f;
-
- f = fopen(path, mode);
- if (f) {
- *_f = f;
- return 0;
- }
-
- return -errno;
- }
-
- copy = strv_copy((char**) search);
- if (!copy)
- return -ENOMEM;
-
- return search_and_fopen_internal(path, mode, root, copy, _f);
-}
-
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
- _cleanup_strv_free_ char **s = NULL;
-
- if (path_is_absolute(path)) {
- FILE *f;
-
- f = fopen(path, mode);
- if (f) {
- *_f = f;
- return 0;
- }
-
- return -errno;
- }
-
- s = strv_split_nulstr(search);
- if (!s)
- return -ENOMEM;
-
- return search_and_fopen_internal(path, mode, root, s, _f);
-}
-
-char *strextend(char **x, ...) {
- va_list ap;
- size_t f, l;
- char *r, *p;
-
- assert(x);
-
- l = f = *x ? strlen(*x) : 0;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- va_end(ap);
-
- r = realloc(*x, l+1);
- if (!r)
- return NULL;
-
- p = r + f;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
- va_end(ap);
-
- *p = 0;
- *x = r;
-
- return r + l;
-}
-
-char *strrep(const char *s, unsigned n) {
- size_t l;
- char *r, *p;
- unsigned i;
-
- assert(s);
-
- l = strlen(s);
- p = r = malloc(l * n + 1);
- if (!r)
- return NULL;
-
- for (i = 0; i < n; i++)
- p = stpcpy(p, s);
-
- *p = 0;
- return r;
-}
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
- size_t a, newalloc;
- void *q;
-
- assert(p);
- assert(allocated);
-
- if (*allocated >= need)
- return *p;
-
- newalloc = MAX(need * 2, 64u / size);
- a = newalloc * size;
-
- /* check for overflows */
- if (a < size * need)
- return NULL;
-
- q = realloc(*p, a);
- if (!q)
- return NULL;
-
- *p = q;
- *allocated = newalloc;
- return q;
-}
-
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
- size_t prev;
- uint8_t *q;
-
- assert(p);
- assert(allocated);
-
- prev = *allocated;
-
- q = greedy_realloc(p, allocated, need, size);
- if (!q)
- return NULL;
-
- if (*allocated > prev)
- memzero(q + prev * size, (*allocated - prev) * size);
-
- return q;
-}
-
bool id128_is_valid(const char *s) {
size_t i, l;
@@ -4877,151 +659,6 @@ bool id128_is_valid(const char *s) {
return true;
}
-int split_pair(const char *s, const char *sep, char **l, char **r) {
- char *x, *a, *b;
-
- assert(s);
- assert(sep);
- assert(l);
- assert(r);
-
- if (isempty(sep))
- return -EINVAL;
-
- x = strstr(s, sep);
- if (!x)
- return -EINVAL;
-
- a = strndup(s, x - s);
- if (!a)
- return -ENOMEM;
-
- b = strdup(x + strlen(sep));
- if (!b) {
- free(a);
- return -ENOMEM;
- }
-
- *l = a;
- *r = b;
-
- return 0;
-}
-
-int shall_restore_state(void) {
- _cleanup_free_ char *value = NULL;
- int r;
-
- r = get_proc_cmdline_key("systemd.restore_state=", &value);
- if (r < 0)
- return r;
- if (r == 0)
- return true;
-
- return parse_boolean(value) != 0;
-}
-
-int proc_cmdline(char **ret) {
- assert(ret);
-
- if (detect_container() > 0)
- return get_process_cmdline(1, 0, false, ret);
- else
- return read_one_line_file("/proc/cmdline", ret);
-}
-
-int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
- _cleanup_free_ char *line = NULL;
- const char *p;
- int r;
-
- assert(parse_item);
-
- r = proc_cmdline(&line);
- if (r < 0)
- return r;
-
- p = line;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- char *value = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- /* Filter out arguments that are intended only for the
- * initrd */
- if (!in_initrd() && startswith(word, "rd."))
- continue;
-
- value = strchr(word, '=');
- if (value)
- *(value++) = 0;
-
- r = parse_item(word, value);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int get_proc_cmdline_key(const char *key, char **value) {
- _cleanup_free_ char *line = NULL, *ret = NULL;
- bool found = false;
- const char *p;
- int r;
-
- assert(key);
-
- r = proc_cmdline(&line);
- if (r < 0)
- return r;
-
- p = line;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- const char *e;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
- if (r < 0)
- return r;
- if (r == 0)
- break;
-
- /* Filter out arguments that are intended only for the
- * initrd */
- if (!in_initrd() && startswith(word, "rd."))
- continue;
-
- if (value) {
- e = startswith(word, key);
- if (!e)
- continue;
-
- r = free_and_strdup(&ret, e);
- if (r < 0)
- return r;
-
- found = true;
- } else {
- if (streq(word, key))
- found = true;
- }
- }
-
- if (value) {
- *value = ret;
- ret = NULL;
- }
-
- return found;
-
-}
-
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
@@ -5171,203 +808,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
return reset_uid_gid();
}
-int getpeercred(int fd, struct ucred *ucred) {
- socklen_t n = sizeof(struct ucred);
- struct ucred u;
- int r;
-
- assert(fd >= 0);
- assert(ucred);
-
- r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
- if (r < 0)
- return -errno;
-
- if (n != sizeof(struct ucred))
- return -EIO;
-
- /* Check if the data is actually useful and not suppressed due
- * to namespacing issues */
- if (u.pid <= 0)
- return -ENODATA;
- if (u.uid == UID_INVALID)
- return -ENODATA;
- if (u.gid == GID_INVALID)
- return -ENODATA;
-
- *ucred = u;
- return 0;
-}
-
-int getpeersec(int fd, char **ret) {
- socklen_t n = 64;
- char *s;
- int r;
-
- assert(fd >= 0);
- assert(ret);
-
- s = new0(char, n);
- if (!s)
- return -ENOMEM;
-
- r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
- if (r < 0) {
- free(s);
-
- if (errno != ERANGE)
- return -errno;
-
- s = new0(char, n);
- if (!s)
- return -ENOMEM;
-
- r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
- if (r < 0) {
- free(s);
- return -errno;
- }
- }
-
- if (isempty(s)) {
- free(s);
- return -EOPNOTSUPP;
- }
-
- *ret = s;
- return 0;
-}
-
-/* This is much like like mkostemp() but is subject to umask(). */
-int mkostemp_safe(char *pattern, int flags) {
- _cleanup_umask_ mode_t u;
- int fd;
-
- assert(pattern);
-
- u = umask(077);
-
- fd = mkostemp(pattern, flags);
- if (fd < 0)
- return -errno;
-
- return fd;
-}
-
-int open_tmpfile(const char *path, int flags) {
- char *p;
- int fd;
-
- assert(path);
-
-#ifdef O_TMPFILE
- /* Try O_TMPFILE first, if it is supported */
- fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
- if (fd >= 0)
- return fd;
-#endif
-
- /* Fall back to unguessable name + unlinking */
- p = strjoina(path, "/systemd-tmp-XXXXXX");
-
- fd = mkostemp_safe(p, flags);
- if (fd < 0)
- return fd;
-
- unlink(p);
- return fd;
-}
-
-int fd_warn_permissions(const char *path, int fd) {
- struct stat st;
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if (st.st_mode & 0111)
- log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
-
- if (st.st_mode & 0002)
- log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path);
-
- if (getpid() == 1 && (st.st_mode & 0044) != 0044)
- log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path);
-
- return 0;
-}
-
-unsigned long personality_from_string(const char *p) {
-
- /* Parse a personality specifier. We introduce our own
- * identifiers that indicate specific ABIs, rather than just
- * hints regarding the register size, since we want to keep
- * things open for multiple locally supported ABIs for the
- * same register size. We try to reuse the ABI identifiers
- * used by libseccomp. */
-
-#if defined(__x86_64__)
-
- if (streq(p, "x86"))
- return PER_LINUX32;
-
- if (streq(p, "x86-64"))
- return PER_LINUX;
-
-#elif defined(__i386__)
-
- if (streq(p, "x86"))
- return PER_LINUX;
-
-#elif defined(__s390x__)
-
- if (streq(p, "s390"))
- return PER_LINUX32;
-
- if (streq(p, "s390x"))
- return PER_LINUX;
-
-#elif defined(__s390__)
-
- if (streq(p, "s390"))
- return PER_LINUX;
-#endif
-
- return PERSONALITY_INVALID;
-}
-
-const char* personality_to_string(unsigned long p) {
-
-#if defined(__x86_64__)
-
- if (p == PER_LINUX32)
- return "x86";
-
- if (p == PER_LINUX)
- return "x86-64";
-
-#elif defined(__i386__)
-
- if (p == PER_LINUX)
- return "x86";
-
-#elif defined(__s390x__)
-
- if (p == PER_LINUX)
- return "s390x";
-
- if (p == PER_LINUX32)
- return "s390";
-
-#elif defined(__s390__)
-
- if (p == PER_LINUX)
- return "s390";
-
-#endif
-
- return NULL;
-}
-
uint64_t physical_memory(void) {
long mem;
@@ -5380,1575 +820,21 @@ uint64_t physical_memory(void) {
return (uint64_t) mem * (uint64_t) page_size();
}
-void hexdump(FILE *f, const void *p, size_t s) {
- const uint8_t *b = p;
- unsigned n = 0;
-
- assert(s == 0 || b);
-
- while (s > 0) {
- size_t i;
-
- fprintf(f, "%04x ", n);
-
- for (i = 0; i < 16; i++) {
-
- if (i >= s)
- fputs(" ", f);
- else
- fprintf(f, "%02x ", b[i]);
-
- if (i == 7)
- fputc(' ', f);
- }
-
- fputc(' ', f);
-
- for (i = 0; i < 16; i++) {
-
- if (i >= s)
- fputc(' ', f);
- else
- fputc(isprint(b[i]) ? (char) b[i] : '.', f);
- }
-
- fputc('\n', f);
-
- if (s < 16)
- break;
-
- n += 16;
- b += 16;
- s -= 16;
- }
-}
-
int update_reboot_param_file(const char *param) {
int r = 0;
if (param) {
-
r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
if (r < 0)
- log_error("Failed to write reboot param to "
- REBOOT_PARAM_FILE": %s", strerror(-r));
- } else
- unlink(REBOOT_PARAM_FILE);
-
- return r;
-}
-
-int umount_recursive(const char *prefix, int flags) {
- bool again;
- int n = 0, r;
-
- /* Try to umount everything recursively below a
- * directory. Also, take care of stacked mounts, and keep
- * unmounting them until they are gone. */
-
- do {
- _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-
- again = false;
- r = 0;
-
- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!proc_self_mountinfo)
- return -errno;
-
- for (;;) {
- _cleanup_free_ char *path = NULL, *p = NULL;
- int k;
-
- k = fscanf(proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%*s" /* (6) mount options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%*s " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path);
- if (k != 1) {
- if (k == EOF)
- break;
-
- continue;
- }
-
- r = cunescape(path, UNESCAPE_RELAX, &p);
- if (r < 0)
- return r;
-
- if (!path_startswith(p, prefix))
- continue;
-
- if (umount2(p, flags) < 0) {
- r = -errno;
- continue;
- }
-
- again = true;
- n++;
-
- break;
- }
-
- } while (again);
-
- return r ? r : n;
-}
-
-static int get_mount_flags(const char *path, unsigned long *flags) {
- struct statvfs buf;
-
- if (statvfs(path, &buf) < 0)
- return -errno;
- *flags = buf.f_flag;
- return 0;
-}
-
-int bind_remount_recursive(const char *prefix, bool ro) {
- _cleanup_set_free_free_ Set *done = NULL;
- _cleanup_free_ char *cleaned = NULL;
- int r;
-
- /* Recursively remount a directory (and all its submounts)
- * read-only or read-write. If the directory is already
- * mounted, we reuse the mount and simply mark it
- * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write
- * operation). If it isn't we first make it one. Afterwards we
- * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all
- * submounts we can access, too. When mounts are stacked on
- * the same mount point we only care for each individual
- * "top-level" mount on each point, as we cannot
- * influence/access the underlying mounts anyway. We do not
- * have any effect on future submounts that might get
- * propagated, they migt be writable. This includes future
- * submounts that have been triggered via autofs. */
-
- cleaned = strdup(prefix);
- if (!cleaned)
- return -ENOMEM;
-
- path_kill_slashes(cleaned);
-
- done = set_new(&string_hash_ops);
- if (!done)
- return -ENOMEM;
-
- for (;;) {
- _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
- _cleanup_set_free_free_ Set *todo = NULL;
- bool top_autofs = false;
- char *x;
- unsigned long orig_flags;
-
- todo = set_new(&string_hash_ops);
- if (!todo)
- return -ENOMEM;
-
- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!proc_self_mountinfo)
- return -errno;
-
- for (;;) {
- _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL;
- int k;
-
- k = fscanf(proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%*s" /* (6) mount options (superblock) */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%ms " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%*s" /* (11) mount options (bind mount) */
- "%*[^\n]", /* some rubbish at the end */
- &path,
- &type);
- if (k != 2) {
- if (k == EOF)
- break;
-
- continue;
- }
-
- r = cunescape(path, UNESCAPE_RELAX, &p);
- if (r < 0)
- return r;
-
- /* Let's ignore autofs mounts. If they aren't
- * triggered yet, we want to avoid triggering
- * them, as we don't make any guarantees for
- * future submounts anyway. If they are
- * already triggered, then we will find
- * another entry for this. */
- if (streq(type, "autofs")) {
- top_autofs = top_autofs || path_equal(cleaned, p);
- continue;
- }
-
- if (path_startswith(p, cleaned) &&
- !set_contains(done, p)) {
-
- r = set_consume(todo, p);
- p = NULL;
-
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return r;
- }
- }
-
- /* If we have no submounts to process anymore and if
- * the root is either already done, or an autofs, we
- * are done */
- if (set_isempty(todo) &&
- (top_autofs || set_contains(done, cleaned)))
- return 0;
-
- if (!set_contains(done, cleaned) &&
- !set_contains(todo, cleaned)) {
- /* The prefix directory itself is not yet a
- * mount, make it one. */
- if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0)
- return -errno;
-
- orig_flags = 0;
- (void) get_mount_flags(cleaned, &orig_flags);
- orig_flags &= ~MS_RDONLY;
-
- if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
- return -errno;
-
- x = strdup(cleaned);
- if (!x)
- return -ENOMEM;
-
- r = set_consume(done, x);
- if (r < 0)
- return r;
- }
-
- while ((x = set_steal_first(todo))) {
-
- r = set_consume(done, x);
- if (r == -EEXIST || r == 0)
- continue;
- if (r < 0)
- return r;
-
- /* Try to reuse the original flag set, but
- * don't care for errors, in case of
- * obstructed mounts */
- orig_flags = 0;
- (void) get_mount_flags(x, &orig_flags);
- orig_flags &= ~MS_RDONLY;
-
- if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
-
- /* Deal with mount points that are
- * obstructed by a later mount */
-
- if (errno != ENOENT)
- return -errno;
- }
-
- }
- }
-}
-
-int fflush_and_check(FILE *f) {
- assert(f);
-
- errno = 0;
- fflush(f);
-
- if (ferror(f))
- return errno ? -errno : -EIO;
-
- return 0;
-}
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t;
-
- assert(p);
- assert(ret);
-
- /*
- * Turns this:
- * /foo/bar/waldo
- *
- * Into this:
- * /foo/bar/.#<extra>waldoXXXXXX
- */
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- if (extra == NULL)
- extra = "";
-
- t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
- if (!t)
- return -ENOMEM;
-
- strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
-
- *ret = path_kill_slashes(t);
- return 0;
-}
-
-int tempfn_random(const char *p, const char *extra, char **ret) {
- const char *fn;
- char *t, *x;
- uint64_t u;
- unsigned i;
-
- assert(p);
- assert(ret);
-
- /*
- * Turns this:
- * /foo/bar/waldo
- *
- * Into this:
- * /foo/bar/.#<extra>waldobaa2a261115984a9
- */
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- if (!extra)
- extra = "";
-
- t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
- if (!t)
- return -ENOMEM;
-
- x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
-
- u = random_u64();
- for (i = 0; i < 16; i++) {
- *(x++) = hexchar(u & 0xF);
- u >>= 4;
- }
-
- *x = 0;
-
- *ret = path_kill_slashes(t);
- return 0;
-}
-
-int tempfn_random_child(const char *p, const char *extra, char **ret) {
- char *t, *x;
- uint64_t u;
- unsigned i;
-
- assert(p);
- assert(ret);
-
- /* Turns this:
- * /foo/bar/waldo
- * Into this:
- * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
- */
-
- if (!extra)
- extra = "";
-
- t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
- if (!t)
- return -ENOMEM;
-
- x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
-
- u = random_u64();
- for (i = 0; i < 16; i++) {
- *(x++) = hexchar(u & 0xF);
- u >>= 4;
- }
-
- *x = 0;
-
- *ret = path_kill_slashes(t);
- return 0;
-}
-
-int take_password_lock(const char *root) {
-
- struct flock flock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
-
- const char *path;
- int fd, r;
-
- /* This is roughly the same as lckpwdf(), but not as awful. We
- * don't want to use alarm() and signals, hence we implement
- * our own trivial version of this.
- *
- * Note that shadow-utils also takes per-database locks in
- * addition to lckpwdf(). However, we don't given that they
- * are redundant as they they invoke lckpwdf() first and keep
- * it during everything they do. The per-database locks are
- * awfully racy, and thus we just won't do them. */
-
- if (root)
- path = strjoina(root, "/etc/.pwd.lock");
- else
- path = "/etc/.pwd.lock";
-
- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
- if (fd < 0)
- return -errno;
-
- r = fcntl(fd, F_SETLKW, &flock);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
-
- return fd;
-}
-
-int is_symlink(const char *path) {
- struct stat info;
-
- if (lstat(path, &info) < 0)
- return -errno;
-
- return !!S_ISLNK(info.st_mode);
-}
-
-int is_dir(const char* path, bool follow) {
- struct stat st;
- int r;
-
- if (follow)
- r = stat(path, &st);
- else
- r = lstat(path, &st);
- if (r < 0)
- return -errno;
-
- return !!S_ISDIR(st.st_mode);
-}
-
-int is_device_node(const char *path) {
- struct stat info;
-
- if (lstat(path, &info) < 0)
- return -errno;
-
- return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
-}
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
- _cleanup_free_ char *s = NULL;
- size_t allocated = 0, sz = 0;
- int r;
-
- enum {
- START,
- VALUE,
- VALUE_ESCAPE,
- SINGLE_QUOTE,
- SINGLE_QUOTE_ESCAPE,
- DOUBLE_QUOTE,
- DOUBLE_QUOTE_ESCAPE,
- SEPARATOR,
- } state = START;
-
- assert(p);
- assert(ret);
-
- if (!separators)
- separators = WHITESPACE;
-
- /* Bail early if called after last value or with no input */
- if (!*p)
- goto finish_force_terminate;
-
- /* Parses the first word of a string, and returns it in
- * *ret. Removes all quotes in the process. When parsing fails
- * (because of an uneven number of quotes or similar), leaves
- * the pointer *p at the first invalid character. */
-
- for (;;) {
- char c = **p;
-
- switch (state) {
-
- case START:
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
- if (c == 0)
- goto finish_force_terminate;
- else if (strchr(separators, c)) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
- goto finish_force_next;
- }
- break;
- }
-
- /* We found a non-blank character, so we will always
- * want to return a string (even if it is empty),
- * allocate it here. */
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
- state = VALUE;
- /* fallthrough */
-
- case VALUE:
- if (c == 0)
- goto finish_force_terminate;
- else if (c == '\'' && (flags & EXTRACT_QUOTES))
- state = SINGLE_QUOTE;
- else if (c == '\\')
- state = VALUE_ESCAPE;
- else if (c == '\"' && (flags & EXTRACT_QUOTES))
- state = DOUBLE_QUOTE;
- else if (strchr(separators, c)) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
- goto finish_force_next;
- }
- state = SEPARATOR;
- } else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case SINGLE_QUOTE:
- if (c == 0) {
- if (flags & EXTRACT_RELAX)
- goto finish_force_terminate;
- return -EINVAL;
- } else if (c == '\'')
- state = VALUE;
- else if (c == '\\')
- state = SINGLE_QUOTE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case DOUBLE_QUOTE:
- if (c == 0)
- return -EINVAL;
- else if (c == '\"')
- state = VALUE;
- else if (c == '\\')
- state = DOUBLE_QUOTE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case SINGLE_QUOTE_ESCAPE:
- case DOUBLE_QUOTE_ESCAPE:
- case VALUE_ESCAPE:
- if (!GREEDY_REALLOC(s, allocated, sz+7))
- return -ENOMEM;
-
- if (c == 0) {
- if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
- (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
- /* If we find an unquoted trailing backslash and we're in
- * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
- * output.
- *
- * Unbalanced quotes will only be allowed in EXTRACT_RELAX
- * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
- */
- s[sz++] = '\\';
- goto finish_force_terminate;
- }
- if (flags & EXTRACT_RELAX)
- goto finish_force_terminate;
- return -EINVAL;
- }
-
- if (flags & EXTRACT_CUNESCAPE) {
- uint32_t u;
-
- r = cunescape_one(*p, (size_t) -1, &c, &u);
- if (r < 0) {
- if (flags & EXTRACT_CUNESCAPE_RELAX) {
- s[sz++] = '\\';
- s[sz++] = c;
- goto end_escape;
- }
- return -EINVAL;
- }
-
- (*p) += r - 1;
-
- if (c != 0)
- s[sz++] = c; /* normal explicit char */
- else
- sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
- } else
- s[sz++] = c;
-
-end_escape:
- state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
- (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
- VALUE;
- break;
-
- case SEPARATOR:
- if (c == 0)
- goto finish_force_terminate;
- if (!strchr(separators, c))
- goto finish;
- break;
- }
-
- (*p) ++;
- }
-
-finish_force_terminate:
- *p = NULL;
-finish:
- if (!s) {
- *p = NULL;
- *ret = NULL;
- return 0;
- }
-
-finish_force_next:
- s[sz] = 0;
- *ret = s;
- s = NULL;
-
- return 1;
-}
-
-int extract_first_word_and_warn(
- const char **p,
- char **ret,
- const char *separators,
- ExtractFlags flags,
- const char *unit,
- const char *filename,
- unsigned line,
- const char *rvalue) {
- /* Try to unquote it, if it fails, warn about it and try again but this
- * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
- * in invalid escape sequences. */
- const char *save;
- int r;
-
- save = *p;
- r = extract_first_word(p, ret, separators, flags);
- if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
- /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
- *p = save;
- r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
- else
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Invalid escape sequences in command line: \"%s\"", rvalue);
- }
- return r;
-}
-
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
- va_list ap;
- char **l;
- int n = 0, i, c, r;
-
- /* Parses a number of words from a string, stripping any
- * quotes if necessary. */
-
- assert(p);
-
- /* Count how many words are expected */
- va_start(ap, flags);
- for (;;) {
- if (!va_arg(ap, char **))
- break;
- n++;
- }
- va_end(ap);
-
- if (n <= 0)
- return 0;
-
- /* Read all words into a temporary array */
- l = newa0(char*, n);
- for (c = 0; c < n; c++) {
-
- r = extract_first_word(p, &l[c], separators, flags);
- if (r < 0) {
- int j;
-
- for (j = 0; j < c; j++)
- free(l[j]);
-
- return r;
- }
-
- if (r == 0)
- break;
- }
-
- /* If we managed to parse all words, return them in the passed
- * in parameters */
- va_start(ap, flags);
- for (i = 0; i < n; i++) {
- char **v;
-
- v = va_arg(ap, char **);
- assert(v);
-
- *v = l[i];
- }
- va_end(ap);
-
- return c;
-}
-
-int free_and_strdup(char **p, const char *s) {
- char *t;
-
- assert(p);
-
- /* Replaces a string pointer with an strdup()ed new string,
- * possibly freeing the old one. */
-
- if (streq_ptr(*p, s))
- return 0;
-
- if (s) {
- t = strdup(s);
- if (!t)
- return -ENOMEM;
- } else
- t = NULL;
-
- free(*p);
- *p = t;
-
- return 1;
-}
-
-int ptsname_malloc(int fd, char **ret) {
- size_t l = 100;
-
- assert(fd >= 0);
- assert(ret);
-
- for (;;) {
- char *c;
-
- c = new(char, l);
- if (!c)
- return -ENOMEM;
-
- if (ptsname_r(fd, c, l) == 0) {
- *ret = c;
- return 0;
- }
- if (errno != ERANGE) {
- free(c);
- return -errno;
- }
-
- free(c);
- l *= 2;
- }
-}
-
-int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
- _cleanup_close_pair_ int pair[2] = { -1, -1 };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- siginfo_t si;
- pid_t child;
- int r;
-
- assert(pid > 0);
-
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
- if (r < 0)
- return r;
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
- return -errno;
-
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
- int master;
-
- pair[0] = safe_close(pair[0]);
-
- r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- master = posix_openpt(flags);
- if (master < 0)
- _exit(EXIT_FAILURE);
-
- if (unlockpt(master) < 0)
- _exit(EXIT_FAILURE);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
- _exit(EXIT_FAILURE);
-
- _exit(EXIT_SUCCESS);
- }
-
- pair[1] = safe_close(pair[1]);
-
- r = wait_for_terminate(child, &si);
- if (r < 0)
- return r;
- if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return -EIO;
-
- if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
- return -errno;
-
- CMSG_FOREACH(cmsg, &mh)
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- int *fds;
- unsigned n_fds;
-
- fds = (int*) CMSG_DATA(cmsg);
- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
- if (n_fds != 1) {
- close_many(fds, n_fds);
- return -EIO;
- }
-
- return fds[0];
- }
-
- return -EIO;
-}
-
-ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
- _cleanup_close_ int fd = -1;
- ssize_t l;
-
- /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
-
- fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
- if (fd < 0)
- return -errno;
-
- l = fgetxattr(fd, attribute, value, size);
- if (l < 0)
- return -errno;
-
- return l;
-}
-
-static int parse_crtime(le64_t le, usec_t *usec) {
- uint64_t u;
-
- assert(usec);
-
- u = le64toh(le);
- if (u == 0 || u == (uint64_t) -1)
- return -EIO;
-
- *usec = (usec_t) u;
- return 0;
-}
-
-int fd_getcrtime(int fd, usec_t *usec) {
- le64_t le;
- ssize_t n;
-
- assert(fd >= 0);
- assert(usec);
-
- /* Until Linux gets a real concept of birthtime/creation time,
- * let's fake one with xattrs */
-
- n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
- if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
-
- return parse_crtime(le, usec);
-}
-
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
- le64_t le;
- ssize_t n;
-
- n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
- if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
-
- return parse_crtime(le, usec);
-}
-
-int path_getcrtime(const char *p, usec_t *usec) {
- le64_t le;
- ssize_t n;
-
- assert(p);
- assert(usec);
-
- n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
- if (n < 0)
- return -errno;
- if (n != sizeof(le))
- return -EIO;
-
- return parse_crtime(le, usec);
-}
-
-int fd_setcrtime(int fd, usec_t usec) {
- le64_t le;
-
- assert(fd >= 0);
-
- if (usec <= 0)
- usec = now(CLOCK_REALTIME);
-
- le = htole64((uint64_t) usec);
- if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
- return -errno;
-
- return 0;
-}
-
-int same_fd(int a, int b) {
- struct stat sta, stb;
- pid_t pid;
- int r, fa, fb;
-
- assert(a >= 0);
- assert(b >= 0);
-
- /* Compares two file descriptors. Note that semantics are
- * quite different depending on whether we have kcmp() or we
- * don't. If we have kcmp() this will only return true for
- * dup()ed file descriptors, but not otherwise. If we don't
- * have kcmp() this will also return true for two fds of the same
- * file, created by separate open() calls. Since we use this
- * call mostly for filtering out duplicates in the fd store
- * this difference hopefully doesn't matter too much. */
-
- if (a == b)
- return true;
-
- /* Try to use kcmp() if we have it. */
- pid = getpid();
- r = kcmp(pid, pid, KCMP_FILE, a, b);
- if (r == 0)
- return true;
- if (r > 0)
- return false;
- if (errno != ENOSYS)
- return -errno;
-
- /* We don't have kcmp(), use fstat() instead. */
- if (fstat(a, &sta) < 0)
- return -errno;
-
- if (fstat(b, &stb) < 0)
- return -errno;
-
- if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT))
- return false;
-
- /* We consider all device fds different, since two device fds
- * might refer to quite different device contexts even though
- * they share the same inode and backing dev_t. */
-
- if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode))
- return false;
-
- if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino)
- return false;
-
- /* The fds refer to the same inode on disk, let's also check
- * if they have the same fd flags. This is useful to
- * distinguish the read and write side of a pipe created with
- * pipe(). */
- fa = fcntl(a, F_GETFL);
- if (fa < 0)
- return -errno;
-
- fb = fcntl(b, F_GETFL);
- if (fb < 0)
- return -errno;
-
- return fa == fb;
-}
-
-int chattr_fd(int fd, unsigned value, unsigned mask) {
- unsigned old_attr, new_attr;
- struct stat st;
-
- assert(fd >= 0);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- /* Explicitly check whether this is a regular file or
- * directory. If it is anything else (such as a device node or
- * fifo), then the ioctl will not hit the file systems but
- * possibly drivers, where the ioctl might have different
- * effects. Notably, DRM is using the same ioctl() number. */
-
- if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
- return -ENOTTY;
-
- if (mask == 0)
- return 0;
-
- if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
- return -errno;
-
- new_attr = (old_attr & ~mask) | (value & mask);
- if (new_attr == old_attr)
- return 0;
-
- if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
- return -errno;
-
- return 1;
-}
-
-int chattr_path(const char *p, unsigned value, unsigned mask) {
- _cleanup_close_ int fd = -1;
-
- assert(p);
-
- if (mask == 0)
- return 0;
-
- fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd < 0)
- return -errno;
-
- return chattr_fd(fd, value, mask);
-}
-
-int read_attr_fd(int fd, unsigned *ret) {
- struct stat st;
-
- assert(fd >= 0);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
- return -ENOTTY;
-
- if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
- return -errno;
-
- return 0;
-}
-
-int read_attr_path(const char *p, unsigned *ret) {
- _cleanup_close_ int fd = -1;
-
- assert(p);
- assert(ret);
-
- fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd < 0)
- return -errno;
-
- return read_attr_fd(fd, ret);
-}
-
-static size_t nul_length(const uint8_t *p, size_t sz) {
- size_t n = 0;
-
- while (sz > 0) {
- if (*p != 0)
- break;
-
- n++;
- p++;
- sz--;
- }
-
- return n;
-}
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
- const uint8_t *q, *w, *e;
- ssize_t l;
-
- q = w = p;
- e = q + sz;
- while (q < e) {
- size_t n;
-
- n = nul_length(q, e - q);
-
- /* If there are more than the specified run length of
- * NUL bytes, or if this is the beginning or the end
- * of the buffer, then seek instead of write */
- if ((n > run_length) ||
- (n > 0 && q == p) ||
- (n > 0 && q + n >= e)) {
- if (q > w) {
- l = write(fd, w, q - w);
- if (l < 0)
- return -errno;
- if (l != q -w)
- return -EIO;
- }
-
- if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
- return -errno;
-
- q += n;
- w = q;
- } else if (n > 0)
- q += n;
- else
- q ++;
- }
-
- if (q > w) {
- l = write(fd, w, q - w);
- if (l < 0)
- return -errno;
- if (l != q - w)
- return -EIO;
- }
-
- return q - (const uint8_t*) p;
-}
-
-void sigkill_wait(pid_t *pid) {
- if (!pid)
- return;
- if (*pid <= 1)
- return;
-
- if (kill(*pid, SIGKILL) > 0)
- (void) wait_for_terminate(*pid, NULL);
-}
-
-int syslog_parse_priority(const char **p, int *priority, bool with_facility) {
- int a = 0, b = 0, c = 0;
- int k;
-
- assert(p);
- assert(*p);
- assert(priority);
-
- if ((*p)[0] != '<')
- return 0;
-
- if (!strchr(*p, '>'))
- return 0;
-
- if ((*p)[2] == '>') {
- c = undecchar((*p)[1]);
- k = 3;
- } else if ((*p)[3] == '>') {
- b = undecchar((*p)[1]);
- c = undecchar((*p)[2]);
- k = 4;
- } else if ((*p)[4] == '>') {
- a = undecchar((*p)[1]);
- b = undecchar((*p)[2]);
- c = undecchar((*p)[3]);
- k = 5;
+ return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
} else
- return 0;
-
- if (a < 0 || b < 0 || c < 0 ||
- (!with_facility && (a || b || c > 7)))
- return 0;
-
- if (with_facility)
- *priority = a*100 + b*10 + c;
- else
- *priority = (*priority & LOG_FACMASK) | c;
-
- *p += k;
- return 1;
-}
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {
- size_t i;
-
- if (!key)
- return -1;
-
- for (i = 0; i < len; ++i)
- if (streq_ptr(table[i], key))
- return (ssize_t) i;
-
- return -1;
-}
-
-void cmsg_close_all(struct msghdr *mh) {
- struct cmsghdr *cmsg;
-
- assert(mh);
-
- CMSG_FOREACH(cmsg, mh)
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
- close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
-}
-
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
- struct stat buf;
- int ret;
-
- ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE);
- if (ret >= 0)
- return 0;
-
- /* renameat2() exists since Linux 3.15, btrfs added support for it later.
- * If it is not implemented, fallback to another method. */
- if (!IN_SET(errno, EINVAL, ENOSYS))
- return -errno;
-
- /* The link()/unlink() fallback does not work on directories. But
- * renameat() without RENAME_NOREPLACE gives the same semantics on
- * directories, except when newpath is an *empty* directory. This is
- * good enough. */
- ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW);
- if (ret >= 0 && S_ISDIR(buf.st_mode)) {
- ret = renameat(olddirfd, oldpath, newdirfd, newpath);
- return ret >= 0 ? 0 : -errno;
- }
-
- /* If it is not a directory, use the link()/unlink() fallback. */
- ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0);
- if (ret < 0)
- return -errno;
-
- ret = unlinkat(olddirfd, oldpath, 0);
- if (ret < 0) {
- /* backup errno before the following unlinkat() alters it */
- ret = errno;
- (void) unlinkat(newdirfd, newpath, 0);
- errno = ret;
- return -errno;
- }
-
- return 0;
-}
-
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
- assert(bad);
-
- for (; *s; s++) {
- if (*s == '\\' || strchr(bad, *s))
- *(t++) = '\\';
-
- *(t++) = *s;
- }
-
- return t;
-}
-
-char *shell_escape(const char *s, const char *bad) {
- char *r, *t;
-
- r = new(char, strlen(s)*2+1);
- if (!r)
- return NULL;
-
- t = strcpy_backslash_escaped(r, s, bad);
- *t = 0;
-
- return r;
-}
-
-char *shell_maybe_quote(const char *s) {
- const char *p;
- char *r, *t;
-
- assert(s);
-
- /* Encloses a string in double quotes if necessary to make it
- * OK as shell string. */
-
- for (p = s; *p; p++)
- if (*p <= ' ' ||
- *p >= 127 ||
- strchr(SHELL_NEED_QUOTES, *p))
- break;
-
- if (!*p)
- return strdup(s);
-
- r = new(char, 1+strlen(s)*2+1+1);
- if (!r)
- return NULL;
-
- t = r;
- *(t++) = '"';
- t = mempcpy(t, s, p - s);
-
- t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
-
- *(t++)= '"';
- *t = 0;
-
- return r;
-}
-
-int parse_mode(const char *s, mode_t *ret) {
- char *x;
- long l;
+ (void) unlink(REBOOT_PARAM_FILE);
- assert(s);
- assert(ret);
-
- errno = 0;
- l = strtol(s, &x, 8);
- if (errno != 0)
- return -errno;
-
- if (!x || x == s || *x)
- return -EINVAL;
- if (l < 0 || l > 07777)
- return -ERANGE;
-
- *ret = (mode_t) l;
return 0;
}
-int mount_move_root(const char *path) {
- assert(path);
-
- if (chdir(path) < 0)
- return -errno;
-
- if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
- return -errno;
-
- if (chroot(".") < 0)
- return -errno;
-
- if (chdir("/") < 0)
- return -errno;
-
+int version(void) {
+ puts(PACKAGE_STRING "\n"
+ SYSTEMD_FEATURES);
return 0;
}
-
-int reset_uid_gid(void) {
-
- if (setgroups(0, NULL) < 0)
- return -errno;
-
- if (setresgid(0, 0, 0) < 0)
- return -errno;
-
- if (setresuid(0, 0, 0) < 0)
- return -errno;
-
- return 0;
-}
-
-int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
- char *v;
- size_t l;
- ssize_t n;
-
- assert(path);
- assert(name);
- assert(value);
-
- for (l = 100; ; l = (size_t) n + 1) {
- v = new0(char, l);
- if (!v)
- return -ENOMEM;
-
- if (allow_symlink)
- n = lgetxattr(path, name, v, l);
- else
- n = getxattr(path, name, v, l);
-
- if (n >= 0 && (size_t) n < l) {
- *value = v;
- return n;
- }
-
- free(v);
-
- if (n < 0 && errno != ERANGE)
- return -errno;
-
- if (allow_symlink)
- n = lgetxattr(path, name, NULL, 0);
- else
- n = getxattr(path, name, NULL, 0);
- if (n < 0)
- return -errno;
- }
-}
-
-int fgetxattr_malloc(int fd, const char *name, char **value) {
- char *v;
- size_t l;
- ssize_t n;
-
- assert(fd >= 0);
- assert(name);
- assert(value);
-
- for (l = 100; ; l = (size_t) n + 1) {
- v = new0(char, l);
- if (!v)
- return -ENOMEM;
-
- n = fgetxattr(fd, name, v, l);
-
- if (n >= 0 && (size_t) n < l) {
- *value = v;
- return n;
- }
-
- free(v);
-
- if (n < 0 && errno != ERANGE)
- return -errno;
-
- n = fgetxattr(fd, name, NULL, 0);
- if (n < 0)
- return -errno;
- }
-}
-
-int send_one_fd(int transport_fd, int fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- ssize_t k;
-
- assert(transport_fd >= 0);
- assert(fd >= 0);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = CMSG_SPACE(sizeof(int));
- k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return -errno;
-
- return 0;
-}
-
-int receive_one_fd(int transport_fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- ssize_t k;
-
- assert(transport_fd >= 0);
-
- /*
- * Receive a single FD via @transport_fd. We don't care for the
- * transport-type, but the caller must assure that no other CMSG types
- * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so
- * for packet-based transports, the caller must ensure to send only a
- * single FD per packet.
- * This is best used in combination with send_one_fd().
- */
-
- k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC);
- if (k < 0)
- return -errno;
-
- cmsg = CMSG_FIRSTHDR(&mh);
- if (!cmsg || CMSG_NXTHDR(&mh, cmsg) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS ||
- cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
- *(const int *)CMSG_DATA(cmsg) < 0) {
- cmsg_close_all(&mh);
- return -EIO;
- }
-
- return *(const int *)CMSG_DATA(cmsg);
-}
diff --git a/src/basic/util.h b/src/basic/util.h
index 56d9f037bf..d9d2f72b75 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -22,13 +22,10 @@
***/
#include <alloca.h>
-#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <locale.h>
-#include <mntent.h>
-#include <sched.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
@@ -47,49 +44,9 @@
#include "missing.h"
#include "time-util.h"
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n\r"
-#define NEWLINE "\n\r"
-#define QUOTES "\"\'"
-#define COMMENTS "#;"
-#define GLOB_CHARS "*?["
-
-/* What characters are special in the shell? */
-/* must be escaped outside and inside double-quotes */
-#define SHELL_NEED_ESCAPE "\"\\`$"
-/* can be escaped or double-quoted */
-#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;"
-
-#define FORMAT_BYTES_MAX 8
-
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
-#define streq(a,b) (strcmp((a),(b)) == 0)
-#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
-#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0)
-#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
-
-bool streq_ptr(const char *a, const char *b) _pure_;
-int strcmp_ptr(const char *a, const char *b) _pure_;
-
-#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
-
-#define new0(t, n) ((t*) calloc((n), sizeof(t)))
-
-#define newa(t, n) ((t*) alloca(sizeof(t)*(n)))
-
-#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n)))
-
-#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
-
-#define malloc0(n) (calloc(1, (n)))
-
-static inline void *mfree(void *memory) {
- free(memory);
- return NULL;
-}
-
static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
}
@@ -102,351 +59,13 @@ static inline const char* one_zero(bool b) {
return b ? "1" : "0";
}
-static inline const char* strempty(const char *s) {
- return s ? s : "";
-}
-
-static inline const char* strnull(const char *s) {
- return s ? s : "(null)";
-}
-
-static inline const char *strna(const char *s) {
- return s ? s : "n/a";
-}
-
-static inline bool isempty(const char *p) {
- return !p || !p[0];
-}
-
-static inline char *startswith(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-static inline char *startswith_no_case(const char *s, const char *prefix) {
- size_t l;
-
- l = strlen(prefix);
- if (strncasecmp(s, prefix, l) == 0)
- return (char*) s + l;
-
- return NULL;
-}
-
-char *endswith(const char *s, const char *postfix) _pure_;
-char *endswith_no_case(const char *s, const char *postfix) _pure_;
-
-char *first_word(const char *s, const char *word) _pure_;
-
-int close_nointr(int fd);
-int safe_close(int fd);
-void safe_close_pair(int p[]);
-
-void close_many(const int fds[], unsigned n_fd);
-
-int fclose_nointr(FILE *f);
-FILE* safe_fclose(FILE *f);
-DIR* safe_closedir(DIR *f);
-
-int parse_size(const char *t, uint64_t base, uint64_t *size);
-
-int parse_boolean(const char *v) _pure_;
-int parse_pid(const char *s, pid_t* ret_pid);
-int parse_uid(const char *s, uid_t* ret_uid);
-#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
-
-bool uid_is_valid(uid_t uid);
-
-static inline bool gid_is_valid(gid_t gid) {
- return uid_is_valid((uid_t) gid);
-}
-
-int safe_atou(const char *s, unsigned *ret_u);
-int safe_atoi(const char *s, int *ret_i);
-
-int safe_atollu(const char *s, unsigned long long *ret_u);
-int safe_atolli(const char *s, long long int *ret_i);
-
-int safe_atod(const char *s, double *ret_d);
-
-int safe_atou8(const char *s, uint8_t *ret);
-
-#if LONG_MAX == INT_MAX
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
- assert_cc(sizeof(unsigned long) == sizeof(unsigned));
- return safe_atou(s, (unsigned*) ret_u);
-}
-static inline int safe_atoli(const char *s, long int *ret_u) {
- assert_cc(sizeof(long int) == sizeof(int));
- return safe_atoi(s, (int*) ret_u);
-}
-#else
-static inline int safe_atolu(const char *s, unsigned long *ret_u) {
- assert_cc(sizeof(unsigned long) == sizeof(unsigned long long));
- return safe_atollu(s, (unsigned long long*) ret_u);
-}
-static inline int safe_atoli(const char *s, long int *ret_u) {
- assert_cc(sizeof(long int) == sizeof(long long int));
- return safe_atolli(s, (long long int*) ret_u);
-}
-#endif
-
-static inline int safe_atou32(const char *s, uint32_t *ret_u) {
- assert_cc(sizeof(uint32_t) == sizeof(unsigned));
- return safe_atou(s, (unsigned*) ret_u);
-}
-
-static inline int safe_atoi32(const char *s, int32_t *ret_i) {
- assert_cc(sizeof(int32_t) == sizeof(int));
- return safe_atoi(s, (int*) ret_i);
-}
-
-static inline int safe_atou64(const char *s, uint64_t *ret_u) {
- assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
- return safe_atollu(s, (unsigned long long*) ret_u);
-}
-
-static inline int safe_atoi64(const char *s, int64_t *ret_i) {
- assert_cc(sizeof(int64_t) == sizeof(long long int));
- return safe_atolli(s, (long long int*) ret_i);
-}
-
-int safe_atou16(const char *s, uint16_t *ret);
-int safe_atoi16(const char *s, int16_t *ret);
-
-const char* split(const char **state, size_t *l, const char *separator, bool quoted);
-
-#define FOREACH_WORD(word, length, s, state) \
- _FOREACH_WORD(word, length, s, WHITESPACE, false, state)
-
-#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \
- _FOREACH_WORD(word, length, s, separator, false, state)
-
-#define FOREACH_WORD_QUOTED(word, length, s, state) \
- _FOREACH_WORD(word, length, s, WHITESPACE, true, state)
-
-#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
- for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
-
-char *strappend(const char *s, const char *suffix);
-char *strnappend(const char *s, const char *suffix, size_t length);
-
-int readlinkat_malloc(int fd, const char *p, char **ret);
-int readlink_malloc(const char *p, char **r);
-int readlink_value(const char *p, char **ret);
-int readlink_and_make_absolute(const char *p, char **r);
-int readlink_and_canonicalize(const char *p, char **r);
-
-char *strstrip(char *s);
-char *delete_chars(char *s, const char *bad);
-char *truncate_nl(char *s);
-
-char *file_in_same_dir(const char *path, const char *filename);
-
-int rmdir_parents(const char *path, const char *stop);
-
-char hexchar(int x) _const_;
-int unhexchar(char c) _const_;
-char octchar(int x) _const_;
-int unoctchar(char c) _const_;
-char decchar(int x) _const_;
-int undecchar(char c) _const_;
-char base32hexchar(int x) _const_;
-int unbase32hexchar(char c) _const_;
-char base64char(int x) _const_;
-int unbase64char(char c) _const_;
-
-char *cescape(const char *s);
-size_t cescape_char(char c, char *buf);
-
-typedef enum UnescapeFlags {
- UNESCAPE_RELAX = 1,
-} UnescapeFlags;
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret);
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-
-char *xescape(const char *s, const char *bad);
-
-char *ascii_strlower(char *path);
-
-bool dirent_is_file(const struct dirent *de) _pure_;
-bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_;
-
-bool hidden_file(const char *filename) _pure_;
-
-bool chars_intersect(const char *a, const char *b) _pure_;
-
-/* For basic lookup tables with strictly enumerated entries */
-#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
- scope const char *name##_to_string(type i) { \
- if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \
- return NULL; \
- return name##_table[i]; \
- }
-
-ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
-
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
- scope type name##_from_string(const char *s) { \
- return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
- }
-
-#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
-
-/* For string conversions where numbers are also acceptable */
-#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
- int name##_to_string_alloc(type i, char **str) { \
- char *s; \
- if (i < 0 || i > max) \
- return -ERANGE; \
- if (i < (type) ELEMENTSOF(name##_table)) { \
- s = strdup(name##_table[i]); \
- if (!s) \
- return -ENOMEM; \
- } else { \
- if (asprintf(&s, "%i", i) < 0) \
- return -ENOMEM; \
- } \
- *str = s; \
- return 0; \
- } \
- type name##_from_string(const char *s) { \
- type i; \
- unsigned u = 0; \
- if (!s) \
- return (type) -1; \
- for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
- if (streq_ptr(name##_table[i], s)) \
- return i; \
- if (safe_atou(s, &u) >= 0 && u <= max) \
- return (type) u; \
- return (type) -1; \
- } \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-int fd_nonblock(int fd, bool nonblock);
-int fd_cloexec(int fd, bool cloexec);
-
-int close_all_fds(const int except[], unsigned n_except);
-
-bool fstype_is_network(const char *fstype);
-
-int flush_fd(int fd);
-
-int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
-
-ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
-int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
-
-bool is_device_path(const char *path);
-
-int dir_is_empty(const char *path);
-char* dirname_malloc(const char *path);
-
-char* lookup_uid(uid_t uid);
-char* getlogname_malloc(void);
-char* getusername_malloc(void);
-
-int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
-int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
-
-bool is_temporary_fs(const struct statfs *s) _pure_;
-int fd_is_temporary_fs(int fd);
-
-int pipe_eof(int fd);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
-#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-
-cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
-
-#define xsprintf(buf, fmt, ...) \
- assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
- "xsprintf: " #buf "[] must be big enough")
-
-int files_same(const char *filea, const char *fileb);
-
-int running_in_chroot(void);
-
-char *ellipsize(const char *s, size_t length, unsigned percent);
- /* bytes columns */
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent);
-
-int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
-int touch(const char *path);
-
-noreturn void freeze(void);
-
-bool null_or_empty(struct stat *st) _pure_;
-int null_or_empty_path(const char *fn);
-int null_or_empty_fd(int fd);
-
-DIR *xopendirat(int dirfd, const char *name, int flags);
-
-char *fstab_node_to_udev_node(const char *p);
-
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
-bool nulstr_contains(const char*nulstr, const char *needle);
-
bool plymouth_running(void);
-char* strshorten(char *s, size_t l);
-
-int symlink_idempotent(const char *from, const char *to);
-
-int symlink_atomic(const char *from, const char *to);
-int mknod_atomic(const char *path, mode_t mode, dev_t dev);
-int mkfifo_atomic(const char *path, mode_t mode);
-
-int fchmod_umask(int fd, mode_t mode);
-
bool display_is_local(const char *display) _pure_;
int socket_from_display(const char *display, char **path);
-int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
-int get_group_creds(const char **groupname, gid_t *gid);
-
-int in_gid(gid_t gid);
-int in_group(const char *name);
-
-char* uid_to_name(uid_t uid);
-char* gid_to_name(gid_t gid);
-
-int glob_exists(const char *path);
-int glob_extend(char ***strv, const char *path);
-
-int dirent_ensure_type(DIR *d, struct dirent *de);
-
-int get_files_in_directory(const char *path, char ***list);
-
-char *strjoin(const char *x, ...) _sentinel_;
-
-bool is_main_thread(void);
-
-static inline bool _pure_ in_charset(const char *s, const char* charset) {
- assert(s);
- assert(charset);
- return s[strspn(s, charset)] == '\0';
-}
-
int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH(i, l) \
@@ -455,27 +74,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH_PAIR(i, j, l) \
for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
-int ioprio_class_to_string_alloc(int i, char **s);
-int ioprio_class_from_string(const char *s);
-
-const char *sigchld_code_to_string(int i) _const_;
-int sigchld_code_from_string(const char *s) _pure_;
-
-int log_facility_unshifted_to_string_alloc(int i, char **s);
-int log_facility_unshifted_from_string(const char *s);
-
-int log_level_to_string_alloc(int i, char **s);
-int log_level_from_string(const char *s);
-
-int sched_policy_to_string_alloc(int i, char **s);
-int sched_policy_from_string(const char *s);
-
-const char *rlimit_to_string(int i) _const_;
-int rlimit_from_string(const char *s) _pure_;
-
-int ip_tos_to_string_alloc(int i, char **s);
-int ip_tos_from_string(const char *s);
-
extern int saved_argc;
extern char **saved_argv;
@@ -483,182 +81,36 @@ bool kexec_loaded(void);
int prot_from_flags(int flags) _const_;
-char *format_bytes(char *buf, size_t l, uint64_t t);
-
-int fd_wait_for_event(int fd, int event, usec_t timeout);
-
-void* memdup(const void *p, size_t l) _alloc_(2);
-
-int fd_inc_sndbuf(int fd, size_t n);
-int fd_inc_rcvbuf(int fd, size_t n);
-
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
-int setrlimit_closest(int resource, const struct rlimit *rlim);
-
-bool http_url_is_valid(const char *url) _pure_;
-bool documentation_url_is_valid(const char *url) _pure_;
-
-bool http_etag_is_valid(const char *etag);
-
bool in_initrd(void);
-int get_home_dir(char **ret);
-int get_shell(char **_ret);
-
-static inline void freep(void *p) {
- free(*(void**) p);
-}
-
-static inline void closep(int *fd) {
- safe_close(*fd);
-}
-
-static inline void umaskp(mode_t *u) {
- umask(*u);
-}
-
-static inline void close_pairp(int (*p)[2]) {
- safe_close_pair(*p);
-}
-
-static inline void fclosep(FILE **f) {
- safe_fclose(*f);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);
-DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
-DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent);
-
-#define _cleanup_free_ _cleanup_(freep)
-#define _cleanup_close_ _cleanup_(closep)
-#define _cleanup_umask_ _cleanup_(umaskp)
-#define _cleanup_globfree_ _cleanup_(globfree)
-#define _cleanup_fclose_ _cleanup_(fclosep)
-#define _cleanup_pclose_ _cleanup_(pclosep)
-#define _cleanup_closedir_ _cleanup_(closedirp)
-#define _cleanup_endmntent_ _cleanup_(endmntentp)
-#define _cleanup_close_pair_ _cleanup_(close_pairp)
-
-_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) {
- if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
- return NULL;
-
- return malloc(a * b);
-}
-
-_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) {
- if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
- return NULL;
-
- return realloc(p, a * b);
-}
-
-_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) {
- if (_unlikely_(b != 0 && a > ((size_t) -1) / b))
- return NULL;
-
- return memdup(p, a * b);
-}
-
-bool filename_is_valid(const char *p) _pure_;
-bool path_is_safe(const char *p) _pure_;
-bool string_is_safe(const char *p) _pure_;
-bool string_has_cc(const char *p, const char *ok) _pure_;
-
-/**
- * Check if a string contains any glob patterns.
- */
-_pure_ static inline bool string_is_glob(const char *p) {
- return !!strpbrk(p, GLOB_CHARS);
-}
-
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *),
void *arg);
-#define _(String) gettext (String)
-#define N_(String) String
-void init_gettext(void);
-bool is_locale_utf8(void);
-
-typedef enum DrawSpecialChar {
- DRAW_TREE_VERTICAL,
- DRAW_TREE_BRANCH,
- DRAW_TREE_RIGHT,
- DRAW_TREE_SPACE,
- DRAW_TRIANGULAR_BULLET,
- DRAW_BLACK_CIRCLE,
- DRAW_ARROW,
- DRAW_DASH,
- _DRAW_SPECIAL_CHAR_MAX
-} DrawSpecialChar;
-
-const char *draw_special_char(DrawSpecialChar ch);
-
-char *strreplace(const char *text, const char *old_string, const char *new_string);
+/**
+ * Normal qsort requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+ if (nmemb <= 1)
+ return;
-char *strip_tab_ansi(char **p, size_t *l);
+ assert(base);
+ qsort(base, nmemb, size, compar);
+}
int on_ac_power(void);
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
-
-#define FOREACH_LINE(line, f, on_error) \
- for (;;) \
- if (!fgets(line, sizeof(line), f)) { \
- if (ferror(f)) { \
- on_error; \
- } \
- break; \
- } else
-
-#define FOREACH_DIRENT(de, d, on_error) \
- for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
- if (!de) { \
- if (errno > 0) { \
- on_error; \
- } \
- break; \
- } else if (hidden_file((de)->d_name)) \
- continue; \
- else
-
-#define FOREACH_DIRENT_ALL(de, d, on_error) \
- for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \
- if (!de) { \
- if (errno > 0) { \
- on_error; \
- } \
- break; \
- } else
+#define memzero(x,l) (memset((x), 0, (l)))
+#define zero(x) (memzero(&(x), sizeof(x)))
static inline void *mempset(void *s, int c, size_t n) {
memset(s, c, n);
return (uint8_t*)s + n;
}
-char *hexmem(const void *p, size_t l);
-int unhexmem(const char *p, size_t l, void **mem, size_t *len);
-
-char *base32hexmem(const void *p, size_t l, bool padding);
-int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
-
-char *base64mem(const void *p, size_t l);
-int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
-
-char *strextend(char **x, ...) _sentinel_;
-char *strrep(const char *s, unsigned n);
-
-void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
-void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
-#define GREEDY_REALLOC(array, allocated, need) \
- greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
-#define GREEDY_REALLOC0(array, allocated, need) \
- greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0]))
-
static inline void _reset_errno_(int *saved_errno) {
errno = *saved_errno;
}
@@ -674,20 +126,6 @@ static inline int negative_errno(void) {
return -errno;
}
-struct _umask_struct_ {
- mode_t mask;
- bool quit;
-};
-
-static inline void _reset_umask_(struct _umask_struct_ *s) {
- umask(s->mask);
-};
-
-#define RUN_WITH_UMASK(mask) \
- for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \
- !_saved_umask_.quit ; \
- _saved_umask_.quit = true)
-
static inline unsigned u64log2(uint64_t n) {
#if __SIZEOF_LONG_LONG__ == 8
return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@@ -725,222 +163,15 @@ static inline unsigned log2u_round_up(unsigned x) {
return log2u(x - 1) + 1;
}
-static inline bool logind_running(void) {
- return access("/run/systemd/seats/", F_OK) >= 0;
-}
-
-#define DECIMAL_STR_WIDTH(x) \
- ({ \
- typeof(x) _x_ = (x); \
- unsigned ans = 1; \
- while (_x_ /= 10) \
- ans++; \
- ans; \
- })
-
-int unlink_noerrno(const char *path);
-
-#define alloca0(n) \
- ({ \
- char *_new_; \
- size_t _len_ = n; \
- _new_ = alloca(_len_); \
- (void *) memset(_new_, 0, _len_); \
- })
-
-/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */
-#define alloca_align(size, align) \
- ({ \
- void *_ptr_; \
- size_t _mask_ = (align) - 1; \
- _ptr_ = alloca((size) + _mask_); \
- (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \
- })
-
-#define alloca0_align(size, align) \
- ({ \
- void *_new_; \
- size_t _size_ = (size); \
- _new_ = alloca_align(_size_, (align)); \
- (void*)memset(_new_, 0, _size_); \
- })
-
-#define strjoina(a, ...) \
- ({ \
- const char *_appendees_[] = { a, __VA_ARGS__ }; \
- char *_d_, *_p_; \
- int _len_ = 0; \
- unsigned _i_; \
- for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
- _len_ += strlen(_appendees_[_i_]); \
- _p_ = _d_ = alloca(_len_ + 1); \
- for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
- _p_ = stpcpy(_p_, _appendees_[_i_]); \
- *_p_ = 0; \
- _d_; \
- })
-
bool id128_is_valid(const char *s) _pure_;
-int split_pair(const char *s, const char *sep, char **l, char **r);
-
-int shall_restore_state(void);
-
-/**
- * Normal qsort requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
- if (nmemb <= 1)
- return;
-
- assert(base);
- qsort(base, nmemb, size, compar);
-}
-
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
- if (needlelen <= 0)
- return (void*) haystack;
-
- if (haystacklen < needlelen)
- return NULL;
-
- assert(haystack);
- assert(needle);
-
- return memmem(haystack, haystacklen, needle, needlelen);
-}
-
-int proc_cmdline(char **ret);
-int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value));
-int get_proc_cmdline_key(const char *parameter, char **value);
-
int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
-int getpeercred(int fd, struct ucred *ucred);
-int getpeersec(int fd, char **ret);
-
-int writev_safe(int fd, const struct iovec *w, int j);
-
-int mkostemp_safe(char *pattern, int flags);
-int open_tmpfile(const char *path, int flags);
-
-int fd_warn_permissions(const char *path, int fd);
-
-#ifndef PERSONALITY_INVALID
-/* personality(7) documents that 0xffffffffUL is used for querying the
- * current personality, hence let's use that here as error
- * indicator. */
-#define PERSONALITY_INVALID 0xffffffffLU
-#endif
-
-unsigned long personality_from_string(const char *p);
-const char *personality_to_string(unsigned long);
-
uint64_t physical_memory(void);
-void hexdump(FILE *f, const void *p, size_t s);
-
-union file_handle_union {
- struct file_handle handle;
- char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
-};
-#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
-
int update_reboot_param_file(const char *param);
-int umount_recursive(const char *target, int flags);
-
-int bind_remount_recursive(const char *prefix, bool ro);
-
-int fflush_and_check(FILE *f);
-
-int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
-int tempfn_random(const char *p, const char *extra, char **ret);
-int tempfn_random_child(const char *p, const char *extra, char **ret);
-
-int take_password_lock(const char *root);
-
-int is_symlink(const char *path);
-int is_dir(const char *path, bool follow);
-int is_device_node(const char *path);
-
-typedef enum ExtractFlags {
- EXTRACT_RELAX = 1,
- EXTRACT_CUNESCAPE = 2,
- EXTRACT_CUNESCAPE_RELAX = 4,
- EXTRACT_QUOTES = 8,
- EXTRACT_DONT_COALESCE_SEPARATORS = 16,
-} ExtractFlags;
-
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
-int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_;
-
-int free_and_strdup(char **p, const char *s);
-
-#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
-
-#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
- for ((e) = &buffer.ev; \
- (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \
- (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len))
-
-union inotify_event_buffer {
- struct inotify_event ev;
- uint8_t raw[INOTIFY_EVENT_MAX];
-};
-
-#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
-
-int ptsname_malloc(int fd, char **ret);
-
-int openpt_in_namespace(pid_t pid, int flags);
-
-ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
-
-int fd_setcrtime(int fd, usec_t usec);
-int fd_getcrtime(int fd, usec_t *usec);
-int path_getcrtime(const char *p, usec_t *usec);
-int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
-
-int same_fd(int a, int b);
-
-int chattr_fd(int fd, unsigned value, unsigned mask);
-int chattr_path(const char *p, unsigned value, unsigned mask);
-
-int read_attr_fd(int fd, unsigned *ret);
-int read_attr_path(const char *p, unsigned *ret);
-
-#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
-
-ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
-
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
-
-int syslog_parse_priority(const char **p, int *priority, bool with_facility);
-
-void cmsg_close_all(struct msghdr *mh);
-
-int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
-
-char *shell_escape(const char *s, const char *bad);
-char *shell_maybe_quote(const char *s);
-
-int parse_mode(const char *s, mode_t *ret);
-
-int mount_move_root(const char *path);
-
-int reset_uid_gid(void);
-
-int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
-int fgetxattr_malloc(int fd, const char *name, char **value);
-
-int send_one_fd(int transport_fd, int fd);
-int receive_one_fd(int transport_fd);
+int version(void);
diff --git a/src/basic/verbs.c b/src/basic/verbs.c
index c7beccc2dc..d63062d39e 100644
--- a/src/basic/verbs.c
+++ b/src/basic/verbs.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
#include "util.h"
#include "verbs.h"
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 1fc6c1baba..ff006e96c6 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -19,18 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
+#include <string.h>
#include <unistd.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "fileio.h"
#include "process-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
#include "virt.h"
-#include "fileio.h"
static int detect_vm_cpuid(void) {
- /* Both CPUID and DMI are x86 specific interfaces... */
+ /* CPUID is an x86 specific interface. */
#if defined(__i386__) || defined(__x86_64__)
static const struct {
@@ -140,11 +144,10 @@ static int detect_vm_device_tree(void) {
}
static int detect_vm_dmi(void) {
-
- /* Both CPUID and DMI are x86 specific interfaces... */
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
static const char *const dmi_vendors[] = {
+ "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
"/sys/class/dmi/id/bios_vendor"
@@ -154,6 +157,7 @@ static int detect_vm_dmi(void) {
const char *vendor;
int id;
} dmi_vendor_table[] = {
+ { "KVM", VIRTUALIZATION_KVM },
{ "QEMU", VIRTUALIZATION_QEMU },
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMware", VIRTUALIZATION_VMWARE },
@@ -240,7 +244,7 @@ static int detect_vm_zvm(void) {
_cleanup_free_ char *t = NULL;
int r;
- r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
+ r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
if (r == -ENOENT)
return VIRTUALIZATION_NONE;
if (r < 0)
@@ -263,12 +267,7 @@ int detect_vm(void) {
if (cached_found >= 0)
return cached_found;
- /* Try xen capabilities file first, if not found try
- * high-level hypervisor sysfs file:
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
-
- r = detect_vm_xen();
+ r = detect_vm_cpuid();
if (r < 0)
return r;
if (r != VIRTUALIZATION_NONE)
@@ -280,7 +279,14 @@ int detect_vm(void) {
if (r != VIRTUALIZATION_NONE)
goto finish;
- r = detect_vm_cpuid();
+ /* x86 xen will most likely be detected by cpuid. If not (most likely
+ * because we're not an x86 guest), then we should try the xen capabilities
+ * file next. If that's not found, then we check for the high-level
+ * hypervisor sysfs file:
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */
+
+ r = detect_vm_xen();
if (r < 0)
return r;
if (r != VIRTUALIZATION_NONE)
@@ -323,6 +329,7 @@ int detect_container(void) {
{ "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT },
{ "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
{ "docker", VIRTUALIZATION_DOCKER },
+ { "rkt", VIRTUALIZATION_RKT },
};
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
@@ -410,6 +417,16 @@ int detect_virtualization(void) {
return detect_vm();
}
+int running_in_chroot(void) {
+ int ret;
+
+ ret = files_same("/proc/1/root", "/");
+ if (ret < 0)
+ return ret;
+
+ return ret == 0;
+}
+
static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_NONE] = "none",
[VIRTUALIZATION_KVM] = "kvm",
@@ -429,6 +446,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_LXC] = "lxc",
[VIRTUALIZATION_OPENVZ] = "openvz",
[VIRTUALIZATION_DOCKER] = "docker",
+ [VIRTUALIZATION_RKT] = "rkt",
[VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
};
diff --git a/src/basic/virt.h b/src/basic/virt.h
index 449e069901..aca961867c 100644
--- a/src/basic/virt.h
+++ b/src/basic/virt.h
@@ -48,6 +48,7 @@ enum {
VIRTUALIZATION_LXC,
VIRTUALIZATION_OPENVZ,
VIRTUALIZATION_DOCKER,
+ VIRTUALIZATION_RKT,
VIRTUALIZATION_CONTAINER_OTHER,
VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER,
@@ -67,5 +68,7 @@ int detect_vm(void);
int detect_container(void);
int detect_virtualization(void);
+int running_in_chroot(void);
+
const char *virtualization_to_string(int v) _const_;
int virtualization_from_string(const char *s) _pure_;
diff --git a/src/basic/web-util.c b/src/basic/web-util.c
new file mode 100644
index 0000000000..68ec04021b
--- /dev/null
+++ b/src/basic/web-util.c
@@ -0,0 +1,78 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "string-util.h"
+#include "utf8.h"
+#include "web-util.h"
+
+bool http_etag_is_valid(const char *etag) {
+ if (isempty(etag))
+ return false;
+
+ if (!endswith(etag, "\""))
+ return false;
+
+ if (!startswith(etag, "\"") && !startswith(etag, "W/\""))
+ return false;
+
+ return true;
+}
+
+bool http_url_is_valid(const char *url) {
+ const char *p;
+
+ if (isempty(url))
+ return false;
+
+ p = startswith(url, "http://");
+ if (!p)
+ p = startswith(url, "https://");
+ if (!p)
+ return false;
+
+ if (isempty(p))
+ return false;
+
+ return ascii_is_valid(p);
+}
+
+bool documentation_url_is_valid(const char *url) {
+ const char *p;
+
+ if (isempty(url))
+ return false;
+
+ if (http_url_is_valid(url))
+ return true;
+
+ p = startswith(url, "file:/");
+ if (!p)
+ p = startswith(url, "info:");
+ if (!p)
+ p = startswith(url, "man:");
+
+ if (isempty(p))
+ return false;
+
+ return ascii_is_valid(p);
+}
diff --git a/src/basic/web-util.h b/src/basic/web-util.h
new file mode 100644
index 0000000000..40c1509eb8
--- /dev/null
+++ b/src/basic/web-util.h
@@ -0,0 +1,32 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+#include "macro.h"
+
+bool http_url_is_valid(const char *url) _pure_;
+
+bool documentation_url_is_valid(const char *url) _pure_;
+
+bool http_etag_is_valid(const char *etag);
diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c
new file mode 100644
index 0000000000..6abdaedc3e
--- /dev/null
+++ b/src/basic/xattr-util.c
@@ -0,0 +1,195 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/xattr.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "sparse-endian.h"
+#include "stdio-util.h"
+#include "util.h"
+#include "xattr-util.h"
+
+int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
+ char *v;
+ size_t l;
+ ssize_t n;
+
+ assert(path);
+ assert(name);
+ assert(value);
+
+ for (l = 100; ; l = (size_t) n + 1) {
+ v = new0(char, l);
+ if (!v)
+ return -ENOMEM;
+
+ if (allow_symlink)
+ n = lgetxattr(path, name, v, l);
+ else
+ n = getxattr(path, name, v, l);
+
+ if (n >= 0 && (size_t) n < l) {
+ *value = v;
+ return n;
+ }
+
+ free(v);
+
+ if (n < 0 && errno != ERANGE)
+ return -errno;
+
+ if (allow_symlink)
+ n = lgetxattr(path, name, NULL, 0);
+ else
+ n = getxattr(path, name, NULL, 0);
+ if (n < 0)
+ return -errno;
+ }
+}
+
+int fgetxattr_malloc(int fd, const char *name, char **value) {
+ char *v;
+ size_t l;
+ ssize_t n;
+
+ assert(fd >= 0);
+ assert(name);
+ assert(value);
+
+ for (l = 100; ; l = (size_t) n + 1) {
+ v = new0(char, l);
+ if (!v)
+ return -ENOMEM;
+
+ n = fgetxattr(fd, name, v, l);
+
+ if (n >= 0 && (size_t) n < l) {
+ *value = v;
+ return n;
+ }
+
+ free(v);
+
+ if (n < 0 && errno != ERANGE)
+ return -errno;
+
+ n = fgetxattr(fd, name, NULL, 0);
+ if (n < 0)
+ return -errno;
+ }
+}
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+ _cleanup_close_ int fd = -1;
+ ssize_t l;
+
+ /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
+
+ fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+ if (fd < 0)
+ return -errno;
+
+ xsprintf(fn, "/proc/self/fd/%i", fd);
+
+ l = getxattr(fn, attribute, value, size);
+ if (l < 0)
+ return -errno;
+
+ return l;
+}
+
+static int parse_crtime(le64_t le, usec_t *usec) {
+ uint64_t u;
+
+ assert(usec);
+
+ u = le64toh(le);
+ if (u == 0 || u == (uint64_t) -1)
+ return -EIO;
+
+ *usec = (usec_t) u;
+ return 0;
+}
+
+int fd_getcrtime(int fd, usec_t *usec) {
+ le64_t le;
+ ssize_t n;
+
+ assert(fd >= 0);
+ assert(usec);
+
+ /* Until Linux gets a real concept of birthtime/creation time,
+ * let's fake one with xattrs */
+
+ n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le));
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
+ le64_t le;
+ ssize_t n;
+
+ n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags);
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int path_getcrtime(const char *p, usec_t *usec) {
+ le64_t le;
+ ssize_t n;
+
+ assert(p);
+ assert(usec);
+
+ n = getxattr(p, "user.crtime_usec", &le, sizeof(le));
+ if (n < 0)
+ return -errno;
+ if (n != sizeof(le))
+ return -EIO;
+
+ return parse_crtime(le, usec);
+}
+
+int fd_setcrtime(int fd, usec_t usec) {
+ le64_t le;
+
+ assert(fd >= 0);
+
+ if (usec <= 0)
+ usec = now(CLOCK_REALTIME);
+
+ le = htole64((uint64_t) usec);
+ if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h
new file mode 100644
index 0000000000..cf4cb12a25
--- /dev/null
+++ b/src/basic/xattr-util.h
@@ -0,0 +1,38 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "time-util.h"
+
+int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
+int fgetxattr_malloc(int fd, const char *name, char **value);
+
+ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
+
+int fd_setcrtime(int fd, usec_t usec);
+
+int fd_getcrtime(int fd, usec_t *usec);
+int path_getcrtime(const char *p, usec_t *usec);
+int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
diff --git a/src/basic/xml.c b/src/basic/xml.c
index 15c629b188..8126bce212 100644
--- a/src/basic/xml.c
+++ b/src/basic/xml.c
@@ -21,6 +21,7 @@
#include <string.h>
+#include "string-util.h"
#include "util.h"
#include "xml.h"
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 1e216f52bd..42ad0adb02 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -19,20 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "log.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
-#include "conf-files.h"
-#include "fileio.h"
-#include "build.h"
static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
@@ -91,8 +94,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
if (feof(f))
break;
- log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
}
p = strstrip(l);
@@ -143,9 +145,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index ac1711b318..4cf42d17f3 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -20,28 +20,32 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
#include <assert.h>
-#include <sys/statfs.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <dirent.h>
+#include <blkid/blkid.h>
#include <ctype.h>
-#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
#include <ftw.h>
+#include <getopt.h>
+#include <limits.h>
#include <stdbool.h>
-#include <blkid/blkid.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "blkid-util.h"
#include "efivars.h"
-#include "build.h"
-#include "util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "locale-util.h"
#include "rm-rf.h"
-#include "blkid-util.h"
+#include "string-util.h"
+#include "util.h"
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
struct statfs sfs;
@@ -967,8 +971,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- printf(VERSION "\n");
- return 0;
+ return version();
case ARG_PATH:
arg_path = optarg;
diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c
index 83ad90c222..852febb225 100644
--- a/src/bootchart/bootchart.c
+++ b/src/bootchart/bootchart.c
@@ -33,30 +33,37 @@
***/
-#include <sys/resource.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
+#include <sys/resource.h>
#include <time.h>
-#include <getopt.h>
-#include <limits.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include "systemd/sd-journal.h"
+#include <unistd.h>
-#include "util.h"
+#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "bootchart.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "io-util.h"
+#include "list.h"
#include "macro.h"
-#include "conf-parser.h"
-#include "strxcpyx.h"
+#include "parse-util.h"
#include "path-util.h"
#include "store.h"
+#include "string-util.h"
+#include "strxcpyx.h"
#include "svg.h"
-#include "bootchart.h"
-#include "list.h"
+#include "util.h"
static int exiting = 0;
diff --git a/src/bootchart/store.c b/src/bootchart/store.c
index caa97b97fc..c1b1e77e44 100644
--- a/src/bootchart/store.c
+++ b/src/bootchart/store.c
@@ -22,22 +22,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <time.h>
+#include <unistd.h>
-#include "util.h"
-#include "time-util.h"
-#include "strxcpyx.h"
-#include "store.h"
+#include "alloc-util.h"
#include "bootchart.h"
#include "cgroup-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "parse-util.h"
+#include "store.h"
+#include "string-util.h"
+#include "strxcpyx.h"
+#include "time-util.h"
+#include "util.h"
/*
* Alloc a static 4k buffer for stdio - primarily used to increase
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index c66f12e3a6..05330c0577 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -30,6 +30,8 @@
#include <sys/utsname.h>
#include <fcntl.h>
+#include "alloc-util.h"
+#include "architecture.h"
#include "util.h"
#include "fileio.h"
#include "macro.h"
@@ -38,6 +40,7 @@
#include "bootchart.h"
#include "list.h"
#include "utf8.h"
+#include "fd-util.h"
#define time_to_graph(t) ((t) * arg_scale_x)
#define ps_to_graph(n) ((n) * arg_scale_y)
@@ -147,7 +150,7 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start,
_cleanup_free_ char *model = NULL;
_cleanup_free_ char *buf = NULL;
char date[256] = "Unknown";
- char *cpu;
+ const char *cpu;
char *c;
time_t t;
int r;
@@ -188,20 +191,11 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start,
assert_se(r > 0);
/* CPU type */
- r = read_full_file("/proc/cpuinfo", &buf, NULL);
+ r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf);
if (r < 0)
- return log_error_errno(r, "Unable to read cpuinfo: %m");
-
- cpu = strstr(buf, "model name");
- if (!cpu) {
- log_error("Unable to read module name from cpuinfo.\n");
- return -ENOENT;
- }
-
- cpu += 13;
- c = strchr(cpu, '\n');
- if (c)
- *c = '\0';
+ cpu = "Unknown";
+ else
+ cpu = buf;
fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
uts.nodename, date);
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index 3cc3b33ae7..6a7134644f 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -22,26 +22,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <sys/prctl.h>
-#include <stddef.h>
#include <getopt.h>
#include <pthread.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
-#include "log.h"
-#include "util.h"
#include "sd-daemon.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
-#include "build.h"
-#include "strv.h"
-#include "def.h"
-#include "capability.h"
#include "bus-xml-policy.h"
-#include "proxy.h"
+#include "capability-util.h"
+#include "def.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "log.h"
+#include "proxy.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
static char *arg_address = NULL;
static char **arg_configuration = NULL;
@@ -85,11 +89,11 @@ static void *run_client(void *userdata) {
int r;
r = proxy_new(&p, c->fd, c->fd, arg_address);
+ c->fd = -1;
+
if (r < 0)
goto exit;
- c->fd = -1;
-
/* set comm to "p$PIDu$UID" and suffix with '*' if truncated */
r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid);
if (r >= (ssize_t)sizeof(comm))
@@ -116,13 +120,12 @@ static int loop_clients(int accept_fd, uid_t bus_uid) {
int r;
r = pthread_attr_init(&attr);
- if (r < 0) {
- return log_error_errno(errno, "Cannot initialize pthread attributes: %m");
- }
+ if (r != 0)
+ return log_error_errno(r, "Cannot initialize pthread attributes: %m");
r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (r < 0) {
- r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m");
+ if (r != 0) {
+ r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m");
goto finish;
}
@@ -156,8 +159,8 @@ static int loop_clients(int accept_fd, uid_t bus_uid) {
c->bus_uid = bus_uid;
r = pthread_create(&tid, &attr, run_client, c);
- if (r < 0) {
- log_error("Cannot spawn thread: %m");
+ if (r != 0) {
+ log_warning_errno(r, "Cannot spawn thread, ignoring: %m");
client_context_free(c);
continue;
}
@@ -215,9 +218,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ADDRESS:
r = free_and_strdup(&arg_address, optarg);
diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c
index 9a3b451c56..f0834e9525 100644
--- a/src/bus-proxyd/bus-xml-policy.c
+++ b/src/bus-proxyd/bus-xml-policy.c
@@ -19,15 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "xml.h"
-#include "fileio.h"
-#include "strv.h"
-#include "set.h"
-#include "conf-files.h"
+#include "sd-login.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-xml-policy.h"
-#include "sd-login.h"
+#include "conf-files.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "locale-util.h"
+#include "set.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "xml.h"
static void policy_item_free(PolicyItem *i) {
assert(i);
@@ -1186,14 +1192,14 @@ int shared_policy_new(SharedPolicy **out) {
return log_oom();
r = pthread_mutex_init(&sp->lock, NULL);
- if (r < 0) {
- log_error_errno(r, "Cannot initialize shared policy mutex: %m");
+ if (r != 0) {
+ r = log_error_errno(r, "Cannot initialize shared policy mutex: %m");
goto exit_free;
}
r = pthread_rwlock_init(&sp->rwlock, NULL);
- if (r < 0) {
- log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
+ if (r != 0) {
+ r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
goto exit_mutex;
}
diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c
index fa4aee691a..2e8bd83efd 100644
--- a/src/bus-proxyd/driver.c
+++ b/src/bus-proxyd/driver.c
@@ -21,21 +21,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
#include <stddef.h>
+#include <string.h>
-#include "util.h"
#include "sd-bus.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "strv.h"
-#include "set.h"
#include "driver.h"
+#include "env-util.h"
#include "proxy.h"
+#include "set.h"
+#include "strv.h"
#include "synthesize.h"
-#include "env-util.h"
+#include "util.h"
static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *c = NULL;
diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c
index 88800f5e7f..db399b24f2 100644
--- a/src/bus-proxyd/proxy.c
+++ b/src/bus-proxyd/proxy.c
@@ -22,27 +22,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <string.h>
#include <errno.h>
#include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
-#include "log.h"
-#include "util.h"
-#include "sd-daemon.h"
#include "sd-bus.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "bus-control.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "strv.h"
-#include "bus-control.h"
-#include "set.h"
#include "bus-xml-policy.h"
#include "driver.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "log.h"
#include "proxy.h"
+#include "set.h"
+#include "strv.h"
#include "synthesize.h"
-#include "formats-util.h"
+#include "user-util.h"
+#include "util.h"
static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
_cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
@@ -100,18 +104,24 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha
return 0;
}
-static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) {
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
+static int proxy_create_local(Proxy *p, bool negotiate_fds) {
sd_id128_t server_id;
+ sd_bus *b;
int r;
r = sd_bus_new(&b);
if (r < 0)
return log_error_errno(r, "Failed to allocate bus: %m");
- r = sd_bus_set_fd(b, in_fd, out_fd);
- if (r < 0)
+ r = sd_bus_set_fd(b, p->local_in, p->local_out);
+ if (r < 0) {
+ sd_bus_unref(b);
return log_error_errno(r, "Failed to set fds: %m");
+ }
+
+ /* The fds are now owned by the bus, and we indicate that by
+ * storing the bus object in the proxy object. */
+ p->local_bus = b;
r = sd_bus_get_bus_id(p->destination_bus, &server_id);
if (r < 0)
@@ -139,8 +149,6 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd
if (r < 0)
return log_error_errno(r, "Failed to start bus client: %m");
- p->local_bus = b;
- b = NULL;
return 0;
}
@@ -224,9 +232,17 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
bool is_unix;
int r;
+ /* This takes possession/destroys the file descriptors passed
+ * in even on failure. The caller should hence forget about
+ * the fds in all cases after calling this function and not
+ * close them. */
+
p = new0(Proxy, 1);
- if (!p)
+ if (!p) {
+ safe_close(in_fd);
+ safe_close(out_fd);
return log_oom();
+ }
p->local_in = in_fd;
p->local_out = out_fd;
@@ -247,7 +263,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
if (r < 0)
return r;
- r = proxy_create_local(p, in_fd, out_fd, is_unix);
+ r = proxy_create_local(p, is_unix);
if (r < 0)
return r;
@@ -257,6 +273,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
*out = p;
p = NULL;
+
return 0;
}
@@ -273,7 +290,14 @@ Proxy *proxy_free(Proxy *p) {
free(activation);
}
- sd_bus_flush_close_unref(p->local_bus);
+ if (p->local_bus)
+ sd_bus_flush_close_unref(p->local_bus);
+ else {
+ safe_close(p->local_in);
+ if (p->local_out != p->local_in)
+ safe_close(p->local_out);
+ }
+
sd_bus_flush_close_unref(p->destination_bus);
set_free_free(p->owned_names);
free(p);
diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h
index 6aac650ac9..7b2e5d422f 100644
--- a/src/bus-proxyd/proxy.h
+++ b/src/bus-proxyd/proxy.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "bus-xml-policy.h"
typedef struct Proxy Proxy;
diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c
index f275f6705f..6e47884209 100644
--- a/src/bus-proxyd/stdio-bridge.c
+++ b/src/bus-proxyd/stdio-bridge.c
@@ -21,23 +21,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <stddef.h>
#include <getopt.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
-#include "log.h"
-#include "util.h"
#include "sd-daemon.h"
#include "sd-bus.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-util.h"
-#include "build.h"
-#include "strv.h"
#include "def.h"
-#include "proxy.h"
#include "formats-util.h"
+#include "log.h"
+#include "proxy.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
static char *arg_address = NULL;
static char *arg_command_line_buffer = NULL;
@@ -86,9 +88,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ADDRESS: {
char *a;
diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c
index 15d99103f6..7f1f9dc28d 100644
--- a/src/bus-proxyd/synthesize.c
+++ b/src/bus-proxyd/synthesize.c
@@ -23,13 +23,14 @@
#include <stddef.h>
-#include "util.h"
#include "sd-bus.h"
+
#include "bus-internal.h"
+#include "bus-match.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "bus-match.h"
#include "synthesize.h"
+#include "util.h"
int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
int r;
diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h
index b596daddf2..ddfe2fd266 100644
--- a/src/bus-proxyd/synthesize.h
+++ b/src/bus-proxyd/synthesize.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "proxy.h"
int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c
index d19d0e1b60..1f465edd91 100644
--- a/src/bus-proxyd/test-bus-xml-policy.c
+++ b/src/bus-proxyd/test-bus-xml-policy.c
@@ -19,15 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
#include <stddef.h>
+#include <unistd.h>
-#include "log.h"
-#include "util.h"
#include "sd-bus.h"
-#include "strv.h"
+
+#include "alloc-util.h"
#include "bus-xml-policy.h"
+#include "log.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
static int test_policy_load(Policy *p, const char *name) {
_cleanup_free_ char *path = NULL;
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index ec4215f741..4e9a76a100 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -19,25 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <unistd.h>
#include <errno.h>
#include <getopt.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+
+#include "sd-bus.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
+#include "fileio.h"
#include "log.h"
-#include "path-util.h"
-#include "util.h"
-#include "pager.h"
-#include "build.h"
#include "output-mode.h"
-#include "fileio.h"
-#include "sd-bus.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "pager.h"
+#include "path-util.h"
#include "unit-name.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_kernel_threads = false;
@@ -89,9 +90,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -147,7 +146,7 @@ static int get_cgroup_root(char **ret) {
if (!path)
return log_oom();
- r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
index 612bc8fdec..e48234f075 100644
--- a/src/cgroups-agent/cgroups-agent.c
+++ b/src/cgroups-agent/cgroups-agent.c
@@ -22,8 +22,9 @@
#include <stdlib.h>
#include "sd-bus.h"
-#include "log.h"
+
#include "bus-util.h"
+#include "log.h"
int main(int argc, char *argv[]) {
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
@@ -43,7 +44,7 @@ int main(int argc, char *argv[]) {
* this to avoid an activation loop when we start dbus when we
* are called when the dbus service is shut down. */
- r = bus_open_system_systemd(&bus);
+ r = bus_connect_system_systemd(&bus);
if (r < 0) {
/* If we couldn't connect we assume this was triggered
* while systemd got restarted/transitioned from
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 9cf13cf57d..eea8aea76b 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -19,27 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
#include <alloca.h>
+#include <errno.h>
#include <getopt.h>
#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-#include "path-util.h"
-#include "terminal-util.h"
-#include "process-util.h"
-#include "util.h"
-#include "hashmap.h"
-#include "cgroup-util.h"
-#include "build.h"
-#include "fileio.h"
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "terminal-util.h"
#include "unit-name.h"
+#include "util.h"
typedef struct Group {
char *path;
@@ -696,9 +699,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_CPU_TYPE:
if (optarg) {
@@ -863,7 +864,7 @@ static int get_cgroup_root(char **ret) {
if (!path)
return log_oom();
- r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index 5a18e263a8..3ae46d8cfb 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -30,6 +30,7 @@
#include "log.h"
#include "util.h"
+#include "fd-util.h"
static bool initialized = false;
static int audit_fd;
diff --git a/src/core/automount.c b/src/core/automount.c
index c88e3311bc..4c229247c5 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -20,29 +20,37 @@
***/
#include <errno.h>
-#include <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <limits.h>
+#include <linux/auto_dev-ioctl.h>
+#include <linux/auto_fs4.h>
#include <sys/epoll.h>
+#include <sys/mount.h>
#include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
+#include <unistd.h>
-#include "unit.h"
+#include "alloc-util.h"
+#include "async.h"
#include "automount.h"
-#include "mount.h"
-#include "unit-name.h"
-#include "special.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "dbus-automount.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
#include "label.h"
#include "mkdir.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "dbus-automount.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "formats-util.h"
#include "process-util.h"
-#include "async.h"
+#include "special.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_DEAD] = UNIT_INACTIVE,
@@ -81,26 +89,11 @@ static void automount_init(Unit *u) {
UNIT(a)->ignore_on_isolate = true;
}
-static void repeat_unmount(const char *path) {
- assert(path);
-
- for (;;) {
- /* If there are multiple mounts on a mount point, this
- * removes them all */
-
- if (umount2(path, MNT_DETACH) >= 0)
- continue;
-
- if (errno != EINVAL)
- log_error_errno(errno, "Failed to unmount: %m");
-
- break;
- }
-}
-
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void unmount_autofs(Automount *a) {
+ int r;
+
assert(a);
if (a->pipe_fd < 0)
@@ -116,8 +109,11 @@ static void unmount_autofs(Automount *a) {
* around */
if (a->where &&
(UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
- UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
- repeat_unmount(a->where);
+ UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) {
+ r = repeat_unmount(a->where, MNT_DETACH);
+ if (r < 0)
+ log_error_errno(r, "Failed to unmount: %m");
+ }
}
static void automount_done(Unit *u) {
@@ -137,13 +133,12 @@ static void automount_done(Unit *u) {
static int automount_add_mount_links(Automount *a) {
_cleanup_free_ char *parent = NULL;
- int r;
assert(a);
- r = path_get_parent(a->where, &parent);
- if (r < 0)
- return r;
+ parent = dirname_malloc(a->where);
+ if (!parent)
+ return -ENOMEM;
return unit_require_mounts_for(UNIT(a), parent);
}
@@ -608,12 +603,16 @@ static void automount_enter_waiting(Automount *a) {
return;
fail:
+ log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
+
safe_close_pair(p);
- if (mounted)
- repeat_unmount(a->where);
+ if (mounted) {
+ r = repeat_unmount(a->where, MNT_DETACH);
+ if (r < 0)
+ log_error_errno(r, "Failed to unmount, ignoring: %m");
+ }
- log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
@@ -774,8 +773,9 @@ static int automount_stop(Unit *u) {
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
- void *p;
Iterator i;
+ void *p;
+ int r;
assert(a);
assert(f);
@@ -790,15 +790,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
SET_FOREACH(p, a->expire_tokens, i)
unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
- if (a->pipe_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, a->pipe_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
+ if (r < 0)
+ return r;
return 0;
}
@@ -1024,15 +1018,6 @@ static bool automount_supported(void) {
return supported;
}
-static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = "dead",
- [AUTOMOUNT_WAITING] = "waiting",
- [AUTOMOUNT_RUNNING] = "running",
- [AUTOMOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources"
diff --git a/src/core/automount.h b/src/core/automount.h
index 2a50fef68d..43ea9f772d 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -25,15 +25,6 @@ typedef struct Automount Automount;
#include "unit.h"
-typedef enum AutomountState {
- AUTOMOUNT_DEAD,
- AUTOMOUNT_WAITING,
- AUTOMOUNT_RUNNING,
- AUTOMOUNT_FAILED,
- _AUTOMOUNT_STATE_MAX,
- _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
typedef enum AutomountResult {
AUTOMOUNT_SUCCESS,
AUTOMOUNT_FAILURE_RESOURCES,
@@ -66,8 +57,5 @@ extern const UnitVTable automount_vtable;
int automount_update_mount(Automount *a, MountState old_state, MountState state);
-const char* automount_state_to_string(AutomountState i) _const_;
-AutomountState automount_state_from_string(const char *s) _pure_;
-
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c
index 0c4b3e7c8b..d22a80c91f 100644
--- a/src/core/bus-endpoint.c
+++ b/src/core/bus-endpoint.c
@@ -19,10 +19,11 @@
#include <stdlib.h>
-#include "kdbus.h"
+#include "alloc-util.h"
+#include "bus-endpoint.h"
#include "bus-kernel.h"
#include "bus-policy.h"
-#include "bus-endpoint.h"
+#include "kdbus.h"
int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c
index a6a8fcd4d3..4907c268e8 100644
--- a/src/core/bus-policy.c
+++ b/src/core/bus-policy.c
@@ -19,10 +19,13 @@
#include <stdlib.h>
-#include "kdbus.h"
-#include "util.h"
+#include "alloc-util.h"
#include "bus-kernel.h"
#include "bus-policy.h"
+#include "kdbus.h"
+#include "string-table.h"
+#include "user-util.h"
+#include "util.h"
int bus_kernel_translate_access(BusPolicyAccess access) {
assert(access >= 0);
diff --git a/src/core/busname.c b/src/core/busname.c
index 4020e9dd3c..68508e20d2 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -21,17 +21,23 @@
#include <sys/mman.h>
-#include "special.h"
-#include "formats-util.h"
-#include "signal-util.h"
-#include "bus-kernel.h"
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-kernel.h"
+#include "bus-policy.h"
#include "bus-util.h"
+#include "busname.h"
+#include "dbus-busname.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "kdbus.h"
-#include "bus-policy.h"
+#include "parse-util.h"
+#include "process-util.h"
#include "service.h"
-#include "dbus-busname.h"
-#include "busname.h"
+#include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
[BUSNAME_DEAD] = UNIT_INACTIVE,
@@ -358,10 +364,9 @@ static int busname_coldplug(Unit *u) {
if (n->deserialized_state == n->state)
return 0;
- if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
-
- if (n->control_pid <= 0)
- return -EBADMSG;
+ if (n->control_pid > 0 &&
+ pid_is_unwaited(n->control_pid) &&
+ IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
r = unit_watch_pid(UNIT(n), n->control_pid);
if (r < 0)
@@ -585,6 +590,12 @@ static void busname_enter_running(BusName *n) {
}
if (!pending) {
+ if (!UNIT_ISSET(n->service)) {
+ log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
+ r = -ENOENT;
+ goto fail;
+ }
+
r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
if (r < 0)
goto fail;
@@ -656,6 +667,7 @@ static int busname_stop(Unit *u) {
static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
BusName *n = BUSNAME(u);
+ int r;
assert(n);
assert(f);
@@ -667,15 +679,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
if (n->control_pid > 0)
unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid);
- if (n->starter_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, n->starter_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd);
+ if (r < 0)
+ return r;
return 0;
}
@@ -991,19 +997,6 @@ static bool busname_supported(void) {
return supported;
}
-static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = "dead",
- [BUSNAME_MAKING] = "making",
- [BUSNAME_REGISTERED] = "registered",
- [BUSNAME_LISTENING] = "listening",
- [BUSNAME_RUNNING] = "running",
- [BUSNAME_SIGTERM] = "sigterm",
- [BUSNAME_SIGKILL] = "sigkill",
- [BUSNAME_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
-
static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_SUCCESS] = "success",
[BUSNAME_FAILURE_RESOURCES] = "resources",
diff --git a/src/core/busname.h b/src/core/busname.h
index 69528a2aef..46f7b6f097 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -24,19 +24,7 @@
typedef struct BusName BusName;
typedef struct BusNamePolicy BusNamePolicy;
-
-typedef enum BusNameState {
- BUSNAME_DEAD,
- BUSNAME_MAKING,
- BUSNAME_REGISTERED,
- BUSNAME_LISTENING,
- BUSNAME_RUNNING,
- BUSNAME_SIGTERM,
- BUSNAME_SIGKILL,
- BUSNAME_FAILED,
- _BUSNAME_STATE_MAX,
- _BUSNAME_STATE_INVALID = -1
-} BusNameState;
+#include "unit.h"
typedef enum BusNameResult {
BUSNAME_SUCCESS,
@@ -77,8 +65,5 @@ struct BusName {
extern const UnitVTable busname_vtable;
-const char* busname_state_to_string(BusNameState i) _const_;
-BusNameState busname_state_from_string(const char *s) _pure_;
-
const char* busname_result_to_string(BusNameResult i) _const_;
BusNameResult busname_result_from_string(const char *s) _pure_;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 0c790c33da..bed01fde21 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -22,12 +22,18 @@
#include <fcntl.h>
#include <fnmatch.h>
+#include "alloc-util.h"
#include "cgroup-util.h"
+#include "cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "special.h"
-
-#include "cgroup.h"
+#include "string-table.h"
+#include "string-util.h"
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
@@ -1203,7 +1209,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
continue;
/* Ignore processes that aren't our kids */
- if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+ if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
continue;
if (pid != 0)
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index 5162ce34cb..45f2c2ffd6 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -20,8 +20,9 @@
***/
#include "automount.h"
-#include "dbus-automount.h"
#include "bus-util.h"
+#include "string-util.h"
+#include "dbus-automount.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
index b1ceb05b1a..05ac89c3c0 100644
--- a/src/core/dbus-busname.c
+++ b/src/core/dbus-busname.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
+#include "bus-util.h"
#include "busname.h"
+#include "string-util.h"
+#include "unit.h"
#include "dbus-busname.h"
-#include "bus-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index f334dc928d..3fd295baa9 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-util.h"
-#include "path-util.h"
#include "cgroup-util.h"
#include "cgroup.h"
#include "dbus-cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
@@ -421,7 +424,9 @@ int bus_cgroup_set_property(
fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
}
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
@@ -495,7 +500,9 @@ int bus_cgroup_set_property(
LIST_FOREACH(device_weights, a, c->blockio_device_weights)
fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
@@ -640,7 +647,9 @@ int bus_cgroup_set_property(
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h
index c2a3910f3d..9dc187c066 100644
--- a/src/core/dbus-cgroup.h
+++ b/src/core/dbus-cgroup.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "cgroup.h"
extern const sd_bus_vtable bus_cgroup_vtable[];
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 868c8cc05a..db4206a523 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -25,22 +25,28 @@
#include <seccomp.h>
#endif
+#include "af-list.h"
+#include "alloc-util.h"
#include "bus-util.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "fileio.h"
-#include "execute.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "dbus-execute.h"
#include "env-util.h"
-#include "af-list.h"
+#include "execute.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "ioprio.h"
+#include "missing.h"
#include "namespace.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "dbus-execute.h"
-
+#include "process-util.h"
+#include "rlimit-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "strv.h"
+#include "syslog-util.h"
+#include "utf8.h"
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
@@ -83,45 +89,6 @@ static int property_get_environment_files(
return sd_bus_message_close_container(reply);
}
-static int property_get_rlimit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- struct rlimit *rl;
- uint64_t u;
- rlim_t x;
-
- assert(bus);
- assert(reply);
- assert(userdata);
-
- rl = *(struct rlimit**) userdata;
- if (rl)
- x = rl->rlim_max;
- else {
- struct rlimit buf = {};
- int z;
-
- z = rlimit_from_string(property);
- assert(z >= 0);
-
- getrlimit(z, &buf);
- x = buf.rlim_max;
- }
-
- /* rlim_t might have different sizes, let's map
- * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
- * all archs */
- u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
-
- return sd_bus_message_append(reply, "t", u);
-}
-
static int property_get_oom_score_adjust(
sd_bus *bus,
const char *path,
@@ -146,7 +113,7 @@ static int property_get_oom_score_adjust(
n = 0;
if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
- safe_atoi(t, &n);
+ safe_atoi32(t, &n);
}
return sd_bus_message_append(reply, "i", n);
@@ -595,28 +562,91 @@ static int property_get_address_families(
return sd_bus_message_close_container(reply);
}
+static int property_get_working_directory(
+ 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;
+ const char *wd;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ if (c->working_directory_home)
+ wd = "~";
+ else
+ wd = c->working_directory;
+
+ if (c->working_directory_missing_ok)
+ wd = strjoina("!", wd);
+
+ return sd_bus_message_append(reply, "s", wd);
+}
+
+static int property_get_syslog_level(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
+}
+
+static int property_get_syslog_facility(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -637,6 +667,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -829,7 +861,64 @@ int bus_exec_context_set_transient_property(
}
return 1;
+ } else if (streq(name, "SyslogIdentifier")) {
+ const char *id;
+
+ r = sd_bus_message_read(message, "s", &id);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+
+ if (isempty(id)) {
+ c->syslog_identifier = mfree(c->syslog_identifier);
+ } else {
+ char *t;
+
+ t = strdup(id);
+ if (!t)
+ return -ENOMEM;
+
+ free(c->syslog_identifier);
+ c->syslog_identifier = t;
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogLevel")) {
+ int level;
+
+ r = sd_bus_message_read(message, "i", &level);
+ if (r < 0)
+ return r;
+
+ if (!log_level_is_valid(level))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
+ unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogFacility")) {
+ int facility;
+
+ r = sd_bus_message_read(message, "i", &facility);
+ if (r < 0)
+ return r;
+
+ if (!log_facility_unshifted_is_valid(facility))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
+ }
+
+ return 1;
} else if (streq(name, "Nice")) {
int n;
@@ -847,8 +936,7 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (STR_IN_SET(name,
- "TTYPath", "WorkingDirectory", "RootDirectory")) {
+ } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) {
const char *s;
r = sd_bus_message_read(message, "s", &s);
@@ -859,24 +947,51 @@ int bus_exec_context_set_transient_property(
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
if (mode != UNIT_CHECK) {
- char *t;
+ if (streq(name, "TTYPath"))
+ r = free_and_strdup(&c->tty_path, s);
+ else {
+ assert(streq(name, "RootDirectory"));
+ r = free_and_strdup(&c->root_directory, s);
+ }
+ if (r < 0)
+ return r;
- t = strdup(s);
- if (!t)
- return -ENOMEM;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "WorkingDirectory")) {
+ const char *s;
+ bool missing_ok;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ if (s[0] == '-') {
+ missing_ok = true;
+ s++;
+ } else
+ missing_ok = false;
+
+ if (!streq(s, "~") && !path_is_absolute(s))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
+
+ if (mode != UNIT_CHECK) {
+ if (streq(s, "~")) {
+ c->working_directory = mfree(c->working_directory);
+ c->working_directory_home = true;
+ } else {
+ r = free_and_strdup(&c->working_directory, s);
+ if (r < 0)
+ return r;
- if (streq(name, "TTYPath")) {
- free(c->tty_path);
- c->tty_path = t;
- } else if (streq(name, "WorkingDirectory")) {
- free(c->working_directory);
- c->working_directory = t;
- } else if (streq(name, "RootDirectory")) {
- free(c->root_directory);
- c->root_directory = t;
+ c->working_directory_home = false;
}
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ c->working_directory_missing_ok = missing_ok;
+ unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
}
return 1;
@@ -945,7 +1060,7 @@ int bus_exec_context_set_transient_property(
} else if (STR_IN_SET(name,
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
"PrivateTmp", "PrivateDevices", "PrivateNetwork",
- "NoNewPrivileges")) {
+ "NoNewPrivileges", "SyslogLevelPrefix")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -967,6 +1082,8 @@ int bus_exec_context_set_transient_property(
c->private_network = b;
else if (streq(name, "NoNewPrivileges"))
c->no_new_privileges = b;
+ else if (streq(name, "SyslogLevelPrefix"))
+ c->syslog_level_prefix = b;
unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
}
@@ -1044,18 +1161,267 @@ int bus_exec_context_set_transient_property(
_cleanup_free_ char *joined = NULL;
char **e;
- e = strv_env_merge(2, c->environment, l);
- if (!e)
- return -ENOMEM;
+ if (strv_length(l) == 0) {
+ c->environment = strv_free(c->environment);
+ unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
+ } else {
+ e = strv_env_merge(2, c->environment, l);
+ if (!e)
+ return -ENOMEM;
- strv_free(c->environment);
- c->environment = e;
+ strv_free(c->environment);
+ c->environment = e;
- joined = strv_join_quoted(c->environment);
- if (!joined)
- return -ENOMEM;
+ joined = strv_join_quoted(c->environment);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+ }
+ }
+
+ return 1;
+
+ } else if (streq(name, "TimerSlackNSec")) {
+
+ nsec_t n;
+
+ r = sd_bus_message_read(message, "t", &n);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->timer_slack_nsec = n;
+ unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+ }
+
+ return 1;
+
+ } else if (streq(name, "OOMScoreAdjust")) {
+ int oa;
+
+ r = sd_bus_message_read(message, "i", &oa);
+ if (r < 0)
+ return r;
+
+ if (!oom_score_adjust_is_valid(oa))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
- unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+ if (mode != UNIT_CHECK) {
+ c->oom_score_adjust = oa;
+ c->oom_score_adjust_set = true;
+ unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa);
+ }
+
+ return 1;
+
+ } else if (streq(name, "EnvironmentFiles")) {
+
+ _cleanup_free_ char *joined = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char **l = NULL;
+ size_t size = 0;
+ char **i;
+
+ r = sd_bus_message_enter_container(message, 'a', "(sb)");
+ if (r < 0)
+ return r;
+
+ f = open_memstream(&joined, &size);
+ if (!f)
+ return -ENOMEM;
+
+ STRV_FOREACH(i, c->environment_files)
+ fprintf(f, "EnvironmentFile=%s\n", *i);
+
+ while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
+ const char *path;
+ int b;
+
+ r = sd_bus_message_read(message, "sb", &path, &b);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (!isempty(path) && !path_is_absolute(path))
+ return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
+
+ if (mode != UNIT_CHECK) {
+ char *buf = NULL;
+
+ buf = strjoin(b ? "-" : "", path, NULL);
+ if (!buf)
+ return -ENOMEM;
+
+ fprintf(f, "EnvironmentFile=%s\n", buf);
+
+ r = strv_consume(&l, buf);
+ if (r < 0)
+ return r;
+ }
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (strv_isempty(l)) {
+ c->environment_files = strv_free(c->environment_files);
+ unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n");
+ } else {
+ r = strv_extend_strv(&c->environment_files, l, true);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private(u, mode, name, joined);
+ }
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+
+ _cleanup_strv_free_ char **l = NULL;
+ char ***dirs;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ int offset;
+ if (!utf8_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+
+ offset = **p == '-';
+ if (!path_is_absolute(*p + offset))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+ }
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (streq(name, "ReadWriteDirectories"))
+ dirs = &c->read_write_dirs;
+ else if (streq(name, "ReadOnlyDirectories"))
+ dirs = &c->read_only_dirs;
+ else if (streq(name, "InaccessibleDirectories"))
+ dirs = &c->inaccessible_dirs;
+
+ if (strv_length(l) == 0) {
+ *dirs = strv_free(*dirs);
+ unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ } else {
+ r = strv_extend_strv(dirs, l, true);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join_quoted(*dirs);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ }
+
+ }
+
+ return 1;
+
+ } else if (streq(name, "ProtectSystem")) {
+ const char *s;
+ ProtectSystem ps;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(s);
+ if (r > 0)
+ ps = PROTECT_SYSTEM_YES;
+ else if (r == 0)
+ ps = PROTECT_SYSTEM_NO;
+ else {
+ ps = protect_system_from_string(s);
+ if (ps < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value");
+ }
+
+ if (mode != UNIT_CHECK) {
+ c->protect_system = ps;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "ProtectHome")) {
+ const char *s;
+ ProtectHome ph;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(s);
+ if (r > 0)
+ ph = PROTECT_HOME_YES;
+ else if (r == 0)
+ ph = PROTECT_HOME_NO;
+ else {
+ ph = protect_home_from_string(s);
+ if (ph < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value");
+ }
+
+ if (mode != UNIT_CHECK) {
+ c->protect_home = ph;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "RuntimeDirectory")) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ if (!filename_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
+ }
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_isempty(l)) {
+ c->runtime_directory = strv_free(c->runtime_directory);
+ unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ } else {
+ r = strv_extend_strv(&c->runtime_directory, l, true);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join_quoted(c->runtime_directory);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ }
}
return 1;
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
index e4c2d5ddf6..c44517ea22 100644
--- a/src/core/dbus-execute.h
+++ b/src/core/dbus-execute.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "execute.h"
#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index cd6b909426..8c30d66250 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -19,12 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
#include "sd-bus.h"
-#include "selinux-access.h"
-#include "job.h"
+
+#include "alloc-util.h"
#include "dbus-job.h"
#include "dbus.h"
+#include "job.h"
+#include "log.h"
+#include "selinux-access.h"
+#include "string-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
index fb5f1b513e..0f2fbe2ee2 100644
--- a/src/core/dbus-job.h
+++ b/src/core/dbus-job.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "job.h"
extern const sd_bus_vtable bus_job_vtable[];
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
index 7c15f3a90b..794c402048 100644
--- a/src/core/dbus-kill.h
+++ b/src/core/dbus-kill.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
#include "kill.h"
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 561b6f8bfa..1f9f25093d 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -20,27 +20,34 @@
***/
#include <errno.h>
+#include <sys/prctl.h>
#include <unistd.h>
-#include "log.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "architecture.h"
#include "build.h"
-#include "install.h"
-#include "selinux-access.h"
-#include "watchdog.h"
+#include "bus-common-errors.h"
#include "clock-util.h"
-#include "path-util.h"
-#include "virt.h"
-#include "architecture.h"
-#include "env-util.h"
-#include "dbus.h"
+#include "dbus-execute.h"
#include "dbus-job.h"
#include "dbus-manager.h"
-#include "dbus-unit.h"
#include "dbus-snapshot.h"
-#include "dbus-execute.h"
-#include "bus-common-errors.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "install.h"
+#include "log.h"
+#include "path-util.h"
+#include "selinux-access.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "virt.h"
+#include "watchdog.h"
static int property_get_version(
sd_bus *bus,
@@ -81,10 +88,21 @@ static int property_get_virtualization(
void *userdata,
sd_bus_error *error) {
+ int v;
+
assert(bus);
assert(reply);
- return sd_bus_message_append(reply, "s", virtualization_to_string(detect_virtualization()));
+ v = detect_virtualization();
+
+ /* Make sure to return the empty string when we detect no virtualization, as that is the API.
+ *
+ * https://github.com/systemd/systemd/issues/1423
+ */
+
+ return sd_bus_message_append(
+ reply, "s",
+ v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v));
}
static int property_get_architecture(
@@ -111,8 +129,7 @@ static int property_get_tainted(
void *userdata,
sd_bus_error *error) {
- char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf;
- _cleanup_free_ char *p = NULL;
+ char buf[sizeof("split-usr:cgroups-missing:local-hwclock:")] = "", *e = buf;
Manager *m = userdata;
assert(bus);
@@ -122,9 +139,6 @@ static int property_get_tainted(
if (m->taint_usr)
e = stpcpy(e, "split-usr:");
- if (readlink_malloc("/etc/mtab", &p) < 0)
- e = stpcpy(e, "mtab-not-symlink:");
-
if (access("/proc/cgroups", F_OK) < 0)
e = stpcpy(e, "cgroups-missing:");
@@ -339,6 +353,21 @@ static int property_set_runtime_watchdog(
return watchdog_set_timeout(t);
}
+static int property_get_timer_slack_nsec(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+}
+
static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
@@ -1960,6 +1989,33 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
+ SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 24813c6d20..0c91850c52 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -19,13 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "mount.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
+#include "mount.h"
+#include "string-util.h"
+#include "unit.h"
#include "dbus-mount.h"
-#include "bus-util.h"
static int property_get_what(
sd_bus *bus,
@@ -117,6 +118,7 @@ const sd_bus_vtable bus_mount_vtable[] = {
SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SmackFileSystemRootLabel", "s", NULL, offsetof(Mount, smack_fs_root_label), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
index f7004d252f..dd0bf51bb0 100644
--- a/src/core/dbus-mount.h
+++ b/src/core/dbus-mount.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_mount_vtable[];
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index 683561999b..9e32b5fb06 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
+#include "bus-util.h"
#include "path.h"
+#include "string-util.h"
+#include "unit.h"
#include "dbus-path.h"
-#include "bus-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult);
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index f8fb373bf0..16375b2311 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -19,17 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "selinux-access.h"
-#include "unit.h"
-#include "scope.h"
-#include "dbus.h"
-#include "bus-util.h"
-#include "bus-internal.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
-#include "dbus-unit.h"
+#include "bus-internal.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-kill.h"
#include "dbus-scope.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "scope.h"
+#include "selinux-access.h"
+#include "unit.h"
static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Scope *s = userdata;
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 3436342bef..24f611a593 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -19,15 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
-#include "path-util.h"
-#include "unit.h"
-#include "service.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
#include "dbus-service.h"
-#include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
+#include "service.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
@@ -58,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -120,6 +126,37 @@ static int bus_service_set_transient_property(
return 1;
+ } else if (STR_IN_SET(name,
+ "StandardInputFileDescriptor",
+ "StandardOutputFileDescriptor",
+ "StandardErrorFileDescriptor")) {
+ int fd;
+
+ r = sd_bus_message_read(message, "h", &fd);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ int copy;
+
+ copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ if (streq(name, "StandardInputFileDescriptor")) {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = copy;
+ } else if (streq(name, "StandardOutputFileDescriptor")) {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = copy;
+ } else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = copy;
+ }
+ }
+
+ return 1;
+
} else if (streq(name, "ExecStart")) {
unsigned n = 0;
@@ -211,7 +248,9 @@ static int bus_service_set_transient_property(
a);
}
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(UNIT(s), mode, name, buf);
}
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 86732e2a45..be5ef261a6 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -19,12 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "socket.h"
-#include "dbus-execute.h"
+#include "alloc-util.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
+#include "dbus-execute.h"
#include "dbus-socket.h"
-#include "bus-util.h"
+#include "socket.h"
+#include "string-util.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
@@ -84,6 +86,25 @@ static int property_get_listen(
return sd_bus_message_close_container(reply);
}
+
+static int property_get_fdname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Socket *s = SOCKET(userdata);
+
+ assert(bus);
+ assert(reply);
+ assert(s);
+
+ return sd_bus_message_append(reply, "s", socket_fdname(s));
+}
+
const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -95,6 +116,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAliveIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_interval), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -127,6 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+ SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 0093371306..603ca95fd9 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -20,12 +20,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "swap.h"
-#include "dbus-execute.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
+#include "dbus-execute.h"
+#include "string-util.h"
+#include "swap.h"
+#include "unit.h"
#include "dbus-swap.h"
-#include "bus-util.h"
static int property_get_priority(
sd_bus *bus,
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
index 4c4297bc9e..6be9c9f708 100644
--- a/src/core/dbus-target.h
+++ b/src/core/dbus-target.h
@@ -21,5 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-bus.h"
extern const sd_bus_vtable bus_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index 8ea2cf84a4..a8a280d961 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "timer.h"
-#include "dbus-timer.h"
+#include "alloc-util.h"
#include "bus-util.h"
+#include "dbus-timer.h"
#include "strv.h"
+#include "timer.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index cd88a87340..6320cd1aa9 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -20,14 +20,19 @@
***/
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "cgroup-util.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "locale-util.h"
#include "log.h"
#include "selinux-access.h"
-#include "cgroup-util.h"
-#include "strv.h"
-#include "bus-common-errors.h"
#include "special.h"
-#include "dbus.h"
-#include "dbus-unit.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
@@ -679,7 +684,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0),
+ SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0),
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -984,7 +989,8 @@ int bus_unit_queue_job(
if ((type == JOB_START && u->refuse_manual_start) ||
(type == JOB_STOP && u->refuse_manual_stop) ||
- ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
+ ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+ (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
r = manager_add_job(u->manager, type, u, mode, true, error, &j);
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 2d6a1ff836..6c44b28adf 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -19,29 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/epoll.h>
#include <errno.h>
+#include <sys/epoll.h>
#include <unistd.h>
#include "sd-bus.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
+#include "dbus-job.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "special.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
#include "dbus.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "strxcpyx.h"
-#include "bus-internal.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+#include "mkdir.h"
#include "selinux-access.h"
+#include "special.h"
+#include "string-util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+#include "user-util.h"
#define CONNECTIONS_MAX 4096
@@ -777,9 +782,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
return r;
HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
- r = unit_install_bus_match(bus, u, name);
+ r = unit_install_bus_match(u, bus, name);
if (r < 0)
- log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
}
r = sd_bus_add_match(
diff --git a/src/core/device.c b/src/core/device.c
index 0b54518691..23ee7aee7e 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -21,16 +21,21 @@
#include <errno.h>
#include <sys/epoll.h>
-#include <libudev.h>
-#include "log.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
#include "dbus-device.h"
+#include "device.h"
+#include "log.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "swap.h"
#include "udev-util.h"
+#include "unit-name.h"
#include "unit.h"
-#include "swap.h"
-#include "device.h"
static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = UNIT_INACTIVE,
@@ -816,14 +821,6 @@ int device_found_node(Manager *m, const char *node, bool add, DeviceFound found,
return device_update_found_by_name(m, node, add, found, now);
}
-static const char* const device_state_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = "dead",
- [DEVICE_TENTATIVE] = "tentative",
- [DEVICE_PLUGGED] = "plugged",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
const UnitVTable device_vtable = {
.object_size = sizeof(Device),
.sections =
diff --git a/src/core/device.h b/src/core/device.h
index 10ab113176..da8737870b 100644
--- a/src/core/device.h
+++ b/src/core/device.h
@@ -23,16 +23,6 @@
typedef struct Device Device;
-/* We simply watch devices, we cannot plug/unplug them. That
- * simplifies the state engine greatly */
-typedef enum DeviceState {
- DEVICE_DEAD,
- DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
- DEVICE_PLUGGED, /* announced by udev */
- _DEVICE_STATE_MAX,
- _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
typedef enum DeviceFound {
DEVICE_NOT_FOUND = 0,
DEVICE_FOUND_UDEV = 1,
@@ -56,7 +46,4 @@ struct Device {
extern const UnitVTable device_vtable;
-const char* device_state_to_string(DeviceState i) _const_;
-DeviceState device_state_from_string(const char *s) _pure_;
-
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
diff --git a/src/core/execute.c b/src/core/execute.c
index 7796c07fcf..d751065af0 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -21,18 +21,18 @@
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
+#include <glob.h>
+#include <grp.h>
+#include <poll.h>
#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <string.h>
+#include <sys/personality.h>
#include <sys/prctl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <grp.h>
-#include <poll.h>
-#include <glob.h>
+#include <sys/un.h>
+#include <unistd.h>
#include <utmpx.h>
-#include <sys/personality.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -50,47 +50,56 @@
#include <sys/apparmor.h>
#endif
-#include "barrier.h"
#include "sd-messages.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "namespace.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
-#include "def.h"
-#include "path-util.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "async.h"
-#include "selinux-util.h"
-#include "errno-list.h"
+
#include "af-list.h"
-#include "mkdir.h"
-#include "smack-util.h"
+#include "alloc-util.h"
+#ifdef HAVE_APPARMOR
+#include "apparmor-util.h"
+#endif
+#include "async.h"
+#include "barrier.h"
#include "bus-endpoint.h"
#include "cap-list.h"
+#include "capability-util.h"
+#include "def.h"
+#include "env-util.h"
+#include "errno-list.h"
+#include "execute.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "namespace.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-
+#include "rlimit-util.h"
+#include "rm-rf.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
-
-#include "execute.h"
+#include "securebits.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "smack-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "unit.h"
+#include "user-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
@@ -358,12 +367,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
return std_output;
}
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
+static int setup_input(
+ const ExecContext *context,
+ const ExecParameters *params,
+ int socket_fd) {
+
ExecInput i;
assert(context);
+ assert(params);
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ if (params->stdin_fd >= 0) {
+ if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
+ return -errno;
+
+ /* Try to make this the controlling tty, if it is a tty, and reset it */
+ (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
+ (void) reset_terminal_fd(STDIN_FILENO, true);
+
+ return STDIN_FILENO;
+ }
+
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
switch (i) {
@@ -400,16 +425,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
}
}
-static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
+static int setup_output(
+ Unit *unit,
+ const ExecContext *context,
+ const ExecParameters *params,
+ int fileno,
+ int socket_fd,
+ const char *ident,
+ uid_t uid, gid_t gid) {
+
ExecOutput o;
ExecInput i;
int r;
assert(unit);
assert(context);
+ assert(params);
assert(ident);
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
+
+ if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
+ return -errno;
+
+ return STDOUT_FILENO;
+ }
+
+ if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
+ if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
+ return -errno;
+
+ return STDERR_FILENO;
+ }
+
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
o = fixup_output(context->std_output, socket_fd);
if (fileno == STDERR_FILENO) {
@@ -502,9 +551,9 @@ static int chown_terminal(int fd, uid_t uid) {
return 0;
}
-static int setup_confirm_stdio(int *_saved_stdin,
- int *_saved_stdout) {
- int fd = -1, saved_stdin, saved_stdout = -1, r;
+static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) {
+ _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
+ int r;
assert(_saved_stdin);
assert(_saved_stdout);
@@ -514,10 +563,8 @@ static int setup_confirm_stdio(int *_saved_stdin,
return -errno;
saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
- if (saved_stdout < 0) {
- r = errno;
- goto fail;
- }
+ if (saved_stdout < 0)
+ return -errno;
fd = acquire_terminal(
"/dev/console",
@@ -525,39 +572,33 @@ static int setup_confirm_stdio(int *_saved_stdin,
false,
false,
DEFAULT_CONFIRM_USEC);
- if (fd < 0) {
- r = fd;
- goto fail;
- }
+ if (fd < 0)
+ return fd;
r = chown_terminal(fd, getuid());
if (r < 0)
- goto fail;
+ return r;
- if (dup2(fd, STDIN_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ return r;
- if (dup2(fd, STDOUT_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ if (dup2(fd, STDIN_FILENO) < 0)
+ return -errno;
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ return -errno;
if (fd >= 2)
safe_close(fd);
+ fd = -1;
*_saved_stdin = saved_stdin;
*_saved_stdout = saved_stdout;
- return 0;
-
-fail:
- safe_close(saved_stdout);
- safe_close(saved_stdin);
- safe_close(fd);
+ saved_stdin = saved_stdout = -1;
- return r;
+ return 0;
}
_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
@@ -577,9 +618,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
return 0;
}
-static int restore_confirm_stdio(int *saved_stdin,
- int *saved_stdout) {
-
+static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
int r = 0;
assert(saved_stdin);
@@ -595,8 +634,8 @@ static int restore_confirm_stdio(int *saved_stdin,
if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
r = -errno;
- safe_close(*saved_stdin);
- safe_close(*saved_stdout);
+ *saved_stdin = safe_close(*saved_stdin);
+ *saved_stdout = safe_close(*saved_stdout);
return r;
}
@@ -1198,6 +1237,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
static int build_environment(
const ExecContext *c,
unsigned n_fds,
+ char ** fd_names,
usec_t watchdog_usec,
const char *home,
const char *username,
@@ -1211,11 +1251,13 @@ static int build_environment(
assert(c);
assert(ret);
- our_env = new0(char*, 10);
+ our_env = new0(char*, 11);
if (!our_env)
return -ENOMEM;
if (n_fds > 0) {
+ _cleanup_free_ char *joined = NULL;
+
if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1223,6 +1265,15 @@ static int build_environment(
if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
return -ENOMEM;
our_env[n_env++] = x;
+
+ joined = strv_join(fd_names, ":");
+ if (!joined)
+ return -ENOMEM;
+
+ x = strjoin("LISTEN_FDNAMES=", joined, NULL);
+ if (!x)
+ return -ENOMEM;
+ our_env[n_env++] = x;
}
if (watchdog_usec > 0) {
@@ -1273,7 +1324,7 @@ static int build_environment(
}
our_env[n_env++] = NULL;
- assert(n_env <= 10);
+ assert(n_env <= 11);
*ret = our_env;
our_env = NULL;
@@ -1311,6 +1362,44 @@ static bool exec_needs_mount_namespace(
return false;
}
+static int close_remaining_fds(
+ const ExecParameters *params,
+ ExecRuntime *runtime,
+ int socket_fd,
+ int *fds, unsigned n_fds) {
+
+ unsigned n_dont_close = 0;
+ int dont_close[n_fds + 7];
+
+ assert(params);
+
+ if (params->stdin_fd >= 0)
+ dont_close[n_dont_close++] = params->stdin_fd;
+ if (params->stdout_fd >= 0)
+ dont_close[n_dont_close++] = params->stdout_fd;
+ if (params->stderr_fd >= 0)
+ dont_close[n_dont_close++] = params->stderr_fd;
+
+ if (socket_fd >= 0)
+ dont_close[n_dont_close++] = socket_fd;
+ if (n_fds > 0) {
+ memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
+ n_dont_close += n_fds;
+ }
+
+ if (params->bus_endpoint_fd >= 0)
+ dont_close[n_dont_close++] = params->bus_endpoint_fd;
+
+ if (runtime) {
+ if (runtime->netns_storage_socket[0] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
+ if (runtime->netns_storage_socket[1] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
+ }
+
+ return close_all_fds(dont_close, n_dont_close);
+}
+
static int exec_child(
Unit *unit,
ExecCommand *command,
@@ -1325,9 +1414,7 @@ static int exec_child(
_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];
+ const char *username = NULL, *home = NULL, *shell = NULL, *wd;
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
@@ -1367,22 +1454,7 @@ static int exec_child(
log_forget_fds();
- if (socket_fd >= 0)
- dont_close[n_dont_close++] = socket_fd;
- if (n_fds > 0) {
- memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
- n_dont_close += n_fds;
- }
- if (params->bus_endpoint_fd >= 0)
- dont_close[n_dont_close++] = params->bus_endpoint_fd;
- if (runtime) {
- if (runtime->netns_storage_socket[0] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
- if (runtime->netns_storage_socket[1] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
- }
-
- r = close_all_fds(dont_close, n_dont_close);
+ r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return r;
@@ -1438,21 +1510,21 @@ static int exec_child(
/* If a socket is connected to STDIN/STDOUT/STDERR, we
* must sure to drop O_NONBLOCK */
if (socket_fd >= 0)
- fd_nonblock(socket_fd, false);
+ (void) fd_nonblock(socket_fd, false);
- r = setup_input(context, socket_fd, params->apply_tty_stdin);
+ r = setup_input(context, params, socket_fd);
if (r < 0) {
*exit_status = EXIT_STDIN;
return r;
}
- r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
@@ -1698,6 +1770,13 @@ static int exec_child(
}
}
+ if (context->working_directory_home)
+ wd = home;
+ else if (context->working_directory)
+ wd = context->working_directory;
+ else
+ wd = "/";
+
if (params->apply_chroot) {
if (!needs_mount_namespace && context->root_directory)
if (chroot(context->root_directory) < 0) {
@@ -1705,21 +1784,15 @@ static int exec_child(
return -errno;
}
- if (chdir(context->working_directory ?: "/") < 0 &&
+ if (chdir(wd) < 0 &&
!context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
return -errno;
}
} else {
- _cleanup_free_ char *d = NULL;
-
- if (asprintf(&d, "%s/%s",
- context->root_directory ?: "",
- context->working_directory ?: "") < 0) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
+ const char *d;
+ d = strjoina(strempty(context->root_directory), "/", strempty(wd));
if (chdir(d) < 0 &&
!context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
@@ -1849,7 +1922,7 @@ static int exec_child(
#endif
}
- r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
+ r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
return r;
@@ -2249,7 +2322,7 @@ static void strv_fprintf(FILE *f, char **l) {
}
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
- char **e;
+ char **e, **d;
unsigned i;
assert(c);
@@ -2285,6 +2358,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
STRV_FOREACH(e, c->environment_files)
fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
+ fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+
+ STRV_FOREACH(d, c->runtime_directory)
+ fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+
if (c->nice_set)
fprintf(f,
"%sNice: %i\n",
@@ -2711,7 +2789,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
if (!l)
return -ENOMEM;
- r = strv_extend_strv(&c->argv, l);
+ r = strv_extend_strv(&c->argv, l, false);
if (r < 0)
return r;
diff --git a/src/core/execute.h b/src/core/execute.h
index a750246a89..f8995a4203 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -103,6 +103,7 @@ struct ExecContext {
struct rlimit *rlimit[_RLIMIT_MAX];
char *working_directory, *root_directory;
bool working_directory_missing_ok;
+ bool working_directory_home;
mode_t umask;
int oom_score_adjust;
@@ -207,21 +208,35 @@ struct ExecContext {
struct ExecParameters {
char **argv;
- int *fds; unsigned n_fds;
char **environment;
- bool apply_permissions;
- bool apply_chroot;
- bool apply_tty_stdin;
- bool confirm_spawn;
- bool selinux_context_net;
+
+ int *fds;
+ char **fd_names;
+ unsigned n_fds;
+
+ bool apply_permissions:1;
+ bool apply_chroot:1;
+ bool apply_tty_stdin:1;
+
+ bool confirm_spawn:1;
+ bool selinux_context_net:1;
+
+ bool cgroup_delegate:1;
CGroupMask cgroup_supported;
const char *cgroup_path;
- bool cgroup_delegate;
+
const char *runtime_prefix;
+
usec_t watchdog_usec;
+
int *idle_pipe;
+
char *bus_endpoint_path;
int bus_endpoint_fd;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
int exec_spawn(Unit *unit,
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
index 3412accf3e..c7c95984b7 100644
--- a/src/core/failure-action.c
+++ b/src/core/failure-action.c
@@ -23,10 +23,11 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include "bus-util.h"
#include "bus-error.h"
-#include "special.h"
+#include "bus-util.h"
#include "failure-action.h"
+#include "special.h"
+#include "string-table.h"
#include "terminal-util.h"
static void log_and_status(Manager *m, const char *message) {
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 932ddbf95a..3645f9c515 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -19,15 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
-#include "macro.h"
-#include "util.h"
-#include "log.h"
+#include "alloc-util.h"
#include "fileio.h"
#include "hostname-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "util.h"
#include "hostname-setup.h"
int hostname_setup(void) {
@@ -59,8 +61,9 @@ int hostname_setup(void) {
hn = "localhost";
}
- if (sethostname_idempotent(hn) < 0)
- return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn);
+ r = sethostname_idempotent(hn);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
log_info("Set hostname to <%s>.", hn);
return 0;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 42a3e97459..9572fa17d9 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -24,9 +24,11 @@
#include <unistd.h>
#include <errno.h>
+#include "fd-util.h"
+#include "fileio.h"
#include "ima-setup.h"
-#include "util.h"
#include "log.h"
+#include "util.h"
#define IMA_SECFS_DIR "/sys/kernel/security/ima"
#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
diff --git a/src/core/job.c b/src/core/job.c
index 558d8d2d52..120381fc3b 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -23,17 +23,24 @@
#include "sd-id128.h"
#include "sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "dbus-job.h"
-#include "special.h"
+
+#include "alloc-util.h"
#include "async.h"
-#include "virt.h"
+#include "dbus-job.h"
#include "dbus.h"
+#include "escape.h"
+#include "job.h"
+#include "log.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "set.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "unit.h"
+#include "virt.h"
Job* job_new_raw(Unit *unit) {
Job *j;
diff --git a/src/core/job.h b/src/core/job.h
index 1d1b10f1d3..350e9f385f 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -23,6 +23,10 @@
#include <stdbool.h>
+#include "sd-event.h"
+
+#include "list.h"
+
typedef struct Job Job;
typedef struct JobDependency JobDependency;
typedef enum JobType JobType;
@@ -105,9 +109,7 @@ enum JobResult {
_JOB_RESULT_INVALID = -1
};
-#include "sd-event.h"
#include "unit.h"
-#include "list.h"
struct JobDependency {
/* Encodes that the 'subject' job needs the 'object' job in
diff --git a/src/core/kill.c b/src/core/kill.c
index bddfa4460f..1466d5ce64 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "signal-util.h"
#include "kill.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "util.h"
void kill_context_init(KillContext *c) {
assert(c);
diff --git a/src/core/killall.c b/src/core/killall.c
index ee5d388560..77f145b4d1 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -19,17 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/wait.h>
-#include <signal.h>
#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
#include <unistd.h>
-#include "util.h"
-#include "killall.h"
-#include "set.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "killall.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "set.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
#define TIMEOUT_USEC (10 * USEC_PER_SEC)
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 2068ffd69b..651f79a1fe 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -27,7 +27,7 @@
#endif
#include "macro.h"
-#include "capability.h"
+#include "capability-util.h"
#include "bus-util.h"
#include "kmod-setup.h"
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index fd293d8287..5b7954dbf9 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -17,7 +17,7 @@ struct ConfigPerfItem;
%%
m4_dnl Define the context options only once
m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
-`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory)
+`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory)
$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user)
$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group)
@@ -59,18 +59,18 @@ $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CO
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
-$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
-$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
-$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
-$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
+$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
+$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
+$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
+$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
$1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit)
-$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
+$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit)
$1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit)
-$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
+$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit)
$1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit)
$1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit)
-$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
+$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit)
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
@@ -261,6 +261,7 @@ Socket.SocketGroup, config_parse_unit_string_printf, 0,
Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode)
Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode)
Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept)
+Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable)
Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive)
Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time)
@@ -286,6 +287,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0,
Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
+Socket.FileDescriptorName, config_parse_fdname, 0, 0
Socket.Service, config_parse_socket_service, 0, 0
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
@@ -317,6 +319,7 @@ Mount.Type, config_parse_string, 0,
Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec)
Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode)
Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options)
+Mount.SmackFileSystemRootLabel, config_parse_string, 0, offsetof(Mount, smack_fs_root_label)
EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index a13f42b5e0..7f12f26b08 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -20,44 +20,52 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <linux/oom.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
-#include <sched.h>
#include <linux/fs.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-
+#include <linux/oom.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
+#include <sched.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
-#include "unit.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "af-list.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "cap-list.h"
+#include "cgroup.h"
#include "conf-parser.h"
+#include "cpu-set-util.h"
+#include "env-util.h"
+#include "errno-list.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "ioprio.h"
#include "load-fragment.h"
#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
#include "missing.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "utf8.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "env-util.h"
-#include "cgroup.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "errno-list.h"
-#include "af-list.h"
-#include "cap-list.h"
-#include "signal-util.h"
-#include "bus-internal.h"
-
+#include "process-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "securebits.h"
+#include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "web-util.h"
int config_parse_warn_compat(
const char *unit,
@@ -74,15 +82,15 @@ int config_parse_warn_compat(
switch(reason) {
case DISABLED_CONFIGURATION:
- log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
+ log_syntax(unit, LOG_DEBUG, filename, line, 0,
"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,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has been removed and it is ignored", lvalue);
break;
case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has not yet been enabled and it is ignored", lvalue);
break;
};
@@ -120,18 +128,16 @@ int config_parse_unit_deps(const char *unit,
r = unit_name_printf(u, t, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
r = unit_add_dependency_by_name(u, d, k, NULL, true);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -166,16 +172,17 @@ int config_parse_unit_string_printf(
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_strv_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_strv_printf(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
@@ -187,24 +194,25 @@ int config_parse_unit_strv_printf(const char *unit,
assert(u);
r = unit_full_printf(u, rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
- k ? k : rvalue, data, userdata);
+ return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_path_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_path_printf(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
_cleanup_free_ char *k = NULL;
Unit *u = userdata;
@@ -217,7 +225,7 @@ int config_parse_unit_path_printf(const char *unit,
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
@@ -256,17 +264,17 @@ int config_parse_unit_path_strv_printf(
r = unit_full_printf(u, t, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t);
return 0;
}
if (!utf8_is_valid(k)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k);
return 0;
}
@@ -279,7 +287,7 @@ int config_parse_unit_path_strv_printf(
k = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -322,12 +330,8 @@ int config_parse_socket_listen(const char *unit,
p->type = ltype;
r = unit_full_printf(UNIT(s), rvalue, &p->path);
if (r < 0) {
- p->path = strdup(rvalue);
- if (!p->path)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
}
path_kill_slashes(p->path);
@@ -337,14 +341,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- r = socket_address_parse_netlink(&p->address, k ?: rvalue);
+ r = socket_address_parse_netlink(&p->address, k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -353,14 +357,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- r = socket_address_parse_and_warn(&p->address, k ? k : rvalue);
+ r = socket_address_parse_and_warn(&p->address, k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -374,8 +378,7 @@ int config_parse_socket_listen(const char *unit,
}
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
- log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
- "Address family not supported, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
return 0;
}
}
@@ -422,8 +425,7 @@ int config_parse_socket_bind(const char *unit,
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
return 0;
}
@@ -455,14 +457,12 @@ int config_parse_exec_nice(const char *unit,
r = safe_atoi(rvalue, &priority);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse nice priority, ignoring: %s. ", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
return 0;
}
if (priority < PRIO_MIN || priority >= PRIO_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Nice priority out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue);
return 0;
}
@@ -493,14 +493,12 @@ int config_parse_exec_oom_score_adjust(const char* unit,
r = safe_atoi(rvalue, &oa);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0;
}
if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "OOM score adjust value out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
return 0;
}
@@ -533,9 +531,7 @@ int config_parse_exec(
assert(e);
e += ltype;
-
rvalue += strspn(rvalue, WHITESPACE);
- p = rvalue;
if (isempty(rvalue)) {
/* An empty assignment resets the list */
@@ -543,14 +539,15 @@ int config_parse_exec(
return 0;
}
+ p = rvalue;
do {
- int i;
+ _cleanup_free_ char *path = NULL, *firstword = NULL;
+ bool separate_argv0 = false, ignore = false;
+ _cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
- _cleanup_free_ ExecCommand *nce = NULL;
- _cleanup_free_ char *path = NULL, *firstword = NULL;
char *f;
- bool separate_argv0 = false, ignore = false;
+ int i;
semicolon = false;
@@ -574,24 +571,19 @@ int config_parse_exec(
if (isempty(f)) {
/* First word is either "-" or "@" with no command. */
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty path in command line, ignoring: \"%s\"", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
return 0;
}
-
if (!string_is_safe(f)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path contains special characters, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
return 0;
}
if (!path_is_absolute(f)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path is not absolute, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
return 0;
}
if (endswith(f, "/")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path specifies a directory, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
return 0;
}
@@ -658,8 +650,7 @@ int config_parse_exec(
}
if (!n || !n[0]) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
return 0;
}
@@ -743,8 +734,7 @@ int config_parse_exec_io_class(const char *unit,
x = ioprio_class_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IO scheduling class, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
return 0;
}
@@ -775,8 +765,7 @@ int config_parse_exec_io_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse IO priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
return 0;
}
@@ -808,8 +797,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
x = sched_policy_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -x,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -842,8 +830,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -852,8 +839,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
max = sched_get_priority_max(c->cpu_sched_policy);
if (i < min || i > max) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "CPU scheduling priority is out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
return 0;
}
@@ -883,8 +869,7 @@ int config_parse_exec_cpu_affinity(const char *unit,
assert(rvalue);
assert(data);
- ncpus = parse_cpu_set(rvalue, &cpuset, unit, filename, line, lvalue);
-
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
if (ncpus < 0)
return ncpus;
@@ -924,8 +909,7 @@ int config_parse_exec_capabilities(const char *unit,
cap = cap_from_text(rvalue);
if (!cap) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse capabilities, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue);
return 0;
}
@@ -976,14 +960,12 @@ int config_parse_exec_secure_bits(const char *unit,
else if (first_word(word, "noroot-locked"))
c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse secure bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid syntax, garbage at the end, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
return 0;
}
@@ -1000,10 +982,11 @@ int config_parse_bounding_set(const char *unit,
void *userdata) {
uint64_t *capability_bounding_set_drop = data;
- const char *word, *state;
- size_t l;
+ uint64_t capability_bounding_set;
bool invert = false;
uint64_t sum = 0;
+ const char *prev;
+ const char *cur;
assert(filename);
assert(lvalue);
@@ -1020,30 +1003,38 @@ int config_parse_bounding_set(const char *unit,
* non-inverted everywhere to have a fully normalized
* interface. */
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
+ prev = cur = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
int cap;
+ int r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev);
+ break;
+ }
- cap = capability_from_name(t);
+ cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse capability in bounding set, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
+ prev = cur;
continue;
}
sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+ prev = cur;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
- if (invert)
- *capability_bounding_set_drop |= sum;
+ capability_bounding_set = invert ? ~sum : sum;
+ if (*capability_bounding_set_drop && capability_bounding_set)
+ *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
else
- *capability_bounding_set_drop |= ~sum;
+ *capability_bounding_set_drop = ~capability_bounding_set;
return 0;
}
@@ -1076,8 +1067,7 @@ int config_parse_limit(const char *unit,
r = safe_atollu(rvalue, &u);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse resource value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
}
@@ -1092,6 +1082,49 @@ int config_parse_limit(const char *unit,
return 0;
}
+int config_parse_bytes_limit(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ struct rlimit **rl = data;
+ uint64_t bytes;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ bytes = (uint64_t) RLIM_INFINITY;
+ else {
+ int r;
+
+ r = parse_size(rvalue, 1024, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes;
+ return 0;
+}
+
#ifdef HAVE_SYSV_COMPAT
int config_parse_sysv_priority(const char *unit,
const char *filename,
@@ -1114,8 +1147,7 @@ int config_parse_sysv_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse SysV start priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
return 0;
}
@@ -1162,12 +1194,12 @@ int config_parse_exec_mount_flags(const char *unit,
else if (streq(t, "private"))
flags = MS_PRIVATE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
c->mount_flags = flags;
return 0;
@@ -1210,8 +1242,7 @@ int config_parse_exec_selinux_context(
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));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1259,8 +1290,7 @@ int config_parse_exec_apparmor_profile(
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));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1308,8 +1338,7 @@ int config_parse_exec_smack_process_label(
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));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1350,23 +1379,18 @@ int config_parse_timer(const char *unit,
b = timer_base_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b,
- "Failed to parse timer base, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
return 0;
}
if (b == TIMER_CALENDAR) {
if (calendar_spec_from_string(rvalue, &c) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse calendar specification, ignoring: %s",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue);
return 0;
}
} else {
if (parse_sec(rvalue, &u) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse timer value, ignoring: %s",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue);
return 0;
}
}
@@ -1409,33 +1433,30 @@ int config_parse_trigger_unit(
assert(data);
if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Multiple units to trigger specified, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
return 0;
}
r = unit_name_printf(u, rvalue, &p);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ return 0;
+ }
- type = unit_name_to_type(p ?: rvalue);
+ type = unit_name_to_type(p);
if (type < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit type not valid, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
return 0;
}
if (type == u->type) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trigger cannot be of same type, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
return 0;
}
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
}
@@ -1472,25 +1493,18 @@ int config_parse_path_spec(const char *unit,
b = path_type_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse path type, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
return 0;
}
r = unit_full_printf(UNIT(p), rvalue, &k);
if (r < 0) {
- k = strdup(rvalue);
- if (!k)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path is not absolute, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
return 0;
}
@@ -1522,10 +1536,10 @@ int config_parse_socket_service(
void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *p = NULL;
Socket *s = data;
- int r;
Unit *x;
- _cleanup_free_ char *p = NULL;
+ int r;
assert(filename);
assert(lvalue);
@@ -1539,13 +1553,13 @@ int config_parse_socket_service(
}
if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
return 0;
}
r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1554,6 +1568,50 @@ int config_parse_socket_service(
return 0;
}
+int config_parse_fdname(
+ 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) {
+
+ _cleanup_free_ char *p = NULL;
+ Socket *s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ s->fdname = mfree(s->fdname);
+ return 0;
+ }
+
+ r = unit_name_printf(UNIT(s), rvalue, &p);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!fdname_is_valid(p)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
+ return 0;
+ }
+
+ free(s->fdname);
+ s->fdname = p;
+ p = NULL;
+
+ return 0;
+}
+
int config_parse_service_sockets(
const char *unit,
const char *filename,
@@ -1567,8 +1625,7 @@ int config_parse_service_sockets(
void *userdata) {
Service *s = data;
- const char *word, *state;
- size_t l;
+ const char *p;
int r;
assert(filename);
@@ -1576,21 +1633,28 @@ int config_parse_service_sockets(
assert(rvalue);
assert(data);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for(;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(UNIT(s), t, &k);
+ r = unit_name_printf(UNIT(s), word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
if (!endswith(k, ".socket")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
continue;
}
@@ -1602,8 +1666,6 @@ int config_parse_service_sockets(
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
return 0;
}
@@ -1636,7 +1698,7 @@ int config_parse_bus_name(
}
if (!service_name_is_valid(k)) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
return 0;
}
@@ -1701,21 +1763,18 @@ int config_parse_busname_service(
r = unit_name_printf(UNIT(n), rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit must be of type service, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
return 0;
}
r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1765,8 +1824,7 @@ int config_parse_bus_policy(
access_str = strpbrk(id_str, WHITESPACE);
if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy value '%s'", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
return 0;
}
@@ -1776,8 +1834,7 @@ int config_parse_bus_policy(
p->access = bus_policy_access_from_string(access_str);
if (p->access < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy access type '%s'", access_str);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
return 0;
}
@@ -1819,8 +1876,7 @@ int config_parse_bus_endpoint_policy(
access_str = strpbrk(name, WHITESPACE);
if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy value '%s'", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue);
return 0;
}
@@ -1831,21 +1887,83 @@ int config_parse_bus_endpoint_policy(
access = bus_policy_access_from_string(access_str);
if (access <= _BUS_POLICY_ACCESS_INVALID ||
access >= _BUS_POLICY_ACCESS_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy access type '%s'", access_str);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str);
return 0;
}
if (!c->bus_endpoint) {
r = bus_endpoint_new(&c->bus_endpoint);
-
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to create bus endpoint object: %m");
}
return bus_endpoint_add_policy(c->bus_endpoint, name, access);
}
+int config_parse_working_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) {
+
+ ExecContext *c = data;
+ Unit *u = userdata;
+ bool missing_ok;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(c);
+ assert(u);
+
+ if (rvalue[0] == '-') {
+ missing_ok = true;
+ rvalue++;
+ } else
+ missing_ok = false;
+
+ if (streq(rvalue, "~")) {
+ c->working_directory_home = true;
+ c->working_directory = mfree(c->working_directory);
+ } else {
+ _cleanup_free_ char *k = NULL;
+
+ r = unit_full_printf(u, rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ path_kill_slashes(k);
+
+ if (!utf8_is_valid(k)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ return 0;
+ }
+
+ if (!path_is_absolute(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
+ return 0;
+ }
+
+ free(c->working_directory);
+ c->working_directory = k;
+ k = NULL;
+
+ c->working_directory_home = false;
+ }
+
+ c->working_directory_missing_ok = missing_ok;
+ return 0;
+}
+
int config_parse_unit_env_file(const char *unit,
const char *filename,
unsigned line,
@@ -1860,7 +1978,6 @@ int config_parse_unit_env_file(const char *unit,
char ***env = data;
Unit *u = userdata;
_cleanup_free_ char *n = NULL;
- const char *s;
int r;
assert(filename);
@@ -1875,18 +1992,17 @@ int config_parse_unit_env_file(const char *unit,
}
r = unit_full_printf(u, rvalue, &n);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
- s = n ?: rvalue;
- if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path '%s' is not absolute, ignoring.", s);
+ if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
return 0;
}
- r = strv_extend(env, s);
+ r = strv_extend(env, n);
if (r < 0)
return log_oom();
@@ -1924,14 +2040,17 @@ int config_parse_environ(const char *unit,
if (u) {
r = unit_full_printf(u, rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
}
- if (!k)
+ if (!k) {
k = strdup(rvalue);
- if (!k)
- return log_oom();
+ if (!k)
+ return log_oom();
+ }
FOREACH_WORD_QUOTED(word, l, k, state) {
_cleanup_free_ char *n = NULL;
@@ -1944,7 +2063,7 @@ int config_parse_environ(const char *unit,
}
if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
continue;
}
@@ -1956,8 +2075,7 @@ int config_parse_environ(const char *unit,
*env = x;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -1982,8 +2100,7 @@ int config_parse_ip_tos(const char *unit,
x = ip_tos_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IP TOS value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
return 0;
}
@@ -2031,12 +2148,12 @@ int config_parse_unit_condition_path(
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);
+ 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, 0, "Path in condition not absolute, ignoring: %s", p);
return 0;
}
@@ -2088,7 +2205,7 @@ int config_parse_unit_condition_string(
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
@@ -2137,7 +2254,7 @@ int config_parse_unit_condition_null(
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;
}
@@ -2185,20 +2302,18 @@ int config_parse_unit_requires_mounts_for(
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
continue;
}
r = unit_require_mounts_for(u, n);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add required mount for, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
continue;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2239,8 +2354,7 @@ int config_parse_documentation(const char *unit,
if (documentation_url_is_valid(*a))
*(b++) = *a;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid URL, ignoring: %s", *a);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
free(*a);
}
}
@@ -2335,8 +2449,7 @@ int config_parse_syscall_filter(
id = seccomp_syscall_resolve_name(t);
if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
continue;
}
@@ -2353,8 +2466,7 @@ int config_parse_syscall_filter(
set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
@@ -2400,8 +2512,7 @@ int config_parse_syscall_archs(
r = seccomp_arch_from_string(t, &a);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call architecture, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
continue;
}
@@ -2412,8 +2523,7 @@ int config_parse_syscall_archs(
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2445,8 +2555,7 @@ int config_parse_syscall_errno(
e = errno_from_name(rvalue);
if (e < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse error number, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
return 0;
}
@@ -2506,8 +2615,7 @@ int config_parse_address_families(
af = af_from_name(t);
if (af <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse address family, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
continue;
}
@@ -2524,8 +2632,7 @@ int config_parse_address_families(
set_remove(c->address_families, INT_TO_PTR(af));
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2628,15 +2735,12 @@ int config_parse_cpu_quota(
}
if (!endswith(rvalue, "%")) {
-
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
return 0;
}
if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2668,7 +2772,7 @@ int config_parse_memory_limit(
r = parse_size(rvalue, 1024, &bytes);
if (r < 0 || bytes < 1) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2699,10 +2803,11 @@ int config_parse_tasks_max(
r = safe_atou64(rvalue, &u);
if (r < 0 || u < 1) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
return 0;
}
+ c->tasks_max = u;
return 0;
}
@@ -2739,8 +2844,7 @@ int config_parse_device_allow(
if (!startswith(path, "/dev/") &&
!startswith(path, "block-") &&
!startswith(path, "char-")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@@ -2749,8 +2853,7 @@ int config_parse_device_allow(
m = "rwm";
if (!in_charset(m, "rwm")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device rights '%s'. Ignoring.", m);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
return 0;
}
@@ -2832,7 +2935,7 @@ int config_parse_blockio_device_weight(
weight += strspn(weight, WHITESPACE);
if (isempty(weight)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
return 0;
}
@@ -2841,7 +2944,7 @@ int config_parse_blockio_device_weight(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@@ -2908,8 +3011,7 @@ int config_parse_blockio_bandwidth(
bandwidth += strspn(bandwidth, WHITESPACE);
if (!*bandwidth) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected space separated pair of device node and bandwidth. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
return 0;
}
@@ -2918,15 +3020,13 @@ int config_parse_blockio_bandwidth(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
r = parse_size(bandwidth, 1000, &bytes);
if (r < 0 || bytes <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2971,13 +3071,12 @@ int config_parse_netclass(
r = safe_atou32(rvalue, &v);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Netclass '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue);
return 0;
}
if (v > CGROUP_NETCLASS_FIXED_MAX)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, 0,
"Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX);
c->netclass_id = v;
@@ -3009,8 +3108,7 @@ int config_parse_job_mode_isolate(
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse boolean, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
return 0;
}
@@ -3056,14 +3154,12 @@ int config_parse_runtime_directory(
r = unit_name_printf(u, t, &n);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
if (!filename_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Runtime directory is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
continue;
}
@@ -3074,8 +3170,7 @@ int config_parse_runtime_directory(
n = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3122,15 +3217,13 @@ int config_parse_set_status(
val = signal_from_string_try_harder(temp);
if (val <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -val,
- "Failed to parse value, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
continue;
}
set = &status_set->signal;
} else {
if (val < 0 || val > 255) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Value %d is outside range 0-255, ignoring", val);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
continue;
}
set = &status_set->status;
@@ -3142,14 +3235,12 @@ int config_parse_set_status(
r = set_put(*set, INT_TO_PTR(val));
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Unable to store: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
return r;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3167,8 +3258,8 @@ int config_parse_namespace_path_strv(
void *userdata) {
char*** sv = data;
- const char *word, *state;
- size_t l;
+ const char *prev;
+ const char *cur;
int r;
assert(filename);
@@ -3182,37 +3273,43 @@ int config_parse_namespace_path_strv(
return 0;
}
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ prev = cur = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
int offset;
- n = strndup(word, l);
- if (!n)
+ r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
+ return 0;
+ }
- if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ if (!utf8_is_valid(word)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
+ prev = cur;
continue;
}
- offset = n[0] == '-';
- if (!path_is_absolute(n + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not an absolute path, ignoring: %s", rvalue);
+ offset = word[0] == '-';
+ if (!path_is_absolute(word + offset)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
+ prev = cur;
continue;
}
- path_kill_slashes(n);
+ path_kill_slashes(word + offset);
- r = strv_push(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
- n = NULL;
+ prev = cur;
+ word = NULL;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
return 0;
}
@@ -3239,8 +3336,7 @@ int config_parse_no_new_privileges(
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -3283,8 +3379,7 @@ int config_parse_protect_home(
h = protect_home_from_string(rvalue);
if (h < 0){
- log_syntax(unit, LOG_ERR, filename, line, -h,
- "Failed to parse protect home value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
return 0;
}
@@ -3327,8 +3422,7 @@ int config_parse_protect_system(
s = protect_system_from_string(rvalue);
if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s,
- "Failed to parse protect system value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 5d0a09249f..029775bb46 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -56,6 +56,7 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -106,6 +107,8 @@ int config_parse_protect_home(const char* unit, const char *filename, unsigned l
int config_parse_protect_system(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_bus_name(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_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_working_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_fdname(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 prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index 6961c26674..bd632131b9 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -19,16 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
-#include "locale-setup.h"
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "strv.h"
#include "env-util.h"
+#include "fileio.h"
#include "locale-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "virt.h"
+#include "locale-setup.h"
int locale_setup(char ***environment) {
char **add;
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 4503fc9dcc..4a57793104 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -23,9 +23,10 @@
#include <stdlib.h>
#include "sd-netlink.h"
-#include "netlink-util.h"
-#include "missing.h"
+
#include "loopback-setup.h"
+#include "missing.h"
+#include "netlink-util.h"
static int start_loopback(sd_netlink *rtnl) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 8f682c6d10..145ba2a28d 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -19,24 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/mount.h>
+#include <unistd.h>
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
+#include "log.h"
#include "machine-id-setup.h"
#include "macro.h"
-#include "util.h"
#include "mkdir.h"
-#include "log.h"
-#include "virt.h"
-#include "fileio.h"
+#include "mount-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "umask-util.h"
+#include "util.h"
+#include "virt.h"
static int shorten_uuid(char destination[34], const char source[36]) {
unsigned i, j;
diff --git a/src/core/main.c b/src/core/main.c
index bc72a2b00b..950315e857 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -19,63 +19,73 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
+#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
-#include <fcntl.h>
-#include <sys/prctl.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/mount.h>
-
-#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
+#include <sys/prctl.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <unistd.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
#include "sd-daemon.h"
#include "sd-bus.h"
-#include "log.h"
-#include "fdset.h"
-#include "special.h"
-#include "conf-parser.h"
-#include "missing.h"
-#include "pager.h"
+
+#include "alloc-util.h"
+#include "architecture.h"
#include "build.h"
-#include "strv.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "capability-util.h"
+#include "clock-util.h"
+#include "conf-parser.h"
+#include "cpu-set-util.h"
+#include "dbus-manager.h"
#include "def.h"
-#include "virt.h"
-#include "architecture.h"
-#include "watchdog.h"
-#include "switch-root.h"
-#include "capability.h"
-#include "killall.h"
#include "env-util.h"
-#include "clock-util.h"
+#include "fd-util.h"
+#include "fdset.h"
#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "selinux-util.h"
#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "manager.h"
-#include "dbus-manager.h"
+#include "fs-util.h"
+#include "hostname-setup.h"
+#include "ima-setup.h"
+#include "killall.h"
+#include "kmod-setup.h"
#include "load-fragment.h"
-
-#include "mount-setup.h"
+#include "log.h"
#include "loopback-setup.h"
-#include "hostname-setup.h"
#include "machine-id-setup.h"
+#include "manager.h"
+#include "missing.h"
+#include "mount-setup.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "rlimit-util.h"
#include "selinux-setup.h"
-#include "ima-setup.h"
+#include "selinux-util.h"
+#include "signal-util.h"
#include "smack-setup.h"
-#include "kmod-setup.h"
+#include "special.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "switch-root.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "virt.h"
+#include "watchdog.h"
static enum {
ACTION_RUN,
@@ -88,8 +98,9 @@ static enum {
static char *arg_default_unit = NULL;
static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
static bool arg_dump_core = true;
-static bool arg_crash_shell = false;
static int arg_crash_chvt = -1;
+static bool arg_crash_shell = false;
+static bool arg_crash_reboot = false;
static bool arg_confirm_spawn = false;
static ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
static bool arg_switched_root = false;
@@ -116,8 +127,6 @@ static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = false;
-static void nop_handler(int sig) {}
-
static void pager_open_if_enabled(void) {
if (arg_no_pager <= 0)
@@ -126,49 +135,66 @@ static void pager_open_if_enabled(void) {
pager_open(false);
}
+noreturn static void freeze_or_reboot(void) {
+
+ if (arg_crash_reboot) {
+ log_notice("Rebooting in 10s...");
+ (void) sleep(10);
+
+ log_notice("Rebooting now...");
+ (void) reboot(RB_AUTOBOOT);
+ log_emergency_errno(errno, "Failed to reboot: %m");
+ }
+
+ log_emergency("Freezing execution.");
+ freeze();
+}
+
noreturn static void crash(int sig) {
+ struct sigaction sa;
+ pid_t pid;
if (getpid() != 1)
/* Pass this on immediately, if this is not PID 1 */
- raise(sig);
+ (void) raise(sig);
else if (!arg_dump_core)
log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
else {
- struct sigaction sa = {
- .sa_handler = nop_handler,
+ sa = (struct sigaction) {
+ .sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
- pid_t pid;
/* We want to wait for the core process, hence let's enable SIGCHLD */
- sigaction(SIGCHLD, &sa, NULL);
+ (void) sigaction(SIGCHLD, &sa, NULL);
pid = raw_clone(SIGCHLD, NULL);
if (pid < 0)
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
-
else if (pid == 0) {
- struct rlimit rl = {};
+ struct rlimit rl = {
+ .rlim_cur = RLIM_INFINITY,
+ .rlim_max = RLIM_INFINITY,
+ };
/* Enable default signal handler for core dump */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- sigaction(sig, &sa, NULL);
+ sa = (struct sigaction) {
+ .sa_handler = SIG_DFL,
+ };
+ (void) sigaction(sig, &sa, NULL);
/* Don't limit the core dump size */
- rl.rlim_cur = RLIM_INFINITY;
- rl.rlim_max = RLIM_INFINITY;
- setrlimit(RLIMIT_CORE, &rl);
+ (void) setrlimit(RLIMIT_CORE, &rl);
/* Just to be sure... */
(void) chdir("/");
/* Raise the signal again */
pid = raw_getpid();
- kill(pid, sig); /* raise() would kill the parent */
+ (void) kill(pid, sig); /* raise() would kill the parent */
assert_not_reached("We shouldn't be here...");
- _exit(1);
+ _exit(EXIT_FAILURE);
} else {
siginfo_t status;
int r;
@@ -190,37 +216,38 @@ noreturn static void crash(int sig) {
}
}
- if (arg_crash_chvt)
- chvt(arg_crash_chvt);
+ if (arg_crash_chvt >= 0)
+ (void) chvt(arg_crash_chvt);
- if (arg_crash_shell) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
- };
- pid_t pid;
+ sa = (struct sigaction) {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
+ };
- log_info("Executing crash shell in 10s...");
- sleep(10);
+ /* Let the kernel reap children for us */
+ (void) sigaction(SIGCHLD, &sa, NULL);
- /* Let the kernel reap children for us */
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
+ if (arg_crash_shell) {
+ log_notice("Executing crash shell in 10s...");
+ (void) sleep(10);
pid = raw_clone(SIGCHLD, NULL);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off crash shell: %m");
else if (pid == 0) {
- make_console_stdio();
- execle("/bin/sh", "/bin/sh", NULL, environ);
+ (void) setsid();
+ (void) make_console_stdio();
+ (void) execle("/bin/sh", "/bin/sh", NULL, environ);
log_emergency_errno(errno, "execle() failed: %m");
- _exit(1);
- } else
- log_info("Successfully spawned crash shell as PID "PID_FMT".", pid);
+ _exit(EXIT_FAILURE);
+ } else {
+ log_info("Spawned crash shell as PID "PID_FMT".", pid);
+ (void) wait_for_terminate(pid, NULL);
+ }
}
- log_emergency("Freezing execution.");
- freeze();
+ freeze_or_reboot();
}
static void install_crash_handler(void) {
@@ -254,37 +281,26 @@ static int console_setup(void) {
return 0;
}
-static int set_default_unit(const char *u) {
- char *c;
+static int parse_crash_chvt(const char *value) {
+ int b;
- assert(u);
+ if (safe_atoi(value, &arg_crash_chvt) >= 0)
+ return 0;
- c = strdup(u);
- if (!c)
- return -ENOMEM;
+ b = parse_boolean(value);
+ if (b < 0)
+ return b;
- free(arg_default_unit);
- arg_default_unit = c;
+ if (b > 0)
+ arg_crash_chvt = 0; /* switch to where kmsg goes */
+ else
+ arg_crash_chvt = -1; /* turn off switching */
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value) {
- static const char * const rlmap[] = {
- "emergency", SPECIAL_EMERGENCY_TARGET,
- "-b", SPECIAL_EMERGENCY_TARGET,
- "rescue", SPECIAL_RESCUE_TARGET,
- "single", SPECIAL_RESCUE_TARGET,
- "-s", SPECIAL_RESCUE_TARGET,
- "s", SPECIAL_RESCUE_TARGET,
- "S", SPECIAL_RESCUE_TARGET,
- "1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_MULTI_USER_TARGET,
- "3", SPECIAL_MULTI_USER_TARGET,
- "4", SPECIAL_MULTI_USER_TARGET,
- "5", SPECIAL_GRAPHICAL_TARGET,
- };
int r;
assert(key);
@@ -292,12 +308,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
if (streq(key, "systemd.unit") && value) {
if (!in_initrd())
- return set_default_unit(value);
+ return free_and_strdup(&arg_default_unit, value);
} else if (streq(key, "rd.systemd.unit") && value) {
if (in_initrd())
- return set_default_unit(value);
+ return free_and_strdup(&arg_default_unit, value);
} else if (streq(key, "systemd.dump_core") && value) {
@@ -307,6 +323,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else
arg_dump_core = r;
+ } else if (streq(key, "systemd.crash_chvt") && value) {
+
+ if (parse_crash_chvt(value) < 0)
+ log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
+
} else if (streq(key, "systemd.crash_shell") && value) {
r = parse_boolean(value);
@@ -315,12 +336,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else
arg_crash_shell = r;
- } else if (streq(key, "systemd.crash_chvt") && value) {
+ } else if (streq(key, "systemd.crash_reboot") && value) {
- if (safe_atoi(value, &r) < 0)
- log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
+ r = parse_boolean(value);
+ if (r < 0)
+ log_warning("Failed to parse crash reboot switch %s. Ignoring.", value);
else
- arg_crash_chvt = r;
+ arg_crash_reboot = r;
} else if (streq(key, "systemd.confirm_spawn") && value) {
@@ -379,12 +401,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
log_set_target(LOG_TARGET_CONSOLE);
} else if (!in_initrd() && !value) {
- unsigned i;
+ const char *target;
/* SysV compatibility */
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(key, rlmap[i]))
- return set_default_unit(rlmap[i+1]);
+ target = runlevel_to_target(key);
+ if (target)
+ return free_and_strdup(&arg_default_unit, target);
}
return 0;
@@ -410,9 +432,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
\
r = func(rvalue); \
if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
- "Invalid " descr "'%s': %s", \
- rvalue, strerror(-r)); \
+ log_syntax(unit, LOG_ERR, filename, line, r, \
+ "Invalid " descr "'%s': %m", \
+ rvalue); \
\
return 0; \
}
@@ -437,8 +459,7 @@ static int config_parse_cpu_affinity2(
_cleanup_cpu_free_ cpu_set_t *c = NULL;
int ncpus;
- ncpus = parse_cpu_set(rvalue, &c, unit, filename, line, lvalue);
-
+ ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
if (ncpus < 0)
return ncpus;
@@ -470,29 +491,38 @@ static int config_parse_show_status(
k = parse_show_status(rvalue, b);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse show status setting, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue);
return 0;
}
return 0;
}
-static void strv_free_free(char ***l) {
- char ***i;
+static int config_parse_crash_chvt(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
- if (!l)
- return;
+ int r;
- for (i = l; *i; i++)
- strv_free(*i);
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
- free(l);
-}
+ r = parse_crash_chvt(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
+ return 0;
+ }
-static void free_join_controllers(void) {
- strv_free_free(arg_join_controllers);
- arg_join_controllers = NULL;
+ return 0;
}
static int config_parse_join_controllers(const char *unit,
@@ -513,7 +543,7 @@ static int config_parse_join_controllers(const char *unit,
assert(lvalue);
assert(rvalue);
- free_join_controllers();
+ arg_join_controllers = strv_free_free(arg_join_controllers);
for (;;) {
_cleanup_free_ char *word = NULL;
@@ -530,7 +560,7 @@ static int config_parse_join_controllers(const char *unit,
l = strv_split(word, ",");
if (!l)
- log_oom();
+ return log_oom();
strv_uniq(l);
if (strv_length(l) <= 1) {
@@ -564,7 +594,7 @@ static int config_parse_join_controllers(const char *unit,
for (a = arg_join_controllers; *a; a++) {
if (strv_overlap(*a, l)) {
- if (strv_extend_strv(&l, *a) < 0) {
+ if (strv_extend_strv(&l, *a, false) < 0) {
strv_free(l);
strv_free_free(t);
return log_oom();
@@ -591,8 +621,7 @@ static int config_parse_join_controllers(const char *unit,
}
}
if (!isempty(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -605,9 +634,11 @@ static int parse_config_file(void) {
{ "Manager", "LogColor", config_parse_color, 0, NULL },
{ "Manager", "LogLocation", config_parse_location, 0, NULL },
{ "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core },
+ { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL },
+ { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL },
{ "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
+ { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
- { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
@@ -627,18 +658,18 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
{ "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
+ { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
+ { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
+ { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
+ { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
+ { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
{ "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] },
- { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] },
+ { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] },
{ "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] },
+ { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] },
{ "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] },
{ "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
+ { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
{ "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
@@ -695,7 +726,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION,
ARG_DUMP_CONFIGURATION_ITEMS,
ARG_DUMP_CORE,
+ ARG_CRASH_CHVT,
ARG_CRASH_SHELL,
+ ARG_CRASH_REBOOT,
ARG_CONFIRM_SPAWN,
ARG_SHOW_STATUS,
ARG_DESERIALIZE,
@@ -718,7 +751,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
+ { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT },
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
+ { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT },
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN },
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE },
@@ -803,7 +838,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_UNIT:
- r = set_default_unit(optarg);
+ r = free_and_strdup(&arg_default_unit, optarg);
if (r < 0)
return log_error_errno(r, "Failed to set default unit %s: %m", optarg);
@@ -836,21 +871,42 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_DUMP_CORE:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse dump core boolean %s.", optarg);
- return r;
+ if (!optarg)
+ arg_dump_core = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg);
+ arg_dump_core = r;
}
- arg_dump_core = r;
+ break;
+
+ case ARG_CRASH_CHVT:
+ r = parse_crash_chvt(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg);
break;
case ARG_CRASH_SHELL:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse crash shell boolean %s.", optarg);
- return r;
+ if (!optarg)
+ arg_crash_shell = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ arg_crash_shell = r;
+ }
+ break;
+
+ case ARG_CRASH_REBOOT:
+ if (!optarg)
+ arg_crash_reboot = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ arg_crash_reboot = r;
}
- arg_crash_shell = r;
break;
case ARG_CONFIRM_SPAWN:
@@ -880,17 +936,16 @@ static int parse_argv(int argc, char *argv[]) {
r = safe_atoi(optarg, &fd);
if (r < 0 || fd < 0) {
log_error("Failed to parse deserialize option %s.", optarg);
- return r < 0 ? r : -EINVAL;
+ return -EINVAL;
}
- fd_cloexec(fd, true);
+ (void) fd_cloexec(fd, true);
f = fdopen(fd, "r");
if (!f)
return log_error_errno(errno, "Failed to open serialization fd: %m");
safe_fclose(arg_serialization);
-
arg_serialization = f;
break;
@@ -950,14 +1005,16 @@ static int help(void) {
" --unit=UNIT Set default unit\n"
" --system Run a system instance, even if PID != 1\n"
" --user Run a user instance\n"
- " --dump-core[=0|1] Dump core on crash\n"
- " --crash-shell[=0|1] Run shell on crash\n"
- " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n"
- " --show-status[=0|1] Show status updates on the console during bootup\n"
+ " --dump-core[=BOOL] Dump core on crash\n"
+ " --crash-vt=NR Change to specified VT on crash\n"
+ " --crash-reboot[=BOOL] Reboot on crash\n"
+ " --crash-shell[=BOOL] Run shell on crash\n"
+ " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n"
+ " --show-status[=BOOL] Show status updates on the console during bootup\n"
" --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n"
" --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
- " --log-color[=0|1] Highlight important log messages\n"
- " --log-location[=0|1] Include code location in log messages\n"
+ " --log-color[=BOOL] Highlight important log messages\n"
+ " --log-location[=BOOL] Include code location in log messages\n"
" --default-standard-output= Set default standard output for services\n"
" --default-standard-error= Set default standard error output for services\n",
program_invocation_short_name);
@@ -965,16 +1022,9 @@ static int help(void) {
return 0;
}
-static int version(void) {
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
-
- return 0;
-}
-
static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) {
- FILE *f = NULL;
- FDSet *fds = NULL;
+ _cleanup_fdset_free_ FDSet *fds = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
@@ -982,56 +1032,39 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
assert(_fds);
r = manager_open_serialization(m, &f);
- if (r < 0) {
- log_error_errno(r, "Failed to create serialization file: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create serialization file: %m");
/* Make sure nothing is really destructed when we shut down */
m->n_reloading ++;
bus_manager_send_reloading(m, true);
fds = fdset_new();
- if (!fds) {
- r = -ENOMEM;
- log_error_errno(r, "Failed to allocate fd set: %m");
- goto fail;
- }
+ if (!fds)
+ return log_oom();
r = manager_serialize(m, f, fds, switching_root);
- if (r < 0) {
- log_error_errno(r, "Failed to serialize state: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize state: %m");
- if (fseeko(f, 0, SEEK_SET) < 0) {
- log_error_errno(errno, "Failed to rewind serialization fd: %m");
- goto fail;
- }
+ if (fseeko(f, 0, SEEK_SET) == (off_t) -1)
+ return log_error_errno(errno, "Failed to rewind serialization fd: %m");
r = fd_cloexec(fileno(f), false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
r = fdset_cloexec(fds, false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
*_f = f;
*_fds = fds;
- return 0;
-
-fail:
- fdset_free(fds);
-
- safe_fclose(f);
+ f = NULL;
+ fds = NULL;
- return r;
+ return 0;
}
static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
@@ -1066,33 +1099,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
return 0;
}
-static void test_mtab(void) {
-
- static const char ok[] =
- "/proc/self/mounts\0"
- "/proc/mounts\0"
- "../proc/self/mounts\0"
- "../proc/mounts\0";
-
- _cleanup_free_ char *p = NULL;
- int r;
-
- /* Check that /etc/mtab is a symlink to the right place or
- * non-existing. But certainly not a file, or a symlink to
- * some weird place... */
-
- r = readlink_malloc("/etc/mtab", &p);
- if (r == -ENOENT)
- return;
- if (r >= 0 && nulstr_contains(ok, p))
- return;
-
- log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
- "This is not supported anymore. "
- "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
- freeze();
-}
-
static void test_usr(void) {
/* Check that /usr is not a separate fs */
@@ -1116,15 +1122,19 @@ static int initialize_join_controllers(void) {
return -ENOMEM;
arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL);
- arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
- arg_join_controllers[2] = NULL;
+ if (!arg_join_controllers[0])
+ goto oom;
- if (!arg_join_controllers[0] || !arg_join_controllers[1]) {
- free_join_controllers();
- return -ENOMEM;
- }
+ arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
+ if (!arg_join_controllers[1])
+ goto oom;
+ arg_join_controllers[2] = NULL;
return 0;
+
+oom:
+ arg_join_controllers = strv_free_free(arg_join_controllers);
+ return -ENOMEM;
}
static int enforce_syscall_archs(Set *archs) {
@@ -1191,12 +1201,50 @@ static int status_welcome(void) {
static int write_container_id(void) {
const char *c;
+ int r;
c = getenv("container");
if (isempty(c))
return 0;
- return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
+
+ return 1;
+}
+
+static int bump_unix_max_dgram_qlen(void) {
+ _cleanup_free_ char *qlen = NULL;
+ unsigned long v;
+ int r;
+
+ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
+ * default of 16 is simply too low. We set the value really
+ * really early during boot, so that it is actually applied to
+ * all our sockets, including the $NOTIFY_SOCKET one. */
+
+ r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
+
+ r = safe_atolu(qlen, &v);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
+
+ if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
+ return 0;
+
+ qlen = mfree(qlen);
+ if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
+ return log_oom();
+
+ r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
+ if (r < 0)
+ return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
+
+ return 1;
}
int main(int argc, char *argv[]) {
@@ -1222,7 +1270,6 @@ int main(int argc, char *argv[]) {
char *switch_root_dir = NULL, *switch_root_init = NULL;
struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0);
const char *error_message = NULL;
- uint8_t shutdown_exit_code = 0;
#ifdef HAVE_SYSV_COMPAT
if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
@@ -1369,7 +1416,7 @@ int main(int argc, char *argv[]) {
}
/* Initialize default unit */
- r = set_default_unit(SPECIAL_DEFAULT_TARGET);
+ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
if (r < 0) {
log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
error_message = "Failed to set default unit";
@@ -1563,8 +1610,8 @@ int main(int argc, char *argv[]) {
hostname_setup();
machine_id_setup(NULL);
loopback_setup();
+ bump_unix_max_dgram_qlen();
- test_mtab();
test_usr();
}
@@ -1646,8 +1693,7 @@ int main(int argc, char *argv[]) {
/* This will close all file descriptors that were opened, but
* not claimed by any unit. */
- fdset_free(fds);
- fds = NULL;
+ fds = fdset_free(fds);
arg_serialization = safe_fclose(arg_serialization);
@@ -1775,8 +1821,9 @@ int main(int argc, char *argv[]) {
goto finish;
case MANAGER_EXIT:
+ retval = m->return_value;
+
if (m->running_as == MANAGER_USER) {
- retval = EXIT_SUCCESS;
log_debug("Exit.");
goto finish;
}
@@ -1809,21 +1856,17 @@ int main(int argc, char *argv[]) {
finish:
pager_close();
- if (m) {
+ if (m)
arg_shutdown_watchdog = m->shutdown_watchdog;
- shutdown_exit_code = m->return_value;
- }
+
m = manager_free(m);
for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++)
arg_default_rlimit[j] = mfree(arg_default_rlimit[j]);
arg_default_unit = mfree(arg_default_unit);
-
- free_join_controllers();
-
+ arg_join_controllers = strv_free_free(arg_join_controllers);
arg_default_environment = strv_free(arg_default_environment);
-
arg_syscall_archs = set_free(arg_syscall_archs);
mac_selinux_finish();
@@ -1841,7 +1884,7 @@ finish:
* that the new systemd can pass the kernel default to
* its child processes */
if (saved_rlimit_nofile.rlim_cur > 0)
- setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
+ (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
if (switch_root_dir) {
/* Kill all remaining processes from the
@@ -1883,10 +1926,10 @@ finish:
/* do not pass along the environment we inherit from the kernel or initrd */
if (switch_root_dir)
- clearenv();
+ (void) clearenv();
assert(i <= args_size);
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
}
/* Try the fallback, if there is any, without any
@@ -1896,14 +1939,10 @@ finish:
* but let's hope that doesn't matter.) */
arg_serialization = safe_fclose(arg_serialization);
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
+ fds = fdset_free(fds);
/* Reopen the console */
- make_console_stdio();
+ (void) make_console_stdio();
for (j = 1, i = 1; j < (unsigned) argc; j++)
args[i++] = argv[j];
@@ -1917,30 +1956,26 @@ finish:
if (switch_root_init) {
args[0] = switch_root_init;
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
}
args[0] = "/sbin/init";
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
if (errno == ENOENT) {
log_warning("No /sbin/init, trying fallback");
args[0] = "/bin/sh";
args[1] = NULL;
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
} else
log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m");
}
arg_serialization = safe_fclose(arg_serialization);
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
+ fds = fdset_free(fds);
#ifdef HAVE_VALGRIND_VALGRIND_H
/* If we are PID 1 and running under valgrind, then let's exit
@@ -1969,6 +2004,7 @@ finish:
xsprintf(log_level, "%d", log_get_max_level());
switch (log_get_target()) {
+
case LOG_TARGET_KMSG:
case LOG_TARGET_JOURNAL_OR_KMSG:
case LOG_TARGET_SYSLOG_OR_KMSG:
@@ -1994,7 +2030,7 @@ finish:
if (streq(shutdown_verb, "exit")) {
command_line[pos++] = "--exit-code";
command_line[pos++] = exit_code;
- xsprintf(exit_code, "%d", shutdown_exit_code);
+ xsprintf(exit_code, "%d", retval);
}
assert(pos < ELEMENTSOF(command_line));
@@ -2010,7 +2046,7 @@ finish:
/* Tell the binary how often to ping, ignore failure */
if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0)
- strv_push(&env_block, e);
+ (void) strv_push(&env_block, e);
} else
watchdog_close(true);
@@ -2030,7 +2066,7 @@ finish:
manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL,
"%s, freezing.", error_message);
- freeze();
+ freeze_or_reboot();
}
return retval;
diff --git a/src/core/manager.c b/src/core/manager.c
index 9bfe867ea0..b13663e702 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -19,19 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <linux/kd.h>
#include <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/inotify.h>
+#include <string.h>
#include <sys/epoll.h>
-#include <sys/reboot.h>
+#include <sys/inotify.h>
#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <fcntl.h>
-#include <dirent.h>
+#include <sys/reboot.h>
#include <sys/timerfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
@@ -40,40 +40,53 @@
#include "sd-daemon.h"
#include "sd-messages.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "util.h"
-#include "mkdir.h"
-#include "ratelimit.h"
-#include "locale-setup.h"
-#include "unit-name.h"
-#include "missing.h"
-#include "rm-rf.h"
-#include "path-lookup.h"
-#include "special.h"
-#include "exit-status.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "path-util.h"
+#include "alloc-util.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
-#include "env-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
-#include "bus-util.h"
#include "bus-kernel.h"
-#include "time-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "dbus.h"
-#include "dbus-unit.h"
+#include "bus-util.h"
#include "dbus-job.h"
#include "dbus-manager.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "env-util.h"
+#include "escape.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hashmap.h"
+#include "io-util.h"
+#include "locale-setup.h"
+#include "log.h"
+#include "macro.h"
#include "manager.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-lookup.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "signal-util.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "time-util.h"
#include "transaction.h"
+#include "umask-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "virt.h"
+#include "watchdog.h"
+
+#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -495,6 +508,7 @@ static void manager_clean_environment(Manager *m) {
"MANAGERPID",
"LISTEN_PID",
"LISTEN_FDS",
+ "LISTEN_FDNAMES",
"WATCHDOG_PID",
"WATCHDOG_USEC",
NULL);
@@ -677,6 +691,8 @@ static int manager_setup_notify(Manager *m) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate notification socket: %m");
+ fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
+
if (m->running_as == MANAGER_SYSTEM)
m->notify_socket = strdup("/run/systemd/notify");
else {
@@ -1476,7 +1492,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
return n;
}
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
+static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
assert(m);
@@ -1497,9 +1513,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
}
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ _cleanup_fdset_free_ FDSet *fds = NULL;
Manager *m = userdata;
+
+ char buf[NOTIFY_BUFFER_MAX+1];
+ struct iovec iovec = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)-1,
+ };
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
+ } control = {};
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+
+ struct cmsghdr *cmsg;
+ struct ucred *ucred = NULL;
+ bool found = false;
+ Unit *u1, *u2, *u3;
+ int r, *fd_array = NULL;
+ unsigned n_fds = 0;
ssize_t n;
- int r;
assert(m);
assert(m->notify_fd == fd);
@@ -1509,106 +1549,80 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
return 0;
}
- for (;;) {
- _cleanup_fdset_free_ FDSet *fds = NULL;
- char buf[NOTIFY_BUFFER_MAX+1];
- struct iovec iovec = {
- .iov_base = buf,
- .iov_len = sizeof(buf)-1,
- };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
- struct msghdr msghdr = {
- .msg_iov = &iovec,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- struct ucred *ucred = NULL;
- bool found = false;
- Unit *u1, *u2, *u3;
- int *fd_array = NULL;
- unsigned n_fds = 0;
-
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
+ n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (n < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
- return -errno;
- }
+ return -errno;
+ }
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ CMSG_FOREACH(cmsg, &msghdr) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- fd_array = (int*) CMSG_DATA(cmsg);
- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+ fd_array = (int*) CMSG_DATA(cmsg);
+ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
- } else if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
}
+ }
- if (n_fds > 0) {
- assert(fd_array);
+ if (n_fds > 0) {
+ assert(fd_array);
- r = fdset_new_array(&fds, fd_array, n_fds);
- if (r < 0) {
- close_many(fd_array, n_fds);
- return log_oom();
- }
+ r = fdset_new_array(&fds, fd_array, n_fds);
+ if (r < 0) {
+ close_many(fd_array, n_fds);
+ return log_oom();
}
+ }
- if (!ucred || ucred->pid <= 0) {
- log_warning("Received notify message without valid credentials. Ignoring.");
- continue;
- }
+ if (!ucred || ucred->pid <= 0) {
+ log_warning("Received notify message without valid credentials. Ignoring.");
+ return 0;
+ }
- if ((size_t) n >= sizeof(buf)) {
- log_warning("Received notify message exceeded maximum size. Ignoring.");
- continue;
- }
+ if ((size_t) n >= sizeof(buf)) {
+ log_warning("Received notify message exceeded maximum size. Ignoring.");
+ return 0;
+ }
- buf[n] = 0;
+ buf[n] = 0;
- /* Notify every unit that might be interested, but try
- * to avoid notifying the same one multiple times. */
- u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
- if (u1) {
- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
- found = true;
- }
+ /* Notify every unit that might be interested, but try
+ * to avoid notifying the same one multiple times. */
+ u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
+ if (u1) {
+ manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
+ found = true;
+ }
- u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
- if (u2 && u2 != u1) {
- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
- found = true;
- }
+ u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
+ if (u2 && u2 != u1) {
+ manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
+ found = true;
+ }
- u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
- if (u3 && u3 != u2 && u3 != u1) {
- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
- found = true;
- }
+ u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
+ if (u3 && u3 != u2 && u3 != u1) {
+ manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
+ found = true;
+ }
- if (!found)
- log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
+ if (!found)
+ log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
- if (fdset_size(fds) > 0)
- log_warning("Got auxiliary fds with notification message, closing all.");
- }
+ if (fdset_size(fds) > 0)
+ log_warning("Got auxiliary fds with notification message, closing all.");
return 0;
}
-static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
+static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
assert(m);
assert(u);
assert(si);
@@ -1990,8 +2004,7 @@ int manager_loop(Manager *m) {
m->exit_code = MANAGER_OK;
/* Release the path cache */
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
+ m->unit_path_cache = set_free_free(m->unit_path_cache);
manager_check_finished(m);
@@ -2101,6 +2114,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
const char *msg;
int audit_fd, r;
+ if (m->running_as != MANAGER_SYSTEM)
+ return;
+
audit_fd = get_audit_fd();
if (audit_fd < 0)
return;
@@ -2110,9 +2126,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
if (m->n_reloading > 0)
return;
- if (m->running_as != MANAGER_SYSTEM)
- return;
-
if (u->type != UNIT_SERVICE)
return;
@@ -2761,8 +2774,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
return log_oom();
if (!mkdtemp(p)) {
- log_error_errno(errno, "Failed to create generator directory %s: %m",
- p);
+ log_error_errno(errno, "Failed to create generator directory %s: %m", p);
free(p);
return -errno;
}
@@ -2951,9 +2963,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
m->show_status = mode;
if (mode > 0)
- touch("/run/systemd/show-status");
+ (void) touch("/run/systemd/show-status");
else
- unlink("/run/systemd/show-status");
+ (void) unlink("/run/systemd/show-status");
}
static bool manager_get_show_status(Manager *m, StatusType type) {
@@ -3012,30 +3024,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
va_end(ap);
}
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
- _cleanup_free_ char *p = NULL;
- Unit *found;
- int r;
-
- assert(m);
- assert(path);
- assert(suffix);
- assert(_found);
-
- r = unit_name_from_path(path, suffix, &p);
- if (r < 0)
- return r;
-
- found = manager_get_unit(m, p);
- if (!found) {
- *_found = NULL;
- return 0;
- }
-
- *_found = found;
- return 1;
-}
-
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
char p[strlen(path)+1];
diff --git a/src/core/manager.h b/src/core/manager.h
index cc0e5e3361..38d2770e97 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -27,8 +27,8 @@
#include "sd-bus.h"
#include "sd-event.h"
-#include "fdset.h"
#include "cgroup-util.h"
+#include "fdset.h"
#include "hashmap.h"
#include "list.h"
#include "ratelimit.h"
@@ -69,11 +69,11 @@ typedef enum StatusType {
STATUS_TYPE_EMERGENCY,
} StatusType;
+#include "execute.h"
#include "job.h"
#include "path-lookup.h"
-#include "execute.h"
-#include "unit-name.h"
#include "show-status.h"
+#include "unit-name.h"
struct Manager {
/* Note that the set of units we know of is allowed to be
@@ -322,8 +322,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
-
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 9b16eaa0e2..b2596d1cd1 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -25,22 +25,25 @@
#include <unistd.h>
#include <ftw.h>
-#include "mount-setup.h"
-#include "dev-setup.h"
+#include "alloc-util.h"
#include "bus-util.h"
+#include "cgroup-util.h"
+#include "dev-setup.h"
+#include "efivars.h"
+#include "label.h"
#include "log.h"
#include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
+#include "missing.h"
#include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
#include "path-util.h"
-#include "missing.h"
-#include "virt.h"
-#include "efivars.h"
+#include "set.h"
#include "smack-util.h"
-#include "cgroup-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
typedef enum MountMode {
MNT_NONE = 0,
diff --git a/src/core/mount.c b/src/core/mount.c
index e7aae6e19a..950d5d76d5 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -20,25 +20,34 @@
***/
#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <sys/epoll.h>
-#include <signal.h>
-#include "manager.h"
-#include "unit.h"
-#include "mount.h"
-#include "log.h"
#include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "mount-setup.h"
-#include "unit-name.h"
+
+#include "alloc-util.h"
#include "dbus-mount.h"
-#include "special.h"
+#include "escape.h"
#include "exit-status.h"
-#include "fstab-util.h"
#include "formats-util.h"
+#include "fstab-util.h"
+#include "log.h"
+#include "manager.h"
+#include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "smack-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit.h"
#define RETRY_UMOUNT_MAX 32
@@ -202,6 +211,7 @@ static void mount_done(Unit *u) {
assert(m);
m->where = mfree(m->where);
+ m->smack_fs_root_label = mfree(m->smack_fs_root_label);
mount_parameters_done(&m->parameters_proc_self_mountinfo);
mount_parameters_done(&m->parameters_fragment);
@@ -246,9 +256,10 @@ static int mount_add_mount_links(Mount *m) {
if (!path_equal(m->where, "/")) {
/* Adds in links to other mount points that might lie further
* up in the hierarchy */
- r = path_get_parent(m->where, &parent);
- if (r < 0)
- return r;
+
+ parent = dirname_malloc(m->where);
+ if (!parent)
+ return -ENOMEM;
r = unit_require_mounts_for(UNIT(m), parent);
if (r < 0)
@@ -621,19 +632,19 @@ static int mount_coldplug(Unit *u) {
if (new_state == m->state)
return 0;
- if (new_state == MOUNT_MOUNTING ||
- new_state == MOUNT_MOUNTING_DONE ||
- new_state == MOUNT_REMOUNTING ||
- new_state == MOUNT_UNMOUNTING ||
- new_state == MOUNT_MOUNTING_SIGTERM ||
- new_state == MOUNT_MOUNTING_SIGKILL ||
- new_state == MOUNT_UNMOUNTING_SIGTERM ||
- new_state == MOUNT_UNMOUNTING_SIGKILL ||
- new_state == MOUNT_REMOUNTING_SIGTERM ||
- new_state == MOUNT_REMOUNTING_SIGKILL) {
-
- if (m->control_pid <= 0)
- return -EBADMSG;
+ if (m->control_pid > 0 &&
+ pid_is_unwaited(m->control_pid) &&
+ IN_SET(new_state,
+ MOUNT_MOUNTING,
+ MOUNT_MOUNTING_DONE,
+ MOUNT_REMOUNTING,
+ MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM,
+ MOUNT_MOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
@@ -666,7 +677,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
"%sOptions: %s\n"
"%sFrom /proc/self/mountinfo: %s\n"
"%sFrom fragment: %s\n"
- "%sDirectoryMode: %04o\n",
+ "%sDirectoryMode: %04o\n"
+ "%sSmackFileSystemRootLabel: %s\n",
prefix, mount_state_to_string(m->state),
prefix, mount_result_to_string(m->result),
prefix, m->where,
@@ -675,7 +687,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
prefix, p ? strna(p->options) : "n/a",
prefix, yes_no(m->from_proc_self_mountinfo),
prefix, yes_no(m->from_fragment),
- prefix, m->directory_mode);
+ prefix, m->directory_mode,
+ prefix, strna(m->smack_fs_root_label));
if (m->control_pid > 0)
fprintf(f,
@@ -694,6 +707,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(m);
@@ -849,6 +865,31 @@ fail:
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
}
+static int mount_get_opts(Mount *m, char **_opts) {
+ int r;
+ char *o = NULL, *opts = NULL;
+
+ r = fstab_filter_options(m->parameters_fragment.options,
+ "nofail\0" "noauto\0" "auto\0", NULL, NULL, &o);
+ if (r < 0)
+ return r;
+
+ if (mac_smack_use() && m->smack_fs_root_label) {
+ if (!isempty(o)) {
+ opts = strjoin(o, ",", "smackfsroot=", m->smack_fs_root_label, NULL);
+ free(o);
+ } else
+ opts = strjoin("smackfsroot=", m->smack_fs_root_label, NULL);
+
+ if (!opts)
+ return -ENOMEM;
+ } else
+ opts = o;
+
+ *_opts = opts;
+ return 0;
+}
+
static void mount_enter_mounting(Mount *m) {
int r;
MountParameters *p;
@@ -874,8 +915,7 @@ static void mount_enter_mounting(Mount *m) {
if (m->from_fragment) {
_cleanup_free_ char *opts = NULL;
- r = fstab_filter_options(m->parameters_fragment.options,
- "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
+ r = mount_get_opts(m, &opts);
if (r < 0)
goto fail;
@@ -1756,24 +1796,6 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}
-static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
- [MOUNT_DEAD] = "dead",
- [MOUNT_MOUNTING] = "mounting",
- [MOUNT_MOUNTING_DONE] = "mounting-done",
- [MOUNT_MOUNTED] = "mounted",
- [MOUNT_REMOUNTING] = "remounting",
- [MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
- [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
- [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
- [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
- [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
- [MOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
-
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
diff --git a/src/core/mount.h b/src/core/mount.h
index 280ea0d638..b344b5aa13 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -26,24 +26,6 @@ typedef struct Mount Mount;
#include "kill.h"
#include "execute.h"
-typedef enum MountState {
- MOUNT_DEAD,
- MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
- MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_FAILED,
- _MOUNT_STATE_MAX,
- _MOUNT_STATE_INVALID = -1
-} MountState;
-
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
MOUNT_EXEC_UNMOUNT,
@@ -89,6 +71,7 @@ struct Mount {
bool reset_cpu_usage:1;
bool sloppy_options;
+ char *smack_fs_root_label;
MountResult result;
MountResult reload_result;
@@ -120,9 +103,6 @@ extern const UnitVTable mount_vtable;
void mount_fd_event(Manager *m, int events);
-const char* mount_state_to_string(MountState i) _const_;
-MountState mount_state_from_string(const char *s) _pure_;
-
const char* mount_exec_command_to_string(MountExecCommand i) _const_;
MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index eb88574f8f..81ba09ea5d 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -20,23 +20,31 @@
***/
#include <errno.h>
-#include <sys/mount.h>
-#include <string.h>
+#include <sched.h>
#include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <sys/mount.h>
#include <sys/stat.h>
-#include <sched.h>
+#include <unistd.h>
#include <linux/fs.h>
-#include "strv.h"
-#include "util.h"
-#include "path-util.h"
-#include "missing.h"
-#include "loopback-setup.h"
+#include "alloc-util.h"
#include "dev-setup.h"
-#include "selinux-util.h"
-#include "namespace.h"
+#include "fd-util.h"
+#include "loopback-setup.h"
+#include "missing.h"
#include "mkdir.h"
+#include "mount-util.h"
+#include "namespace.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "user-util.h"
+#include "util.h"
typedef enum MountMode {
/* This is ordered by priority! */
@@ -643,16 +651,7 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
int setup_netns(int netns_storage_socket[2]) {
_cleanup_close_ int netns = -1;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- int r;
+ int r, q;
assert(netns_storage_socket);
assert(netns_storage_socket[0] >= 0);
@@ -669,12 +668,8 @@ int setup_netns(int netns_storage_socket[2]) {
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
return -errno;
- if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) {
- if (errno != EAGAIN) {
- r = -errno;
- goto fail;
- }
-
+ netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
+ if (netns == -EAGAIN) {
/* Nothing stored yet, so let's create a new namespace */
if (unshare(CLONE_NEWNET) < 0) {
@@ -691,15 +686,13 @@ int setup_netns(int netns_storage_socket[2]) {
}
r = 1;
- } else {
- /* Yay, found something, so let's join the namespace */
- CMSG_FOREACH(cmsg, &mh)
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
- netns = *(int*) CMSG_DATA(cmsg);
- }
+ } else if (netns < 0) {
+ r = netns;
+ goto fail;
+ } else {
+ /* Yay, found something, so let's join the namespace */
if (setns(netns, CLONE_NEWNET) < 0) {
r = -errno;
goto fail;
@@ -708,21 +701,14 @@ int setup_netns(int netns_storage_socket[2]) {
r = 0;
}
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &netns, sizeof(int));
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) {
- r = -errno;
+ q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
+ if (q < 0) {
+ r = q;
goto fail;
}
fail:
lockf(netns_storage_socket[0], F_ULOCK, 0);
-
return r;
}
diff --git a/src/core/path.c b/src/core/path.c
index e9111d0612..35e1753583 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -19,20 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/inotify.h>
-#include <sys/epoll.h>
#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
#include <unistd.h>
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "dbus-path.h"
-#include "special.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
#include "macro.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "mkdir.h"
+#include "path.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
[PATH_DEAD] = UNIT_INACTIVE,
@@ -715,15 +721,6 @@ static void path_reset_failed(Unit *u) {
p->result = PATH_SUCCESS;
}
-static const char* const path_state_table[_PATH_STATE_MAX] = {
- [PATH_DEAD] = "dead",
- [PATH_WAITING] = "waiting",
- [PATH_RUNNING] = "running",
- [PATH_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
-
static const char* const path_type_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = "PathExists",
[PATH_EXISTS_GLOB] = "PathExistsGlob",
diff --git a/src/core/path.h b/src/core/path.h
index dec39333e4..deb9bab1e5 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -26,15 +26,6 @@ typedef struct PathSpec PathSpec;
#include "unit.h"
-typedef enum PathState {
- PATH_DEAD,
- PATH_WAITING,
- PATH_RUNNING,
- PATH_FAILED,
- _PATH_STATE_MAX,
- _PATH_STATE_INVALID = -1
-} PathState;
-
typedef enum PathType {
PATH_EXISTS,
PATH_EXISTS_GLOB,
@@ -96,9 +87,6 @@ void path_free_specs(Path *p);
extern const UnitVTable path_vtable;
-const char* path_state_to_string(PathState i) _const_;
-PathState path_state_from_string(const char *s) _pure_;
-
const char* path_type_to_string(PathType i) _const_;
PathType path_type_from_string(const char *s) _pure_;
diff --git a/src/core/scope.c b/src/core/scope.c
index 98395becfd..6bacb226e8 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -22,14 +22,17 @@
#include <errno.h>
#include <unistd.h>
+#include "alloc-util.h"
+#include "dbus-scope.h"
+#include "load-dropin.h"
#include "log.h"
-#include "strv.h"
+#include "scope.h"
#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "unit.h"
-#include "scope.h"
-#include "dbus-scope.h"
-#include "load-dropin.h"
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = UNIT_INACTIVE,
@@ -534,6 +537,9 @@ static int scope_enumerate(Manager *m) {
u->transient = true;
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SCOPE(u)->deserialized_state = SCOPE_RUNNING;
SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
@@ -549,17 +555,6 @@ static int scope_enumerate(Manager *m) {
return 0;
}
-static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
- [SCOPE_DEAD] = "dead",
- [SCOPE_RUNNING] = "running",
- [SCOPE_ABANDONED] = "abandoned",
- [SCOPE_STOP_SIGTERM] = "stop-sigterm",
- [SCOPE_STOP_SIGKILL] = "stop-sigkill",
- [SCOPE_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
-
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
[SCOPE_SUCCESS] = "success",
[SCOPE_FAILURE_RESOURCES] = "resources",
diff --git a/src/core/scope.h b/src/core/scope.h
index 4452fe2c94..f838ee5357 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -25,17 +25,6 @@ typedef struct Scope Scope;
#include "kill.h"
-typedef enum ScopeState {
- SCOPE_DEAD,
- SCOPE_RUNNING,
- SCOPE_ABANDONED,
- SCOPE_STOP_SIGTERM,
- SCOPE_STOP_SIGKILL,
- SCOPE_FAILED,
- _SCOPE_STATE_MAX,
- _SCOPE_STATE_INVALID = -1
-} ScopeState;
-
typedef enum ScopeResult {
SCOPE_SUCCESS,
SCOPE_FAILURE_RESOURCES,
@@ -64,8 +53,5 @@ extern const UnitVTable scope_vtable;
int scope_abandon(Scope *s);
-const char* scope_state_to_string(ScopeState i) _const_;
-ScopeState scope_state_from_string(const char *s) _pure_;
-
const char* scope_result_to_string(ScopeResult i) _const_;
ScopeResult scope_result_from_string(const char *s) _pure_;
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 40ca0c6166..4bcdd27389 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -32,13 +32,16 @@
#endif
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "audit-fd.h"
#include "bus-util.h"
-#include "util.h"
#include "log.h"
+#include "path-util.h"
#include "selinux-util.h"
-#include "audit-fd.h"
+#include "stdio-util.h"
#include "strv.h"
-#include "path-util.h"
+#include "util.h"
static bool initialized = false;
@@ -178,17 +181,6 @@ static int mac_selinux_access_init(sd_bus_error *error) {
}
#endif
-void mac_selinux_access_free(void) {
-
-#ifdef HAVE_SELINUX
- if (!initialized)
- return;
-
- avc_destroy();
- initialized = false;
-#endif
-}
-
/*
This function communicates with the kernel to check whether or not it should
allow the access.
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index e6b4dd7fee..30725521cb 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -25,8 +25,6 @@
#include "bus-util.h"
#include "manager.h"
-void mac_selinux_access_free(void);
-
int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
#ifdef HAVE_SELINUX
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index e5b457643b..d9b00fb95c 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -19,19 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
-#include "selinux-setup.h"
-#include "selinux-util.h"
+#include "log.h"
#include "macro.h"
+#include "selinux-util.h"
+#include "string-util.h"
#include "util.h"
-#include "log.h"
+#include "selinux-setup.h"
#ifdef HAVE_SELINUX
_printf_(2,3)
@@ -78,14 +79,14 @@ int mac_selinux_setup(bool *loaded_policy) {
before_load = now(CLOCK_MONOTONIC);
r = selinux_init_load_policy(&enforce);
if (r == 0) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
char timespan[FORMAT_TIMESPAN_MAX];
- char *label;
mac_selinux_retest();
/* Transition to the new context */
r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
- if (r < 0 || label == NULL) {
+ if (r < 0 || !label) {
log_open();
log_error("Failed to compute init label, ignoring.");
} else {
@@ -94,8 +95,6 @@ int mac_selinux_setup(bool *loaded_policy) {
log_open();
if (r < 0)
log_error("Failed to transition into init label '%s', ignoring.", label);
-
- mac_selinux_free(label);
}
after_load = now(CLOCK_MONOTONIC);
diff --git a/src/core/service.c b/src/core/service.c
index f7de5e89ff..586eddd99a 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -23,31 +23,38 @@
#include <signal.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "async.h"
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
#include "dbus-service.h"
-#include "special.h"
-#include "exit-status.h"
#include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
#include "env-util.h"
+#include "escape.h"
+#include "exit-status.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "manager.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
+#include "service.h"
#include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "util.h"
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
@@ -108,6 +115,7 @@ static void service_init(Unit *u) {
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -1;
s->bus_endpoint_fd = -1;
+ s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
s->guess_main_pid = true;
RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@@ -167,7 +175,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid = pid;
s->main_pid_known = true;
- if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
+ if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) {
log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
s->main_pid_alien = true;
} else
@@ -261,6 +269,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
sd_event_source_unref(fs->event_source);
}
+ free(fs->fdname);
safe_close(fs->fd);
free(fs);
}
@@ -270,11 +279,15 @@ static void service_release_resources(Unit *u) {
assert(s);
- if (!s->fd_store)
+ if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
return;
log_unit_debug(u, "Releasing all resources.");
+ s->stdin_fd = safe_close(s->stdin_fd);
+ s->stdout_fd = safe_close(s->stdout_fd);
+ s->stderr_fd = safe_close(s->stderr_fd);
+
while (s->fd_store)
service_fd_store_unlink(s->fd_store);
@@ -334,7 +347,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
return 0;
}
-static int service_add_fd_store(Service *s, int fd) {
+static int service_add_fd_store(Service *s, int fd, const char *name) {
ServiceFDStore *fs;
int r;
@@ -361,9 +374,15 @@ static int service_add_fd_store(Service *s, int fd) {
fs->fd = fd;
fs->service = s;
+ fs->fdname = strdup(name ?: "stored");
+ if (!fs->fdname) {
+ free(fs);
+ return -ENOMEM;
+ }
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0) {
+ free(fs->fdname);
free(fs);
return r;
}
@@ -376,7 +395,7 @@ static int service_add_fd_store(Service *s, int fd) {
return 1;
}
-static int service_add_fd_store_set(Service *s, FDSet *fds) {
+static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
int r;
assert(s);
@@ -391,7 +410,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
if (fd < 0)
break;
- r = service_add_fd_store(s, fd);
+ r = service_add_fd_store(s, fd, name);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
if (r > 0) {
@@ -401,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
}
if (fdset_size(fds) > 0)
- log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
+ log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
return 0;
}
@@ -884,7 +903,6 @@ static void service_set_state(Service *s, ServiceState state) {
log_unit_debug(UNIT(s), "Changed %s -> %s", 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;
}
static int service_coldplug(Unit *u) {
@@ -894,125 +912,143 @@ static int service_coldplug(Unit *u) {
assert(s);
assert(s->state == SERVICE_DEAD);
- if (s->deserialized_state != s->state) {
-
- if (IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-
- usec_t k;
-
- k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
+ if (s->deserialized_state == s->state)
+ return 0;
- /* For the start/stop timeouts 0 means off */
- if (k > 0) {
- r = service_arm_timer(s, k);
- if (r < 0)
- return r;
- }
- }
+ if (IN_SET(s->deserialized_state,
+ SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- if (s->deserialized_state == SERVICE_AUTO_RESTART) {
+ usec_t k;
- /* The restart timeouts 0 means immediately */
- r = service_arm_timer(s, s->restart_usec);
- if (r < 0)
- return r;
- }
+ k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
- if (pid_is_unwaited(s->main_pid) &&
- ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
- IN_SET(s->deserialized_state,
- SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid);
+ /* For the start/stop timeouts 0 means off */
+ if (k > 0) {
+ r = service_arm_timer(s, k);
if (r < 0)
return r;
}
+ }
- if (pid_is_unwaited(s->control_pid) &&
- IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
- }
+ if (s->deserialized_state == SERVICE_AUTO_RESTART) {
- if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
- unit_watch_all_pids(UNIT(s));
+ /* The restart timeouts 0 means immediately */
+ r = service_arm_timer(s, s->restart_usec);
+ if (r < 0)
+ return r;
+ }
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
- service_start_watchdog(s);
+ if (s->main_pid > 0 &&
+ pid_is_unwaited(s->main_pid) &&
+ ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
+ IN_SET(s->deserialized_state,
+ SERVICE_START, SERVICE_START_POST,
+ SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+ r = unit_watch_pid(UNIT(s), s->main_pid);
+ if (r < 0)
+ return r;
+ }
- service_set_state(s, s->deserialized_state);
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(s->deserialized_state,
+ SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+ r = unit_watch_pid(UNIT(s), s->control_pid);
+ if (r < 0)
+ return r;
}
+ if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+ unit_watch_all_pids(UNIT(s));
+
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ service_start_watchdog(s);
+
+ service_set_state(s, s->deserialized_state);
return 0;
}
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
+static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
+ _cleanup_strv_free_ char **rfd_names = NULL;
_cleanup_free_ int *rfds = NULL;
- unsigned rn_fds = 0;
- Iterator i;
- int r;
- Unit *u;
+ int rn_fds = 0, r;
assert(s);
assert(fds);
- assert(n_fds);
+ assert(fd_names);
- if (s->socket_fd >= 0)
- return 0;
+ if (s->socket_fd >= 0) {
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- int *cfds;
- unsigned cn_fds;
- Socket *sock;
+ /* Pass the per-connection socket */
- if (u->type != UNIT_SOCKET)
- continue;
+ rfds = new(int, 1);
+ if (!rfds)
+ return -ENOMEM;
+ rfds[0] = s->socket_fd;
- sock = SOCKET(u);
+ rfd_names = strv_new("connection", NULL);
+ if (!rfd_names)
+ return -ENOMEM;
- r = socket_collect_fds(sock, &cfds, &cn_fds);
- if (r < 0)
- return r;
+ rn_fds = 1;
+ } else {
+ Iterator i;
+ Unit *u;
- if (cn_fds <= 0) {
- free(cfds);
- continue;
- }
+ /* Pass all our configured sockets for singleton services */
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
- } else {
- int *t;
+ SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+ _cleanup_free_ int *cfds = NULL;
+ Socket *sock;
+ int cn_fds;
- t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
- if (!t) {
- free(cfds);
- return -ENOMEM;
- }
+ if (u->type != UNIT_SOCKET)
+ continue;
+
+ sock = SOCKET(u);
+
+ cn_fds = socket_collect_fds(sock, &cfds);
+ if (cn_fds < 0)
+ return cn_fds;
+
+ if (cn_fds <= 0)
+ continue;
+
+ if (!rfds) {
+ rfds = cfds;
+ rn_fds = cn_fds;
+
+ cfds = NULL;
+ } else {
+ int *t;
- memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- rfds = t;
- rn_fds += cn_fds;
+ t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
+ if (!t)
+ return -ENOMEM;
+
+ memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- free(cfds);
+ rfds = t;
+ rn_fds += cn_fds;
+ }
+ r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
+ if (r < 0)
+ return r;
}
}
if (s->n_fd_store > 0) {
ServiceFDStore *fs;
+ char **nl;
int *t;
t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
@@ -1020,15 +1056,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
return -ENOMEM;
rfds = t;
- LIST_FOREACH(fd_store, fs, s->fd_store)
- rfds[rn_fds++] = fs->fd;
+
+ nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
+ if (!nl)
+ return -ENOMEM;
+
+ rfd_names = nl;
+
+ LIST_FOREACH(fd_store, fs, s->fd_store) {
+ rfds[rn_fds] = fs->fd;
+ rfd_names[rn_fds] = strdup(strempty(fs->fdname));
+ if (!rfd_names[rn_fds])
+ return -ENOMEM;
+
+ rn_fds++;
+ }
+
+ rfd_names[rn_fds] = NULL;
}
*fds = rfds;
- *n_fds = rn_fds;
+ *fd_names = rfd_names;
rfds = NULL;
- return 0;
+ rfd_names = NULL;
+
+ return rn_fds;
}
static int service_spawn(
@@ -1042,23 +1095,25 @@ static int service_spawn(
bool is_control,
pid_t *_pid) {
- pid_t pid;
- int r;
- int *fds = NULL;
- _cleanup_free_ int *fdsbuf = NULL;
- unsigned n_fds = 0, n_env = 0;
+ _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ char *bus_endpoint_path = NULL;
- _cleanup_strv_free_ char
- **argv = NULL, **final_env = NULL, **our_env = NULL;
+ _cleanup_free_ int *fds = NULL;
+ unsigned n_fds = 0, n_env = 0;
const char *path;
+ pid_t pid;
+
ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
- .selinux_context_net = s->socket_fd_selinux_context_net
+ .apply_permissions = apply_permissions,
+ .apply_chroot = apply_chroot,
+ .apply_tty_stdin = apply_tty_stdin,
+ .bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
+ int r;
+
assert(s);
assert(c);
assert(_pid);
@@ -1078,16 +1133,11 @@ static int service_spawn(
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
- if (s->socket_fd >= 0) {
- fds = &s->socket_fd;
- n_fds = 1;
- } else {
- r = service_collect_fds(s, &fdsbuf, &n_fds);
- if (r < 0)
- goto fail;
+ r = service_collect_fds(s, &fds, &fd_names);
+ if (r < 0)
+ goto fail;
- fds = fdsbuf;
- }
+ n_fds = r;
}
if (timeout > 0) {
@@ -1125,7 +1175,7 @@ static int service_spawn(
goto fail;
}
- if (UNIT_DEREF(s->accept_socket)) {
+ if (s->socket_fd >= 0) {
union sockaddr_union sa;
socklen_t salen = sizeof(sa);
@@ -1173,7 +1223,7 @@ static int service_spawn(
if (is_control && UNIT(s)->cgroup_path) {
path = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+ (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
} else
path = UNIT(s)->cgroup_path;
@@ -1191,6 +1241,7 @@ static int service_spawn(
exec_params.argv = argv;
exec_params.fds = fds;
+ exec_params.fd_names = fd_names;
exec_params.n_fds = n_fds;
exec_params.environment = final_env;
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
@@ -1200,8 +1251,12 @@ static int service_spawn(
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.bus_endpoint_path = bus_endpoint_path;
+ exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
+ exec_params.stdin_fd = s->stdin_fd;
+ exec_params.stdout_fd = s->stdout_fd;
+ exec_params.stderr_fd = s->stderr_fd;
r = exec_spawn(UNIT(s),
c,
@@ -1778,6 +1833,7 @@ static void service_enter_reload(Service *s) {
assert(s);
service_unwatch_control_pid(s);
+ s->reload_result = SERVICE_SUCCESS;
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
@@ -2001,6 +2057,7 @@ _pure_ static bool service_can_reload(Unit *u) {
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
Service *s = SERVICE(u);
ServiceFDStore *fs;
+ int r;
assert(u);
assert(f);
@@ -2019,12 +2076,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
- if (s->status_text) {
- _cleanup_free_ char *c = NULL;
-
- c = cescape(s->status_text);
- unit_serialize_item(u, f, "status-text", strempty(c));
- }
+ r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
+ if (r < 0)
+ return r;
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here, we will start from the
@@ -2032,34 +2086,34 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->control_command_id >= 0)
unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
- if (s->socket_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->socket_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
- }
-
- if (s->bus_endpoint_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->bus_endpoint_fd);
- if (copy < 0)
- return copy;
+ r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
+ if (r < 0)
+ return r;
- unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
+ if (r < 0)
+ return r;
LIST_FOREACH(fd_store, fs, s->fd_store) {
+ _cleanup_free_ char *c = NULL;
int copy;
copy = fdset_put_dup(fds, fs->fd);
if (copy < 0)
return copy;
- unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy);
+ c = cescape(fs->fdname);
+
+ unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c));
}
if (s->main_exec_status.pid > 0) {
@@ -2076,8 +2130,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (dual_timestamp_is_set(&s->watchdog_timestamp))
dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
- if (s->forbid_restart)
- unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
+ unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
return 0;
}
@@ -2189,12 +2242,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->bus_endpoint_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
+ const char *fdv;
+ size_t pf;
int fd;
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ pf = strcspn(value, WHITESPACE);
+ fdv = strndupa(value, pf);
+
+ if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
else {
- r = service_add_fd_store(s, fd);
+ _cleanup_free_ char *t = NULL;
+ const char *fdn;
+
+ fdn = value + pf;
+ fdn += strspn(fdn, WHITESPACE);
+ (void) cunescape(fdn, 0, &t);
+
+ r = service_add_fd_store(s, fd, t);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else if (r > 0)
@@ -2236,6 +2301,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
else
s->forbid_restart = b;
+ } else if (streq(key, "stdin-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stdout-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stderr-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
+ else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = fdset_remove(fds, fd);
+ }
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2948,8 +3040,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (strv_find(tags, "WATCHDOG=1"))
service_reset_watchdog(s);
- if (strv_find(tags, "FDSTORE=1"))
- service_add_fd_store_set(s, fds);
+ if (strv_find(tags, "FDSTORE=1")) {
+ const char *name;
+
+ name = strv_find_startswith(tags, "FDNAME=");
+ if (name && !fdname_is_valid(name)) {
+ log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring.");
+ name = NULL;
+ }
+
+ service_add_fd_store_set(s, fds, name);
+ }
/* Notify clients about changed status or main pid */
if (notify_dbus)
@@ -3092,27 +3193,6 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
}
-static const char* const service_state_table[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = "dead",
- [SERVICE_START_PRE] = "start-pre",
- [SERVICE_START] = "start",
- [SERVICE_START_POST] = "start-post",
- [SERVICE_RUNNING] = "running",
- [SERVICE_EXITED] = "exited",
- [SERVICE_RELOAD] = "reload",
- [SERVICE_STOP] = "stop",
- [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
- [SERVICE_STOP_SIGTERM] = "stop-sigterm",
- [SERVICE_STOP_SIGKILL] = "stop-sigkill",
- [SERVICE_STOP_POST] = "stop-post",
- [SERVICE_FINAL_SIGTERM] = "final-sigterm",
- [SERVICE_FINAL_SIGKILL] = "final-sigkill",
- [SERVICE_FAILED] = "failed",
- [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
diff --git a/src/core/service.h b/src/core/service.h
index 789dff23a9..e765668247 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -29,27 +29,6 @@ typedef struct ServiceFDStore ServiceFDStore;
#include "kill.h"
#include "exit-status.h"
-typedef enum ServiceState {
- SERVICE_DEAD,
- SERVICE_START_PRE,
- SERVICE_START,
- SERVICE_START_POST,
- SERVICE_RUNNING,
- SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
- SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
- SERVICE_STOP_SIGABRT, /* Watchdog timeout */
- SERVICE_STOP_SIGTERM,
- SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
- SERVICE_FINAL_SIGKILL,
- SERVICE_FAILED,
- SERVICE_AUTO_RESTART,
- _SERVICE_STATE_MAX,
- _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
SERVICE_RESTART_ON_SUCCESS,
@@ -118,6 +97,7 @@ struct ServiceFDStore {
Service *service;
int fd;
+ char *fdname;
sd_event_source *event_source;
LIST_FIELDS(ServiceFDStore, fd_store);
@@ -215,15 +195,16 @@ struct Service {
char *usb_function_descriptors;
char *usb_function_strings;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
-const char* service_state_to_string(ServiceState i) _const_;
-ServiceState service_state_from_string(const char *s) _pure_;
-
const char* service_restart_to_string(ServiceRestart i) _const_;
ServiceRestart service_restart_from_string(const char *s) _pure_;
diff --git a/src/core/show-status.c b/src/core/show-status.c
index 02b1be73e3..e4e12a3365 100644
--- a/src/core/show-status.c
+++ b/src/core/show-status.c
@@ -19,7 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "parse-util.h"
#include "show-status.h"
+#include "string-util.h"
+#include "terminal-util.h"
#include "util.h"
int parse_show_status(const char *v, ShowStatus *ret) {
@@ -40,3 +46,81 @@ int parse_show_status(const char *v, ShowStatus *ret) {
*ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
return 0;
}
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
+ static const char status_indent[] = " "; /* "[" STATUS "] " */
+ _cleanup_free_ char *s = NULL;
+ _cleanup_close_ int fd = -1;
+ struct iovec iovec[6] = {};
+ int n = 0;
+ static bool prev_ephemeral;
+
+ assert(format);
+
+ /* This is independent of logging, as status messages are
+ * optional and go exclusively to the console. */
+
+ if (vasprintf(&s, format, ap) < 0)
+ return log_oom();
+
+ fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ if (ellipse) {
+ char *e;
+ size_t emax, sl;
+ int c;
+
+ c = fd_columns(fd);
+ if (c <= 0)
+ c = 80;
+
+ sl = status ? sizeof(status_indent)-1 : 0;
+
+ emax = c - sl - 1;
+ if (emax < 3)
+ emax = 3;
+
+ e = ellipsize(s, emax, 50);
+ if (e) {
+ free(s);
+ s = e;
+ }
+ }
+
+ if (prev_ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+ prev_ephemeral = ephemeral;
+
+ if (status) {
+ if (!isempty(status)) {
+ IOVEC_SET_STRING(iovec[n++], "[");
+ IOVEC_SET_STRING(iovec[n++], status);
+ IOVEC_SET_STRING(iovec[n++], "] ");
+ } else
+ IOVEC_SET_STRING(iovec[n++], status_indent);
+ }
+
+ IOVEC_SET_STRING(iovec[n++], s);
+ if (!ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\n");
+
+ if (writev(fd, iovec, n) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
+ va_list ap;
+ int r;
+
+ assert(format);
+
+ va_start(ap, format);
+ r = status_vprintf(status, ellipse, ephemeral, format, ap);
+ va_end(ap);
+
+ return r;
+}
diff --git a/src/core/show-status.h b/src/core/show-status.h
index a2b2153746..c79d4acb66 100644
--- a/src/core/show-status.h
+++ b/src/core/show-status.h
@@ -21,6 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
+
+#include "macro.h"
+
/* Manager status */
typedef enum ShowStatus {
@@ -32,3 +36,6 @@ typedef enum ShowStatus {
} ShowStatus;
int parse_show_status(const char *v, ShowStatus *ret);
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 5296efce1d..3a95b5fd72 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -19,31 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mman.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
#include <errno.h>
-#include <unistd.h>
+#include <getopt.h>
+#include <linux/reboot.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <getopt.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <unistd.h>
-#include "missing.h"
-#include "log.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "def.h"
#include "fileio.h"
+#include "killall.h"
+#include "log.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
+#include "switch-root.h"
+#include "terminal-util.h"
#include "umount.h"
#include "util.h"
#include "virt.h"
#include "watchdog.h"
-#include "killall.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "switch-root.h"
-#include "process-util.h"
-#include "terminal-util.h"
#define FINALIZE_ATTEMPTS 50
@@ -430,6 +433,5 @@ int main(int argc, char *argv[]) {
error:
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 b414462066..4602144150 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -21,13 +21,15 @@
#include <errno.h>
+#include "alloc-util.h"
+#include "dbus-slice.h"
#include "log.h"
-#include "strv.h"
#include "special.h"
+#include "string-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "unit.h"
#include "slice.h"
-#include "dbus-slice.h"
static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_DEAD] = UNIT_INACTIVE,
@@ -274,6 +276,9 @@ static int slice_enumerate(Manager *m) {
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SLICE(u)->deserialized_state = SLICE_ACTIVE;
if (!u->description)
@@ -287,13 +292,6 @@ static int slice_enumerate(Manager *m) {
return 0;
}
-static const char* const slice_state_table[_SLICE_STATE_MAX] = {
- [SLICE_DEAD] = "dead",
- [SLICE_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
-
const UnitVTable slice_vtable = {
.object_size = sizeof(Slice),
.cgroup_context_offset = offsetof(Slice, cgroup_context),
diff --git a/src/core/slice.h b/src/core/slice.h
index ac648e56f8..0c356651e3 100644
--- a/src/core/slice.h
+++ b/src/core/slice.h
@@ -23,14 +23,6 @@
typedef struct Slice Slice;
-
-typedef enum SliceState {
- SLICE_DEAD,
- SLICE_ACTIVE,
- _SLICE_STATE_MAX,
- _SLICE_STATE_INVALID = -1
-} SliceState;
-
struct Slice {
Unit meta;
@@ -40,6 +32,3 @@ struct Slice {
};
extern const UnitVTable slice_vtable;
-
-const char* slice_state_to_string(SliceState i) _const_;
-SliceState slice_state_from_string(const char *s) _pure_;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index cbe7d0b4a9..0661ff9ecd 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -21,18 +21,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include <fcntl.h>
-#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
#include "macro.h"
#include "smack-setup.h"
+#include "string-util.h"
#include "util.h"
-#include "fileio.h"
-#include "log.h"
#ifdef HAVE_SMACK
@@ -215,16 +219,14 @@ int mac_smack_setup(bool *loaded_policy) {
log_info("Successfully loaded Smack policies.");
break;
default:
- log_warning("Failed to load Smack access rules: %s, ignoring.",
- strerror(abs(r)));
+ log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
return 0;
}
#ifdef SMACK_RUN_LABEL
r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
if (r)
- log_warning("Failed to set SMACK label \"%s\" on self: %s",
- SMACK_RUN_LABEL, strerror(-r));
+ log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL);
#endif
r = write_cipso2_rules("/etc/smack/cipso.d/");
@@ -239,8 +241,7 @@ int mac_smack_setup(bool *loaded_policy) {
log_info("Successfully loaded Smack/CIPSO policies.");
break;
default:
- log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
- strerror(abs(r)));
+ log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
return 0;
}
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
index 336ff20f84..ba3135f401 100644
--- a/src/core/snapshot.c
+++ b/src/core/snapshot.c
@@ -21,11 +21,15 @@
#include <errno.h>
-#include "unit.h"
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "dbus-snapshot.h"
+#include "parse-util.h"
+#include "parse-util.h"
#include "snapshot.h"
+#include "string-util.h"
#include "unit-name.h"
-#include "dbus-snapshot.h"
-#include "bus-common-errors.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
[SNAPSHOT_DEAD] = UNIT_INACTIVE,
@@ -272,13 +276,6 @@ void snapshot_remove(Snapshot *s) {
unit_add_to_cleanup_queue(UNIT(s));
}
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = "dead",
- [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
const UnitVTable snapshot_vtable = {
.object_size = sizeof(Snapshot),
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
index f2451b1193..bd52dea408 100644
--- a/src/core/snapshot.h
+++ b/src/core/snapshot.h
@@ -23,13 +23,7 @@
typedef struct Snapshot Snapshot;
-
-typedef enum SnapshotState {
- SNAPSHOT_DEAD,
- SNAPSHOT_ACTIVE,
- _SNAPSHOT_STATE_MAX,
- _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
+#include "unit.h"
struct Snapshot {
Unit meta;
@@ -43,6 +37,3 @@ extern const UnitVTable snapshot_vtable;
int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s);
void snapshot_remove(Snapshot *s);
-
-const char* snapshot_state_to_string(SnapshotState i) _const_;
-SnapshotState snapshot_state_from_string(const char *s) _pure_;
diff --git a/src/core/socket.c b/src/core/socket.c
index 54e94c4f74..3c7f972fbc 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -19,38 +19,46 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <unistd.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
#include <mqueue.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "sd-event.h"
+
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "copy.h"
+#include "dbus-socket.h"
+#include "def.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "label.h"
#include "log.h"
-#include "strv.h"
+#include "missing.h"
#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "missing.h"
-#include "special.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.h"
-#include "smack-util.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "process-util.h"
#include "selinux-util.h"
-#include "dbus-socket.h"
-#include "unit.h"
-#include "formats-util.h"
#include "signal-util.h"
+#include "smack-util.h"
#include "socket.h"
-#include "copy.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "user-util.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -106,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) {
}
static void socket_cleanup_fd_list(SocketPort *p) {
- int k = p->n_auxiliary_fds;
-
- while (k--)
- safe_close(p->auxiliary_fds[k]);
+ assert(p);
+ close_many(p->auxiliary_fds, p->n_auxiliary_fds);
p->auxiliary_fds = mfree(p->auxiliary_fds);
p->n_auxiliary_fds = 0;
}
@@ -506,6 +512,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sPassSecurity: %s\n"
"%sTCPCongestion: %s\n"
"%sRemoveOnStop: %s\n"
+ "%sWritable: %s\n"
+ "%sFDName: %s\n"
"%sSELinuxContextFromNet: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_result_to_string(s->result),
@@ -522,6 +530,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(s->pass_sec),
prefix, strna(s->tcp_congestion),
prefix, yes_no(s->remove_on_stop),
+ prefix, yes_no(s->writable),
+ prefix, socket_fdname(s),
prefix, yes_no(s->selinux_context_from_net));
if (s->control_pid > 0)
@@ -642,7 +652,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
int r;
char *k = NULL;
- if ((r = socket_address_print(&p->address, &k)) < 0)
+ r = socket_address_print(&p->address, &k);
+ if (r < 0)
t = strerror(-r);
else
t = k;
@@ -955,50 +966,48 @@ 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_unit_warning_errno(UNIT(s), errno, "F_SETPIPE_SZ: %m");
+ log_unit_warning_errno(UNIT(s), errno, "Setting pipe size failed, ignoring: %m");
if (s->smack) {
r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, s->smack);
if (r < 0)
- log_unit_error_errno(UNIT(s), r, "mac_smack_apply_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "SMACK relabelling failed, ignoring: %m");
}
}
static int fifo_address_create(
const char *path,
mode_t directory_mode,
- mode_t socket_mode,
- int *_fd) {
+ mode_t socket_mode) {
- int fd = -1, r = 0;
- struct stat st;
+ _cleanup_close_ int fd = -1;
mode_t old_mask;
+ struct stat st;
+ int r;
assert(path);
- assert(_fd);
mkdir_parents_label(path, directory_mode);
r = mac_selinux_create_file_prepare(path, S_IFIFO);
if (r < 0)
- goto fail;
+ return r;
/* Enforce the right access mode for the fifo */
old_mask = umask(~ socket_mode);
/* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
+ (void) umask(~socket_mode | old_mask);
r = mkfifo(path, socket_mode);
- umask(old_mask);
+ (void) umask(old_mask);
if (r < 0 && errno != EEXIST) {
r = -errno;
goto fail;
}
- fd = open(path,
- O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
+ fd = open(path, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
if (fd < 0) {
r = -errno;
goto fail;
@@ -1015,66 +1024,50 @@ static int fifo_address_create(
(st.st_mode & 0777) != (socket_mode & ~old_mask) ||
st.st_uid != getuid() ||
st.st_gid != getgid()) {
-
r = -EEXIST;
goto fail;
}
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
+
+ return r;
fail:
mac_selinux_create_file_clear();
- safe_close(fd);
-
return r;
}
-static int special_address_create(
- const char *path,
- int *_fd) {
-
- int fd = -1, r = 0;
+static int special_address_create(const char *path, bool writable) {
+ _cleanup_close_ int fd = -1;
struct stat st;
+ int r;
assert(path);
- assert(_fd);
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ fd = open(path, (writable ? O_RDWR : O_RDONLY)|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
/* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
+ if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode))
+ return -EEXIST;
-fail:
- safe_close(fd);
+ r = fd;
+ fd = -1;
return r;
}
-static int ffs_address_create(
- const char *path,
- int *_fd) {
-
+static int usbffs_address_create(const char *path) {
_cleanup_close_ int fd = -1;
struct stat st;
+ int r;
assert(path);
- assert(_fd);
fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
if (fd < 0)
@@ -1087,32 +1080,32 @@ static int ffs_address_create(
if (!S_ISREG(st.st_mode))
return -EEXIST;
- *_fd = fd;
+ r = fd;
fd = -1;
- return 0;
+ return r;
}
static int mq_address_create(
const char *path,
mode_t mq_mode,
long maxmsg,
- long msgsize,
- int *_fd) {
+ long msgsize) {
- int fd = -1, r = 0;
+ _cleanup_close_ int fd = -1;
struct stat st;
mode_t old_mask;
struct mq_attr _attr, *attr = NULL;
+ int r;
assert(path);
- assert(_fd);
if (maxmsg > 0 && msgsize > 0) {
- zero(_attr);
- _attr.mq_flags = O_NONBLOCK;
- _attr.mq_maxmsg = maxmsg;
- _attr.mq_msgsize = msgsize;
+ _attr = (struct mq_attr) {
+ .mq_flags = O_NONBLOCK,
+ .mq_maxmsg = maxmsg,
+ .mq_msgsize = msgsize,
+ };
attr = &_attr;
}
@@ -1120,33 +1113,24 @@ static int mq_address_create(
old_mask = umask(~ mq_mode);
/* Include the original umask in our mask */
- umask(~mq_mode | old_mask);
+ (void) umask(~mq_mode | old_mask);
fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- umask(old_mask);
+ (void) umask(old_mask);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
+ st.st_gid != getgid())
+ return -EEXIST;
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
-fail:
- safe_close(fd);
return r;
}
@@ -1166,8 +1150,7 @@ static int socket_symlink(Socket *s) {
return 0;
}
-static int ffs_write_descs(int fd, Unit *u) {
- Service *s = SERVICE(u);
+static int usbffs_write_descs(int fd, Service *s) {
int r;
if (!s->usb_function_descriptors || !s->usb_function_strings)
@@ -1175,27 +1158,25 @@ static int ffs_write_descs(int fd, Unit *u) {
r = copy_file_fd(s->usb_function_descriptors, fd, false);
if (r < 0)
- return 0;
-
- r = copy_file_fd(s->usb_function_strings, fd, false);
+ return r;
- return r;
+ return copy_file_fd(s->usb_function_strings, fd, false);
}
-static int select_ep(const struct dirent *d) {
+static int usbffs_select_ep(const struct dirent *d) {
return d->d_name[0] != '.' && !streq(d->d_name, "ep0");
}
-static int ffs_dispatch_eps(SocketPort *p) {
+static int usbffs_dispatch_eps(SocketPort *p) {
_cleanup_free_ struct dirent **ent = NULL;
- int r, i, n, k;
_cleanup_free_ char *path = NULL;
+ int r, i, n, k;
- r = path_get_parent(p->path, &path);
- if (r < 0)
- return r;
+ path = dirname_malloc(p->path);
+ if (!path)
+ return -ENOMEM;
- r = scandir(path, &ent, select_ep, alphasort);
+ r = scandir(path, &ent, usbffs_select_ep, alphasort);
if (r < 0)
return -errno;
@@ -1216,10 +1197,12 @@ static int ffs_dispatch_eps(SocketPort *p) {
path_kill_slashes(ep);
- r = ffs_address_create(ep, &p->auxiliary_fds[k]);
+ r = usbffs_address_create(ep);
if (r < 0)
goto fail;
+ p->auxiliary_fds[k] = r;
+
++k;
free(ent[i]);
}
@@ -1227,9 +1210,7 @@ static int ffs_dispatch_eps(SocketPort *p) {
return r;
fail:
- while (k)
- safe_close(p->auxiliary_fds[--k]);
-
+ close_many(p->auxiliary_fds, k);
p->auxiliary_fds = mfree(p->auxiliary_fds);
p->n_auxiliary_fds = 0;
@@ -1237,10 +1218,10 @@ fail:
}
static int socket_open_fds(Socket *s) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
+ bool know_label = false;
SocketPort *p;
int r;
- char *label = NULL;
- bool know_label = false;
assert(s);
@@ -1249,7 +1230,9 @@ static int socket_open_fds(Socket *s) {
if (p->fd >= 0)
continue;
- if (p->type == SOCKET_SOCKET) {
+ switch (p->type) {
+
+ case SOCKET_SOCKET:
if (!know_label) {
/* Figure out label, if we don't it know
@@ -1300,64 +1283,72 @@ static int socket_open_fds(Socket *s) {
p->fd = r;
socket_apply_socket_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_SPECIAL) {
+ case SOCKET_SPECIAL:
- r = special_address_create(
- p->path,
- &p->fd);
- if (r < 0)
+ p->fd = special_address_create(p->path, s->writable);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
+ break;
- } else if (p->type == SOCKET_FIFO) {
+ case SOCKET_FIFO:
- r = fifo_address_create(
+ p->fd = fifo_address_create(
p->path,
s->directory_mode,
- s->socket_mode,
- &p->fd);
- if (r < 0)
+ s->socket_mode);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
socket_apply_fifo_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_MQUEUE) {
+ case SOCKET_MQUEUE:
- r = mq_address_create(
+ p->fd = mq_address_create(
p->path,
s->socket_mode,
s->mq_maxmsg,
- s->mq_msgsize,
- &p->fd);
- if (r < 0)
+ s->mq_msgsize);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
- } else if (p->type == SOCKET_USB_FUNCTION) {
+ }
+ break;
- r = ffs_address_create(
- p->path,
- &p->fd);
- if (r < 0)
+ case SOCKET_USB_FUNCTION:
+
+ p->fd = usbffs_address_create(p->path);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
- r = ffs_write_descs(p->fd, s->service.unit);
+ r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service)));
if (r < 0)
goto rollback;
- r = ffs_dispatch_eps(p);
+ r = usbffs_dispatch_eps(p);
if (r < 0)
goto rollback;
- } else
+
+ break;
+
+ default:
assert_not_reached("Unknown port type");
+ }
}
- mac_selinux_free(label);
return 0;
rollback:
socket_close_fds(s);
- mac_selinux_free(label);
-
return r;
}
@@ -1464,7 +1455,9 @@ static int socket_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- if (IN_SET(s->deserialized_state,
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(s->deserialized_state,
SOCKET_START_PRE,
SOCKET_START_CHOWN,
SOCKET_START_POST,
@@ -1475,9 +1468,6 @@ static int socket_coldplug(Unit *u) {
SOCKET_FINAL_SIGTERM,
SOCKET_FINAL_SIGKILL)) {
- if (s->control_pid <= 0)
- return -EBADMSG;
-
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
return r;
@@ -1519,6 +1509,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -2644,49 +2637,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
return 0;
}
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
- int i;
+int socket_collect_fds(Socket *s, int **fds) {
+ int *rfds, k = 0, n = 0;
SocketPort *p;
assert(s);
assert(fds);
- assert(n_fds);
/* Called from the service code for requesting our fds */
- rn_fds = 0;
LIST_FOREACH(port, p, s->ports) {
if (p->fd >= 0)
- rn_fds++;
- rn_fds += p->n_auxiliary_fds;
+ n++;
+ n += p->n_auxiliary_fds;
}
- if (rn_fds <= 0) {
+ if (n <= 0) {
*fds = NULL;
- *n_fds = 0;
return 0;
}
- rfds = new(int, rn_fds);
+ rfds = new(int, n);
if (!rfds)
return -ENOMEM;
- k = 0;
LIST_FOREACH(port, p, s->ports) {
+ int i;
+
if (p->fd >= 0)
rfds[k++] = p->fd;
for (i = 0; i < p->n_auxiliary_fds; ++i)
rfds[k++] = p->auxiliary_fds[i];
}
- assert(k == rn_fds);
+ assert(k == n);
*fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
+ return n;
}
static void socket_reset_failed(Unit *u) {
@@ -2782,23 +2769,18 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = "dead",
- [SOCKET_START_PRE] = "start-pre",
- [SOCKET_START_CHOWN] = "start-chown",
- [SOCKET_START_POST] = "start-post",
- [SOCKET_LISTENING] = "listening",
- [SOCKET_RUNNING] = "running",
- [SOCKET_STOP_PRE] = "stop-pre",
- [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
- [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
- [SOCKET_STOP_POST] = "stop-post",
- [SOCKET_FINAL_SIGTERM] = "final-sigterm",
- [SOCKET_FINAL_SIGKILL] = "final-sigkill",
- [SOCKET_FAILED] = "failed"
-};
+char *socket_fdname(Socket *s) {
+ assert(s);
+
+ /* Returns the name to use for $LISTEN_NAMES. If the user
+ * didn't specify anything specifically, use the socket unit's
+ * name as fallback. */
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+ if (s->fdname)
+ return s->fdname;
+
+ return UNIT(s)->id;
+}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
diff --git a/src/core/socket.h b/src/core/socket.h
index 286397b41c..94cda8a90d 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -27,24 +27,6 @@ typedef struct Socket Socket;
#include "mount.h"
#include "service.h"
-typedef enum SocketState {
- SOCKET_DEAD,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL,
- SOCKET_FAILED,
- _SOCKET_STATE_MAX,
- _SOCKET_STATE_INVALID = -1
-} SocketState;
-
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
SOCKET_EXEC_START_CHOWN,
@@ -136,6 +118,7 @@ struct Socket {
bool accept;
bool remove_on_stop;
+ bool writable;
/* Socket options */
bool keep_alive;
@@ -171,20 +154,23 @@ struct Socket {
char *user, *group;
bool reset_cpu_usage:1;
+
+ char *fdname;
};
/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
+int socket_collect_fds(Socket *s, int **fds);
/* Called from the service code when a per-connection service ended */
void socket_connection_unref(Socket *s);
void socket_free_ports(Socket *s);
-extern const UnitVTable socket_vtable;
+int socket_instantiate_service(Socket *s);
-const char* socket_state_to_string(SocketState i) _const_;
-SocketState socket_state_from_string(const char *s) _pure_;
+char *socket_fdname(Socket *s);
+
+extern const UnitVTable socket_vtable;
const char* socket_exec_command_to_string(SocketExecCommand i) _const_;
SocketExecCommand socket_exec_command_from_string(const char *s) _pure_;
@@ -193,5 +179,3 @@ const char* socket_result_to_string(SocketResult i) _const_;
SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
-
-int socket_instantiate_service(Socket *s);
diff --git a/src/core/swap.c b/src/core/swap.c
index bef457069f..baaa27b6a3 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -20,22 +20,30 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <sys/epoll.h>
#include <sys/stat.h>
-#include <libudev.h>
+#include <unistd.h>
-#include "unit.h"
-#include "swap.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
#include "dbus-swap.h"
-#include "special.h"
+#include "escape.h"
#include "exit-status.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "fstab-util.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "virt.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "swap.h"
#include "udev-util.h"
-#include "fstab-util.h"
-#include "formats-util.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "virt.h"
static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
[SWAP_DEAD] = UNIT_INACTIVE,
@@ -520,16 +528,16 @@ static int swap_coldplug(Unit *u) {
if (new_state == s->state)
return 0;
- if (new_state == SWAP_ACTIVATING ||
- new_state == SWAP_ACTIVATING_SIGTERM ||
- new_state == SWAP_ACTIVATING_SIGKILL ||
- new_state == SWAP_ACTIVATING_DONE ||
- new_state == SWAP_DEACTIVATING ||
- new_state == SWAP_DEACTIVATING_SIGTERM ||
- new_state == SWAP_DEACTIVATING_SIGKILL) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(new_state,
+ SWAP_ACTIVATING,
+ SWAP_ACTIVATING_SIGTERM,
+ SWAP_ACTIVATING_SIGKILL,
+ SWAP_ACTIVATING_DONE,
+ SWAP_DEACTIVATING,
+ SWAP_DEACTIVATING_SIGTERM,
+ SWAP_DEACTIVATING_SIGKILL)) {
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
@@ -597,6 +605,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -1195,7 +1206,7 @@ static Unit *swap_following(Unit *u) {
if (other->from_fragment)
return UNIT(other);
- /* Otherwise make everybody follow the unit that's named after
+ /* Otherwise, make everybody follow the unit that's named after
* the swap device in the kernel */
if (streq_ptr(s->what, s->devnode))
@@ -1398,21 +1409,6 @@ static bool swap_supported(void) {
return supported;
}
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = "dead",
- [SWAP_ACTIVATING] = "activating",
- [SWAP_ACTIVATING_DONE] = "activating-done",
- [SWAP_ACTIVE] = "active",
- [SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
- [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
- [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
- [SWAP_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
diff --git a/src/core/swap.h b/src/core/swap.h
index 9136b9abab..303b926568 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -22,26 +22,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <libudev.h>
+#include "libudev.h"
typedef struct Swap Swap;
-
-typedef enum SwapState {
- SWAP_DEAD,
- SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
- SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
- SWAP_ACTIVE,
- SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_FAILED,
- _SWAP_STATE_MAX,
- _SWAP_STATE_INVALID = -1
-} SwapState;
-
typedef enum SwapExecCommand {
SWAP_EXEC_ACTIVATE,
SWAP_EXEC_DEACTIVATE,
@@ -120,9 +104,6 @@ extern const UnitVTable swap_vtable;
int swap_process_device_new(Manager *m, struct udev_device *dev);
int swap_process_device_remove(Manager *m, struct udev_device *dev);
-const char* swap_state_to_string(SwapState i) _const_;
-SwapState swap_state_from_string(const char *s) _pure_;
-
const char* swap_exec_command_to_string(SwapExecCommand i) _const_;
SwapExecCommand swap_exec_command_from_string(const char *s) _pure_;
diff --git a/src/core/system.conf b/src/core/system.conf
index 231609033b..50668e12c4 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -17,9 +17,10 @@
#LogColor=yes
#LogLocation=no
#DumpCore=yes
-#CrashShell=no
#ShowStatus=yes
-#CrashChVT=1
+#CrashChangeVT=no
+#CrashShell=no
+#CrashReboot=no
#CPUAffinity=1 2
#JoinControllers=cpu,cpuacct net_cls,net_prio
#RuntimeWatchdogSec=0
@@ -39,6 +40,7 @@
#DefaultCPUAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
+#DefaultTasksAccounting=no
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=
diff --git a/src/core/target.c b/src/core/target.c
index f714cb31c2..c3e79fffc8 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-#include "unit.h"
-#include "target.h"
-#include "log.h"
#include "dbus-target.h"
+#include "log.h"
#include "special.h"
+#include "string-util.h"
#include "unit-name.h"
+#include "unit.h"
+#include "target.h"
static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
[TARGET_DEAD] = UNIT_INACTIVE,
@@ -192,13 +192,6 @@ _pure_ static const char *target_sub_state_to_string(Unit *u) {
return target_state_to_string(TARGET(u)->state);
}
-static const char* const target_state_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = "dead",
- [TARGET_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
-
const UnitVTable target_vtable = {
.object_size = sizeof(Target),
diff --git a/src/core/target.h b/src/core/target.h
index 0a25ef469a..3cc6c07bfa 100644
--- a/src/core/target.h
+++ b/src/core/target.h
@@ -23,14 +23,6 @@
typedef struct Target Target;
-
-typedef enum TargetState {
- TARGET_DEAD,
- TARGET_ACTIVE,
- _TARGET_STATE_MAX,
- _TARGET_STATE_INVALID = -1
-} TargetState;
-
struct Target {
Unit meta;
@@ -38,6 +30,3 @@ struct Target {
};
extern const UnitVTable target_vtable;
-
-const char* target_state_to_string(TargetState i) _const_;
-TargetState target_state_from_string(const char *s) _pure_;
diff --git a/src/core/timer.c b/src/core/timer.c
index eb6567bbfa..c9dc97d4fb 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -21,13 +21,20 @@
#include <errno.h>
-#include "unit.h"
-#include "unit-name.h"
-#include "timer.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "dbus-timer.h"
+#include "fs-util.h"
+#include "parse-util.h"
#include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "timer.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "user-util.h"
+#include "virt.h"
static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
[TIMER_DEAD] = UNIT_INACTIVE,
@@ -353,10 +360,14 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_BOOT:
- /* CLOCK_MONOTONIC equals the uptime on Linux */
- base = 0;
- break;
-
+ if (detect_container() <= 0) {
+ /* CLOCK_MONOTONIC equals the uptime on Linux */
+ base = 0;
+ break;
+ }
+ /* In a container we don't want to include the time the host
+ * was already up when the container started, so count from
+ * our own startup. Fall through. */
case TIMER_STARTUP:
base = UNIT(t)->manager->userspace_timestamp.monotonic;
break;
@@ -713,16 +724,6 @@ static void timer_time_change(Unit *u) {
timer_enter_waiting(t, false);
}
-static const char* const timer_state_table[_TIMER_STATE_MAX] = {
- [TIMER_DEAD] = "dead",
- [TIMER_WAITING] = "waiting",
- [TIMER_RUNNING] = "running",
- [TIMER_ELAPSED] = "elapsed",
- [TIMER_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
-
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec",
diff --git a/src/core/timer.h b/src/core/timer.h
index 9d919e4d3e..ac5af6a93c 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -25,16 +25,6 @@ typedef struct Timer Timer;
#include "calendarspec.h"
-typedef enum TimerState {
- TIMER_DEAD,
- TIMER_WAITING,
- TIMER_RUNNING,
- TIMER_ELAPSED,
- TIMER_FAILED,
- _TIMER_STATE_MAX,
- _TIMER_STATE_INVALID = -1
-} TimerState;
-
typedef enum TimerBase {
TIMER_ACTIVE,
TIMER_BOOT,
@@ -91,9 +81,6 @@ void timer_free_values(Timer *t);
extern const UnitVTable timer_vtable;
-const char *timer_state_to_string(TimerState i) _const_;
-TimerState timer_state_from_string(const char *s) _pure_;
-
const char *timer_base_to_string(TimerBase i) _const_;
TimerBase timer_base_from_string(const char *s) _pure_;
diff --git a/src/core/transaction.c b/src/core/transaction.c
index d1c1b9a3cd..69f28c902f 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -22,10 +22,11 @@
#include <unistd.h>
#include <fcntl.h>
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
-#include "transaction.h"
#include "terminal-util.h"
+#include "transaction.h"
static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
diff --git a/src/core/umount.c b/src/core/umount.c
index 22dbe67259..9d1f7660db 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -21,23 +21,30 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/dm-ioctl.h>
+#include <linux/loop.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/swap.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
+#include "libudev.h"
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fstab-util.h"
#include "list.h"
#include "mount-setup.h"
-#include "umount.h"
#include "path-util.h"
+#include "string-util.h"
+#include "udev-util.h"
+#include "umount.h"
#include "util.h"
#include "virt.h"
-#include "libudev.h"
-#include "udev-util.h"
typedef struct MountPoint {
char *path;
+ char *options;
dev_t devnum;
LIST_FIELDS(struct MountPoint, mount_point);
} MountPoint;
@@ -71,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) {
return -errno;
for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *path = NULL, *options = NULL;
char *p = NULL;
MountPoint *m;
int k;
@@ -82,15 +89,15 @@ static int mount_points_list_get(MountPoint **head) {
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
- "%*s" /* (6) mount options */
+ "%*s" /* (6) mount flags */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%*s " /* (9) file system type */
"%*s" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
+ "%ms" /* (11) mount options */
"%*[^\n]", /* some rubbish at the end */
- &path);
- if (k != 1) {
+ &path, &options);
+ if (k != 2) {
if (k == EOF)
break;
@@ -125,6 +132,9 @@ static int mount_points_list_get(MountPoint **head) {
}
m->path = p;
+ m->options = options;
+ options = NULL;
+
LIST_PREPEND(mount_point, *head, m);
}
@@ -369,6 +379,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
benefits, but might confuse the host, as we remount
the superblock here, not the bind mound. */
if (detect_container() <= 0) {
+ _cleanup_free_ char *options = NULL;
+ /* MS_REMOUNT requires that the data parameter
+ * should be the same from the original mount
+ * except for the desired changes. Since we want
+ * to remount read-only, we should filter out
+ * rw (and ro too, because it confuses the kernel) */
+ (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
+
/* We always try to remount directories
* read-only first, before we go on and umount
* them.
@@ -385,7 +403,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
* alias read-only we hence should be
* relatively safe regarding keeping the fs we
* can otherwise not see dirty. */
- (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
+ log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
+ (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
}
/* Skip / and /usr since we cannot unmount that
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index 0889769d03..721c8ccce9 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -19,14 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "formats-util.h"
+#include "macro.h"
#include "specifier.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "macro.h"
-#include "cgroup-util.h"
-#include "formats-util.h"
+#include "unit.h"
+#include "user-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
@@ -63,10 +66,7 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda
assert(u);
- if (!u->instance)
- return -EINVAL;
-
- return unit_name_unescape(u->instance, ret);
+ return unit_name_unescape(strempty(u->instance), ret);
}
static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
@@ -128,6 +128,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
n = unit_default_cgroup_path(slice);
} else
n = strdup(u->manager->cgroup_root);
+ if (!n)
+ return -ENOMEM;
*ret = n;
return 0;
@@ -166,7 +168,7 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char
c = unit_get_exec_context(u);
if (!c)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (u->manager->running_as == MANAGER_SYSTEM) {
diff --git a/src/core/unit.c b/src/core/unit.c
index 3a6313e4a2..6c130d4cd1 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -20,36 +20,43 @@
***/
#include <errno.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "sd-id128.h"
#include "sd-messages.h"
-#include "set.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "log.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-util.h"
#include "cgroup-util.h"
-#include "missing.h"
-#include "mkdir.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "dropin.h"
+#include "escape.h"
+#include "execute.h"
#include "fileio-label.h"
#include "formats-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "virt.h"
-#include "bus-common-errors.h"
-#include "bus-util.h"
-#include "dropin.h"
-#include "unit-name.h"
+#include "set.h"
#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
#include "unit.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "execute.h"
+#include "user-util.h"
+#include "virt.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
@@ -412,12 +419,11 @@ static void unit_remove_transient(Unit *u) {
STRV_FOREACH(i, u->dropin_paths) {
_cleanup_free_ char *p = NULL;
- int r;
(void) unlink(*i);
- r = path_get_parent(*i, &p);
- if (r >= 0)
+ p = dirname_malloc(*i);
+ if (p)
(void) rmdir(p);
}
}
@@ -1129,12 +1135,12 @@ static int unit_add_slice_dependencies(Unit *u) {
return 0;
if (UNIT_ISSET(u->slice))
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+ return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true);
- if (streq(u->id, SPECIAL_ROOT_SLICE))
+ if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return 0;
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
+ return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true);
}
static int unit_add_mount_dependencies(Unit *u) {
@@ -1147,13 +1153,23 @@ static int unit_add_mount_dependencies(Unit *u) {
char prefix[strlen(*i) + 1];
PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+ _cleanup_free_ char *p = NULL;
Unit *m;
- r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
+ r = unit_name_from_path(prefix, ".mount", &p);
if (r < 0)
return r;
- if (r == 0)
+
+ m = manager_get_unit(u->manager, p);
+ if (!m) {
+ /* Make sure to load the mount unit if
+ * it exists. If so the dependencies
+ * on this unit will be added later
+ * during the loading of the mount
+ * unit. */
+ (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
continue;
+ }
if (m == u)
continue;
@@ -2310,47 +2326,9 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
return unit_add_two_dependencies(u, d, e, other, add_reference);
}
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_dependency(other, d, u, add_reference);
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_two_dependencies(other, d, e, u, add_reference);
-}
-
int set_unit_path(const char *p) {
/* This is mostly for debug purposes */
- if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
+ if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0)
return -errno;
return 0;
@@ -2498,26 +2476,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd
return 0;
}
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
- _cleanup_free_ char *match = NULL;
- Manager *m = u->manager;
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
+ const char *match;
- assert(m);
+ assert(u);
+ assert(bus);
+ assert(name);
if (u->match_bus_slot)
return -EBUSY;
- match = strjoin("type='signal',"
+ match = strjoina("type='signal',"
"sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus',"
"interface='org.freedesktop.DBus',"
"member='NameOwnerChanged',"
- "arg0='",
- name,
- "'",
+ "arg0='", name, "'",
NULL);
- if (!match)
- return -ENOMEM;
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
}
@@ -2534,9 +2509,9 @@ int unit_watch_bus_name(Unit *u, const char *name) {
if (u->manager->api_bus) {
/* If the bus is already available, install the match directly.
* Otherwise, just put the name in the list. bus_setup_api() will take care later. */
- r = unit_install_bus_match(u->manager->api_bus, u, name);
+ r = unit_install_bus_match(u, u->manager->api_bus, name);
if (r < 0)
- return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
}
r = hashmap_put(u->manager->watch_bus, name, u);
@@ -2624,6 +2599,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
return 0;
}
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(value, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
+ _cleanup_free_ char *c = NULL;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ c = cescape(value);
+ if (!c)
+ return -ENOMEM;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(c, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
+ int copy;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (fd < 0)
+ return 0;
+
+ copy = fdset_put_dup(fds, fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "%s=%i\n", key, copy);
+ return 1;
+}
+
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
va_list ap;
@@ -2642,15 +2673,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
fputc('\n', f);
}
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
- assert(value);
-
- fprintf(f, "%s=%s\n", key, value);
-}
-
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
ExecRuntime **rt = NULL;
size_t offset;
@@ -3311,19 +3333,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
return 0;
}
-static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
- _cleanup_free_ char *dir = NULL;
- int r;
-
- assert(u);
-
- r = unit_drop_in_dir(u, mode, u->transient, &dir);
- if (r < 0)
- return r;
-
- return drop_in_file(dir, u->id, 50, name, p, q);
-}
-
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
@@ -3422,28 +3431,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
return unit_write_drop_in_private(u, mode, name, p);
}
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
- _cleanup_free_ char *p = NULL, *q = NULL;
- int r;
-
- assert(u);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- r = unit_drop_in_file(u, mode, name, &p, &q);
- if (r < 0)
- return r;
-
- if (unlink(q) < 0)
- r = errno == ENOENT ? 0 : -errno;
- else
- r = 1;
-
- rmdir(p);
- return r;
-}
-
int unit_make_transient(Unit *u) {
assert(u);
@@ -3729,14 +3716,3 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
return -ELOOP;
}
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
- [UNIT_ACTIVE] = "active",
- [UNIT_RELOADING] = "reloading",
- [UNIT_INACTIVE] = "inactive",
- [UNIT_FAILED] = "failed",
- [UNIT_ACTIVATING] = "activating",
- [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
diff --git a/src/core/unit.h b/src/core/unit.h
index c868d75c79..6f775c5ce1 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -27,7 +27,6 @@
typedef struct Unit Unit;
typedef struct UnitVTable UnitVTable;
-typedef enum UnitActiveState UnitActiveState;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
@@ -37,17 +36,6 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
#include "unit-name.h"
#include "failure-action.h"
-enum UnitActiveState {
- UNIT_ACTIVE,
- UNIT_RELOADING,
- UNIT_INACTIVE,
- UNIT_FAILED,
- UNIT_ACTIVATING,
- UNIT_DEACTIVATING,
- _UNIT_ACTIVE_STATE_MAX,
- _UNIT_ACTIVE_STATE_INVALID = -1
-};
-
typedef enum KillOperation {
KILL_TERMINATE,
KILL_KILL,
@@ -476,9 +464,6 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
int unit_choose_id(Unit *u, const char *name);
@@ -532,7 +517,7 @@ void unit_unwatch_all_pids(Unit *u);
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name);
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name);
int unit_watch_bus_name(Unit *u, const char *name);
void unit_unwatch_bus_name(Unit *u, const char *name);
@@ -545,11 +530,15 @@ char *unit_dbus_path(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
bool unit_can_serialize(Unit *u) _pure_;
+
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
+
int unit_add_node_link(Unit *u, const char *what, bool wants);
int unit_coldplug(Unit *u);
@@ -600,8 +589,6 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n
int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name);
-
int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
int unit_make_transient(Unit *u);
@@ -617,9 +604,6 @@ static inline bool unit_supported(Unit *u) {
void unit_warn_if_dir_nonempty(Unit *u, const char* where);
int unit_fail_if_symlink(Unit *u, const char* where);
-const char *unit_active_state_to_string(UnitActiveState i) _const_;
-UnitActiveState unit_active_state_from_string(const char *s) _pure_;
-
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c
index ab91afec4d..ae53bac600 100644
--- a/src/cryptsetup/cryptsetup-generator.c
+++ b/src/cryptsetup/cryptsetup-generator.c
@@ -21,13 +21,19 @@
#include <errno.h>
+#include "alloc-util.h"
#include "dropin.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
#include "generator.h"
#include "hashmap.h"
#include "log.h"
#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "fstab-util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "util.h"
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 5d5872b7f4..98fe52a81b 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -19,21 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
-#include <sys/mman.h>
+#include <libcryptsetup.h>
#include <mntent.h>
+#include <string.h>
+#include <sys/mman.h>
-#include <libcryptsetup.h>
+#include "sd-device.h"
+#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "device-util.h"
+#include "escape.h"
#include "fileio.h"
#include "log.h"
-#include "util.h"
+#include "mount-util.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "ask-password-api.h"
-#include "sd-device.h"
-#include "device-util.h"
+#include "util.h"
static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
static char *arg_cipher = NULL;
@@ -312,19 +317,16 @@ static char *disk_mount_point(const char *label) {
return NULL;
}
-static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) {
- int r = 0;
- char **p;
- _cleanup_free_ char *text = NULL;
- _cleanup_free_ char *escaped_name = NULL;
- char *id;
+static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) {
+ _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
+ _cleanup_strv_free_erase_ char **passwords = NULL;
const char *name = NULL;
- _cleanup_free_ char *description = NULL, *name_buffer = NULL,
- *mount_point = NULL, *maj_min = NULL;
+ char **p, *id;
+ int r = 0;
assert(vol);
assert(src);
- assert(passwords);
+ assert(ret);
description = disk_description(src);
mount_point = disk_mount_point(vol);
@@ -364,42 +366,45 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
id = strjoina("cryptsetup:", escaped_name);
- r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
+ ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
+ &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
if (arg_verify) {
- _cleanup_strv_free_ char **passwords2 = NULL;
+ _cleanup_strv_free_erase_ char **passwords2 = NULL;
- assert(strv_length(*passwords) == 1);
+ assert(strv_length(passwords) == 1);
if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
return log_oom();
id = strjoina("cryptsetup-verification:", escaped_name);
- r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query verification password: %m");
assert(strv_length(passwords2) == 1);
- if (!streq(*passwords[0], passwords2[0])) {
+ if (!streq(passwords[0], passwords2[0])) {
log_warning("Passwords did not match, retrying.");
return -EAGAIN;
}
}
- strv_uniq(*passwords);
+ strv_uniq(passwords);
- STRV_FOREACH(p, *passwords) {
+ STRV_FOREACH(p, passwords) {
char *c;
if (strlen(*p)+1 >= arg_key_size)
continue;
/* Pad password if necessary */
- if (!(c = new(char, arg_key_size)))
+ c = new(char, arg_key_size);
+ if (!c)
return log_oom();
strncpy(c, *p, arg_key_size);
@@ -407,14 +412,19 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
*p = c;
}
+ *ret = passwords;
+ passwords = NULL;
+
return 0;
}
-static int attach_tcrypt(struct crypt_device *cd,
- const char *name,
- const char *key_file,
- char **passwords,
- uint32_t flags) {
+static int attach_tcrypt(
+ struct crypt_device *cd,
+ const char *name,
+ const char *key_file,
+ char **passwords,
+ uint32_t flags) {
+
int r = 0;
_cleanup_free_ char *passphrase = NULL;
struct crypt_params_tcrypt params = {
@@ -524,8 +534,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
* it just configures encryption
* parameters when used for plain
* mode. */
- r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
- NULL, NULL, arg_keyfile_size, &params);
+ r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
/* hash == NULL implies the user passed "plain" */
pass_volume_key = (params.hash == NULL);
@@ -541,9 +550,7 @@ static int attach_luks_or_plain(struct crypt_device *cd,
crypt_get_device_name(cd));
if (key_file) {
- r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
- key_file, arg_keyfile_size,
- arg_keyfile_offset, flags);
+ r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
if (r < 0) {
log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
return -EAGAIN;
@@ -635,7 +642,6 @@ int main(int argc, char *argv[]) {
k = crypt_init(&cd, arg_header);
} else
k = crypt_init(&cd, argv[3]);
-
if (k) {
log_error_errno(k, "crypt_init() failed: %m");
goto finish;
@@ -673,7 +679,7 @@ int main(int argc, char *argv[]) {
}
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
- _cleanup_strv_free_ char **passwords = NULL;
+ _cleanup_strv_free_erase_ char **passwords = NULL;
if (!key_file) {
k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c
index 7bbec5467e..6861a592fe 100644
--- a/src/dbus1-generator/dbus1-generator.c
+++ b/src/dbus1-generator/dbus1-generator.c
@@ -19,14 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "alloc-util.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
#include "conf-parser.h"
-#include "special.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "mkdir.h"
-#include "bus-util.h"
-#include "bus-internal.h"
+#include "special.h"
#include "unit-name.h"
-#include "cgroup-util.h"
+#include "util.h"
static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
@@ -223,8 +227,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
if (errno == -ENOENT)
return 0;
- log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
}
r = 0;
@@ -242,8 +245,7 @@ static int parse_dbus_fragments(const char *path, const char *type) {
return r;
fail:
- log_error_errno(errno, "Failed to read D-Bus services directory: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to read D-Bus services directory: %m");
}
static int link_busnames_target(const char *units) {
diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c
index 8b29e8fd09..413cfd0388 100644
--- a/src/debug-generator/debug-generator.c
+++ b/src/debug-generator/debug-generator.c
@@ -19,11 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "alloc-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "special.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
-#include "mkdir.h"
+#include "util.h"
+static char *arg_default_unit = NULL;
static const char *arg_dest = "/tmp";
static char **arg_mask = NULL;
static char **arg_wants = NULL;
@@ -76,6 +82,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
arg_debug_shell = r;
} else
arg_debug_shell = true;
+ } else if (streq(key, "systemd.unit")) {
+
+ if (!value)
+ log_error("Missing argument for systemd.unit= kernel command line parameter.");
+ else {
+ r = free_and_strdup(&arg_default_unit, value);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default unit %s: %m", value);
+ }
+ } else if (!value) {
+ const char *target;
+
+ target = runlevel_to_target(key);
+ if (target) {
+ r = free_and_strdup(&arg_default_unit, target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default unit %s: %m", target);
+ }
}
return 0;
@@ -114,7 +138,7 @@ static int generate_wants_symlinks(void) {
STRV_FOREACH(u, arg_wants) {
_cleanup_free_ char *p = NULL, *f = NULL;
- p = strjoin(arg_dest, "/default.target.wants/", *u, NULL);
+ p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u, NULL);
if (!p)
return log_oom();
@@ -150,6 +174,12 @@ int main(int argc, char *argv[]) {
umask(0022);
+ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
+ goto finish;
+ }
+
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
diff --git a/src/delta/delta.c b/src/delta/delta.c
index 990130d00b..8bf678c28f 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -21,21 +21,28 @@
***/
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
#include <getopt.h>
+#include <string.h>
#include <sys/prctl.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "hashmap.h"
-#include "util.h"
-#include "path-util.h"
+#include "locale-util.h"
#include "log.h"
#include "pager.h"
-#include "build.h"
-#include "strv.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
static const char prefixes[] =
"/etc\0"
@@ -312,8 +319,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to open %s: %m", path);
}
for (;;) {
@@ -544,9 +550,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 97ae569ca5..0a256c29be 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -19,20 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
#include <getopt.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include "util.h"
#include "virt.h"
-#include "build.h"
static bool arg_quiet = false;
static enum {
ANY_VIRTUALIZATION,
ONLY_VM,
- ONLY_CONTAINER
+ ONLY_CONTAINER,
+ ONLY_CHROOT,
} arg_mode = ANY_VIRTUALIZATION;
static void help(void) {
@@ -42,6 +42,7 @@ static void help(void) {
" --version Show package version\n"
" -c --container Only detect whether we are run in a container\n"
" -v --vm Only detect whether we are run in a VM\n"
+ " -r --chroot Detect whether we are run in a chroot() environment\n"
" -q --quiet Don't output anything, just set return value\n"
, program_invocation_short_name);
}
@@ -56,7 +57,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "container", no_argument, NULL, 'c' },
- { "vm", optional_argument, NULL, 'v' },
+ { "vm", no_argument, NULL, 'v' },
+ { "chroot", no_argument, NULL, 'r' },
{ "quiet", no_argument, NULL, 'q' },
{}
};
@@ -66,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hqcvr", options, NULL)) >= 0)
switch (c) {
@@ -75,9 +77,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'q':
arg_quiet = true;
@@ -91,6 +91,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = ONLY_VM;
break;
+ case 'r':
+ arg_mode = ONLY_CHROOT;
+ break;
+
case '?':
return -EINVAL;
@@ -99,8 +103,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (optind < argc) {
- log_error("%s takes no arguments.",
- program_invocation_short_name);
+ log_error("%s takes no arguments.", program_invocation_short_name);
return -EINVAL;
}
@@ -108,7 +111,7 @@ static int parse_argv(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
- int retval = EXIT_SUCCESS, r;
+ int r;
/* This is mostly intended to be used for scripts which want
* to detect whether we are being run in a virtualized
@@ -126,7 +129,7 @@ int main(int argc, char *argv[]) {
case ONLY_VM:
r = detect_vm();
if (r < 0) {
- log_error_errno(r, "Failed to check for vm: %m");
+ log_error_errno(r, "Failed to check for VM: %m");
return EXIT_FAILURE;
}
@@ -141,6 +144,15 @@ int main(int argc, char *argv[]) {
break;
+ case ONLY_CHROOT:
+ r = running_in_chroot();
+ if (r < 0) {
+ log_error_errno(r, "Failed to check for chroot() environment: %m");
+ return EXIT_FAILURE;
+ }
+
+ return r ? EXIT_SUCCESS : EXIT_FAILURE;
+
case ANY_VIRTUALIZATION:
default:
r = detect_virtualization();
@@ -155,7 +167,5 @@ int main(int argc, char *argv[]) {
if (!arg_quiet)
puts(virtualization_to_string(r));
- retval = r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE;
-
- return retval;
+ return r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/escape/escape.c b/src/escape/escape.c
index 341453398d..e857affbc4 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -19,14 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
+#include "alloc-util.h"
#include "log.h"
-#include "unit-name.h"
-#include "build.h"
+#include "string-util.h"
#include "strv.h"
+#include "unit-name.h"
static enum {
ACTION_ESCAPE,
@@ -83,9 +84,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_SUFFIX:
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index e2a1c00a75..642d36912c 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -19,24 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include <fcntl.h>
-#include <unistd.h>
#include <getopt.h>
#include <shadow.h>
+#include <unistd.h>
-#include "strv.h"
-#include "fileio.h"
+#include "alloc-util.h"
+#include "ask-password-api.h"
#include "copy.h"
-#include "build.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "locale-util.h"
#include "mkdir.h"
-#include "time-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "random-util.h"
-#include "locale-util.h"
-#include "ask-password-api.h"
+#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "time-util.h"
+#include "umask-util.h"
+#include "user-util.h"
static char *arg_root = NULL;
static char *arg_locale = NULL; /* $LANG */
@@ -53,15 +58,6 @@ static bool arg_copy_locale = false;
static bool arg_copy_timezone = false;
static bool arg_copy_root_password = false;
-static void clear_string(char *x) {
-
- if (!x)
- return;
-
- /* A delicious drop of snake-oil! */
- memset(x, 'x', strlen(x));
-}
-
static bool press_any_key(void) {
char k = 0;
bool need_nl = true;
@@ -466,9 +462,9 @@ static int prompt_root_password(void) {
msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: ");
for (;;) {
- _cleanup_free_ char *a = NULL, *b = NULL;
+ _cleanup_string_free_erase_ char *a = NULL, *b = NULL;
- r = ask_password_tty(msg1, 0, false, NULL, &a);
+ r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a);
if (r < 0)
return log_error_errno(r, "Failed to query root password: %m");
@@ -477,21 +473,15 @@ static int prompt_root_password(void) {
break;
}
- r = ask_password_tty(msg2, 0, false, NULL, &b);
- if (r < 0) {
- log_error_errno(r, "Failed to query root password: %m");
- clear_string(a);
- return r;
- }
+ r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b);
+ if (r < 0)
+ return log_error_errno(r, "Failed to query root password: %m");
if (!streq(a, b)) {
log_error("Entered passwords did not match, please try again.");
- clear_string(a);
- clear_string(b);
continue;
}
- clear_string(b);
arg_root_password = a;
a = NULL;
break;
@@ -550,7 +540,7 @@ static int process_root_password(void) {
mkdir_parents(etc_shadow, 0755);
- lock = take_password_lock(arg_root);
+ lock = take_etc_passwd_lock(arg_root);
if (lock < 0)
return lock;
@@ -564,8 +554,7 @@ static int process_root_password(void) {
if (!errno)
errno = EIO;
- log_error_errno(errno, "Failed to find shadow entry for root: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to find shadow entry for root: %m");
}
r = write_root_shadow(etc_shadow, p);
@@ -600,10 +589,9 @@ static int process_root_password(void) {
item.sp_pwdp = crypt(arg_root_password, salt);
if (!item.sp_pwdp) {
if (!errno)
- errno = -EINVAL;
+ errno = EINVAL;
- log_error_errno(errno, "Failed to encrypt password: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to encrypt password: %m");
}
item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);
@@ -704,21 +692,12 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
- free(arg_root);
- arg_root = path_make_absolute_cwd(optarg);
- if (!arg_root)
- return log_oom();
-
- path_kill_slashes(arg_root);
-
- if (path_equal(arg_root, "/"))
- arg_root = mfree(arg_root);
-
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case ARG_LOCALE:
@@ -886,7 +865,7 @@ finish:
free(arg_locale_messages);
free(arg_timezone);
free(arg_hostname);
- clear_string(arg_root_password);
+ string_erase(arg_root_password);
free(arg_root_password);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index bd3051f30d..5b806a1e69 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -32,16 +32,22 @@
#include "sd-bus.h"
#include "sd-device.h"
-#include "util.h"
-#include "process-util.h"
-#include "signal-util.h"
-#include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "device-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "signal-util.h"
#include "socket-util.h"
+#include "special.h"
+#include "stdio-util.h"
+#include "util.h"
/* exit codes as defined in fsck(8) */
enum {
@@ -60,14 +66,14 @@ static bool arg_force = false;
static bool arg_show_progress = false;
static const char *arg_repair = "-a";
-static void start_target(const char *target) {
+static void start_target(const char *target, const char *mode) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
assert(target);
- r = bus_open_system_systemd(&bus);
+ r = bus_connect_system_systemd(&bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
return;
@@ -83,7 +89,7 @@ static void start_target(const char *target) {
"StartUnitReplace",
&error,
NULL,
- "sss", "basic.target", target, "replace");
+ "sss", "basic.target", target, mode);
/* Don't print a warning if we aren't called during startup */
if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
@@ -366,12 +372,12 @@ int main(int argc, char *argv[]) {
r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type);
if (r >= 0) {
r = fsck_exists(type);
- if (r == -ENOENT) {
- log_info("fsck.%s doesn't exist, not checking file system on %s", type, device);
- r = 0;
+ if (r < 0)
+ log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device);
+ else if (r == 0) {
+ log_info("fsck.%s doesn't exist, not checking file system on %s.", type, device);
goto finish;
- } else if (r < 0)
- log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device);
+ }
}
if (arg_show_progress) {
@@ -463,10 +469,10 @@ int main(int argc, char *argv[]) {
if (status.si_code == CLD_EXITED && (status.si_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory)
/* System should be rebooted. */
- start_target(SPECIAL_REBOOT_TARGET);
+ start_target(SPECIAL_REBOOT_TARGET, "replace-irreversibly");
else if (status.si_code == CLD_EXITED && (status.si_status & (FSCK_SYSTEM_SHOULD_REBOOT | FSCK_ERRORS_LEFT_UNCORRECTED)))
/* Some other problem */
- start_target(SPECIAL_EMERGENCY_TARGET);
+ start_target(SPECIAL_EMERGENCY_TARGET, "replace");
else {
log_warning("Ignoring error.");
r = 0;
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 3f8ea5647c..f7c8d11ace 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -19,22 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <mntent.h>
#include <errno.h>
+#include <mntent.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include "log.h"
-#include "util.h"
-#include "unit-name.h"
-#include "path-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "fstab-util.h"
+#include "generator.h"
+#include "log.h"
+#include "mkdir.h"
#include "mount-setup.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
#include "special.h"
-#include "mkdir.h"
-#include "generator.h"
+#include "stat-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "unit-name.h"
+#include "util.h"
#include "virt.h"
static const char *arg_dest = "/tmp";
diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c
index 9a4b038ef3..03df7365b5 100644
--- a/src/getty-generator/getty-generator.c
+++ b/src/getty-generator/getty-generator.c
@@ -19,20 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "log.h"
-#include "util.h"
#include "mkdir.h"
-#include "unit-name.h"
-#include "virt.h"
-#include "fileio.h"
#include "path-util.h"
#include "process-util.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "virt.h"
static const char *arg_dest = "/tmp";
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index bb821797f1..34852ce381 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -24,22 +24,32 @@
#include <sys/statfs.h>
#include <blkid/blkid.h>
-#include "sd-id128.h"
#include "libudev.h"
-#include "path-util.h"
-#include "util.h"
-#include "mkdir.h"
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "blkid-util.h"
+#include "btrfs-util.h"
+#include "dirent-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
+#include "generator.h"
+#include "gpt.h"
#include "missing.h"
-#include "udev-util.h"
+#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "udev-util.h"
#include "unit-name.h"
+#include "util.h"
#include "virt.h"
-#include "generator.h"
-#include "gpt.h"
-#include "fileio.h"
-#include "efivars.h"
-#include "blkid-util.h"
-#include "btrfs-util.h"
static const char *arg_dest = "/tmp";
static bool arg_enabled = true;
@@ -292,8 +302,7 @@ static int probe_and_add_mount(
if (!b) {
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed to allocate prober: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to allocate prober: %m");
}
blkid_probe_enable_superblocks(b, 1);
@@ -465,6 +474,12 @@ static int add_boot(const char *what) {
return 0;
}
+ /* We create an .automount which is not overridden by the .mount from the fstab generator. */
+ if (fstab_is_mount_point("/boot")) {
+ log_debug("/boot specified in fstab, ignoring.");
+ return 0;
+ }
+
if (path_is_busy("/boot")) {
log_debug("/boot already populated, ignoring.");
return 0;
@@ -486,8 +501,7 @@ static int add_boot(const char *what) {
if (!b) {
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed to allocate prober: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to allocate prober: %m");
}
blkid_probe_enable_partitions(b, 1);
@@ -864,7 +878,6 @@ static int get_block_device_harder(const char *path, dev_t *dev) {
goto fallback;
found = de;
- break;
}
if (!found)
diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c
index 9fb6233336..da719f2a30 100644
--- a/src/hibernate-resume/hibernate-resume-generator.c
+++ b/src/hibernate-resume/hibernate-resume-generator.c
@@ -19,14 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
+#include "alloc-util.h"
+#include "fstab-util.h"
#include "log.h"
-#include "util.h"
-#include "special.h"
#include "mkdir.h"
+#include "proc-cmdline.h"
+#include "special.h"
+#include "string-util.h"
#include "unit-name.h"
+#include "util.h"
static const char *arg_dest = "/tmp";
static char *arg_resume_dev = NULL;
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index 1f3b169905..316a2803d3 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -23,9 +23,10 @@
#include <errno.h>
#include <sys/stat.h>
+#include "alloc-util.h"
+#include "fileio.h"
#include "log.h"
#include "util.h"
-#include "fileio.h"
int main(int argc, char *argv[]) {
struct stat st;
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index dcbad99ae9..bf09fb8fbb 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -19,21 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <getopt.h>
#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
#include "sd-bus.h"
#include "sd-id128.h"
-#include "hostname-util.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "architecture.h"
#include "bus-error.h"
-#include "util.h"
+#include "bus-util.h"
+#include "hostname-util.h"
#include "spawn-polkit-agent.h"
-#include "build.h"
-#include "architecture.h"
+#include "util.h"
static bool arg_ask_password = true;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
@@ -387,9 +388,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
@@ -519,7 +518,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index dd508aefb5..92061532b8 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -24,16 +24,20 @@
#include <unistd.h>
#include <sys/utsname.h>
-#include "util.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "bus-util.h"
#include "def.h"
-#include "virt.h"
#include "env-util.h"
-#include "fileio-label.h"
-#include "bus-util.h"
#include "event-util.h"
-#include "selinux-util.h"
+#include "fileio-label.h"
#include "hostname-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 446de3a2fc..de59b797a6 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -17,21 +17,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <ctype.h>
#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "util.h"
-#include "strbuf.h"
+#include "alloc-util.h"
#include "conf-files.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "verbs.h"
-#include "build.h"
-
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
+#include "mkdir.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "verbs.h"
/*
* Generic udev properties, key/value database based on modalias strings.
@@ -688,9 +691,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USR:
arg_hwdb_bin_dir = UDEVLIBEXECDIR;
diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c
index 18c42b8b6d..7b1ac134a0 100644
--- a/src/import/aufs-util.c
+++ b/src/import/aufs-util.c
@@ -21,8 +21,9 @@
#include <ftw.h>
-#include "util.h"
#include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
#include "aufs-util.h"
static int nftw_cb(
diff --git a/src/import/curl-util.c b/src/import/curl-util.c
index d390cfb1f3..4278466df1 100644
--- a/src/import/curl-util.c
+++ b/src/import/curl-util.c
@@ -19,7 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "curl-util.h"
+#include "fd-util.h"
+#include "string-util.h"
static void curl_glue_check_finished(CurlGlue *g) {
CURLMsg *msg;
diff --git a/src/import/curl-util.h b/src/import/curl-util.h
index c249069ffa..6a2aa81c76 100644
--- a/src/import/curl-util.h
+++ b/src/import/curl-util.h
@@ -24,9 +24,10 @@
#include <sys/types.h>
#include <curl/curl.h>
-#include "hashmap.h"
#include "sd-event.h"
+#include "hashmap.h"
+
typedef struct CurlGlue CurlGlue;
struct CurlGlue {
diff --git a/src/import/export-raw.c b/src/import/export-raw.c
index 8f9c9bbc80..103d45bf21 100644
--- a/src/import/export-raw.c
+++ b/src/import/export-raw.c
@@ -24,12 +24,17 @@
#undef basename
#include "sd-daemon.h"
-#include "util.h"
-#include "ratelimit.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
#include "copy.h"
-#include "import-common.h"
#include "export-raw.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "import-common.h"
+#include "ratelimit.h"
+#include "string-util.h"
+#include "util.h"
#define COPY_BUFFER_SIZE (16*1024)
diff --git a/src/import/export-tar.c b/src/import/export-tar.c
index 43fa9d1b03..2bbec661e6 100644
--- a/src/import/export-tar.c
+++ b/src/import/export-tar.c
@@ -19,15 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/sendfile.h>
-
#include "sd-daemon.h"
-#include "util.h"
-#include "ratelimit.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "import-common.h"
#include "export-tar.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "import-common.h"
#include "process-util.h"
+#include "ratelimit.h"
+#include "string-util.h"
+#include "util.h"
#define COPY_BUFFER_SIZE (16*1024)
@@ -78,7 +81,7 @@ TarExport *tar_export_unref(TarExport *e) {
}
if (e->temp_path) {
- (void) btrfs_subvol_remove(e->temp_path, false);
+ (void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA);
free(e->temp_path);
}
@@ -283,7 +286,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
BtrfsQuotaInfo q;
- r = btrfs_subvol_get_quota_fd(sfd, &q);
+ r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q);
if (r >= 0)
e->quota_referenced = q.referenced;
diff --git a/src/import/export.c b/src/import/export.c
index b88d71fec6..2b33d778d3 100644
--- a/src/import/export.c
+++ b/src/import/export.c
@@ -22,15 +22,19 @@
#include <getopt.h>
#include "sd-event.h"
+
+#include "alloc-util.h"
#include "event-util.h"
-#include "signal-util.h"
+#include "export-raw.h"
+#include "export-tar.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "hostname-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "machine-image.h"
#include "import-util.h"
-#include "export-tar.h"
-#include "export-raw.h"
+#include "machine-image.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "verbs.h"
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
@@ -260,9 +264,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORMAT:
if (streq(optarg, "uncompressed"))
diff --git a/src/import/import-common.c b/src/import/import-common.c
index d8a3bbc249..a8551ca9e8 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -19,15 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sched.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <unistd.h>
-#include "util.h"
#include "btrfs-util.h"
-#include "capability.h"
-#include "signal-util.h"
+#include "capability-util.h"
+#include "fd-util.h"
#include "import-common.h"
+#include "signal-util.h"
+#include "util.h"
int import_make_read_only_fd(int fd) {
int r;
diff --git a/src/import/import-compress.c b/src/import/import-compress.c
index d6b8133036..d4ff178f60 100644
--- a/src/import/import-compress.c
+++ b/src/import/import-compress.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "import-compress.h"
+#include "string-table.h"
+#include "util.h"
void import_compress_free(ImportCompress *c) {
assert(c);
diff --git a/src/import/import-raw.c b/src/import/import-raw.c
index 5f7d25d063..7593f064fc 100644
--- a/src/import/import-raw.c
+++ b/src/import/import-raw.c
@@ -23,19 +23,27 @@
#include "sd-daemon.h"
#include "sd-event.h"
-#include "util.h"
-#include "path-util.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "hostname-util.h"
+#include "chattr-util.h"
#include "copy.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "ratelimit.h"
-#include "machine-pool.h"
-#include "qcow2-util.h"
-#include "import-compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
#include "import-common.h"
+#include "import-compress.h"
#include "import-raw.h"
+#include "io-util.h"
+#include "machine-pool.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "qcow2-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
struct RawImport {
sd_event *event;
@@ -191,7 +199,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
+ log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
log_info("Unpacking QCOW2 file.");
@@ -279,7 +287,7 @@ static int raw_import_open_disk(RawImport *i) {
r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
+ log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
return 0;
}
diff --git a/src/import/import-tar.c b/src/import/import-tar.c
index d2bfb30238..c7983c04be 100644
--- a/src/import/import-tar.c
+++ b/src/import/import-tar.c
@@ -23,20 +23,27 @@
#include "sd-daemon.h"
#include "sd-event.h"
-#include "util.h"
-#include "path-util.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "hostname-util.h"
#include "copy.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "ratelimit.h"
-#include "machine-pool.h"
-#include "qcow2-util.h"
-#include "import-compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
#include "import-common.h"
+#include "import-compress.h"
#include "import-tar.h"
+#include "io-util.h"
+#include "machine-pool.h"
+#include "mkdir.h"
+#include "path-util.h"
#include "process-util.h"
+#include "qcow2-util.h"
+#include "ratelimit.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "util.h"
struct TarImport {
sd_event *event;
@@ -234,7 +241,9 @@ static int tar_import_fork_tar(TarImport *i) {
if (mkdir(i->temp_path, 0755) < 0)
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
} else if (r < 0)
- return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
+ return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path);
+ else
+ (void) import_assign_pool_quota_and_warn(i->temp_path);
i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (i->tar_fd < 0)
diff --git a/src/import/import.c b/src/import/import.c
index 929a840298..018b94d4c4 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -22,15 +22,19 @@
#include <getopt.h>
#include "sd-event.h"
+
+#include "alloc-util.h"
#include "event-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "signal-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "hostname-util.h"
-#include "machine-image.h"
-#include "import-util.h"
-#include "import-tar.h"
#include "import-raw.h"
+#include "import-tar.h"
+#include "import-util.h"
+#include "machine-image.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "verbs.h"
static bool arg_force = false;
static bool arg_read_only = false;
@@ -280,9 +284,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORCE:
arg_force = true;
diff --git a/src/import/importd.c b/src/import/importd.c
index c90ada5da4..4228681cea 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -22,20 +22,28 @@
#include <sys/prctl.h>
#include "sd-bus.h"
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-common-errors.h"
-#include "socket-util.h"
-#include "mkdir.h"
+#include "bus-util.h"
#include "def.h"
-#include "missing.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "import-util.h"
#include "machine-pool.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "import-util.h"
#include "process-util.h"
#include "signal-util.h"
-#include "hostname-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "user-util.h"
+#include "util.h"
+#include "web-util.h"
typedef struct Transfer Transfer;
typedef struct Manager Manager;
@@ -600,11 +608,11 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
-
+ CMSG_FOREACH(cmsg, &msghdr)
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
if (msghdr.msg_flags & MSG_TRUNC) {
log_warning("Got overly long notification datagram, ignoring.");
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index 38201e46e1..d6567ba7ee 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -21,18 +21,28 @@
#include <sys/prctl.h>
-#include "util.h"
-#include "strv.h"
-#include "copy.h"
-#include "rm-rf.h"
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "capability.h"
-#include "pull-job.h"
-#include "pull-common.h"
+#include "capability-util.h"
+#include "copy.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "path-util.h"
#include "process-util.h"
+#include "pull-common.h"
+#include "pull-job.h"
+#include "rm-rf.h"
#include "signal-util.h"
+#include "siphash24.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "web-util.h"
#define FILENAME_ESCAPE "/.#\"\'"
+#define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16)
int pull_find_old_etags(
const char *url,
@@ -136,7 +146,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
if (force_local)
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
- r = btrfs_subvol_snapshot(final, p, 0);
+ r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA);
if (r == -ENOTTY) {
r = copy_tree(final, p, false);
if (r < 0)
@@ -149,8 +159,21 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
return 0;
}
+static int hash_url(const char *url, char **ret) {
+ uint64_t h;
+ static const sd_id128_t k = SD_ID128_ARRAY(df,89,16,87,01,cc,42,30,98,ab,4a,19,a6,a5,63,4f);
+
+ assert(url);
+
+ siphash24((uint8_t *) &h, url, strlen(url), k.bytes);
+ if (asprintf(ret, "%"PRIx64, h) < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
- _cleanup_free_ char *escaped_url = NULL;
+ _cleanup_free_ char *escaped_url = NULL, *escaped_etag = NULL;
char *path;
assert(url);
@@ -164,18 +187,35 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
return -ENOMEM;
if (etag) {
- _cleanup_free_ char *escaped_etag = NULL;
-
escaped_etag = xescape(etag, FILENAME_ESCAPE);
if (!escaped_etag)
return -ENOMEM;
+ }
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
- } else
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
+ path = strjoin(image_root, "/", strempty(prefix), escaped_url, escaped_etag ? "." : "",
+ strempty(escaped_etag), strempty(suffix), NULL);
if (!path)
return -ENOMEM;
+ /* URLs might make the path longer than the maximum allowed length for a file name.
+ * When that happens, a URL hash is used instead. Paths returned by this function
+ * can be later used with tempfn_random() which adds 16 bytes to the resulting name. */
+ if (strlen(path) >= HASH_URL_THRESHOLD_LENGTH) {
+ _cleanup_free_ char *hash = NULL;
+ int r;
+
+ free(path);
+
+ r = hash_url(url, &hash);
+ if (r < 0)
+ return r;
+
+ path = strjoin(image_root, "/", strempty(prefix), hash, escaped_etag ? "." : "",
+ strempty(escaped_etag), strempty(suffix), NULL);
+ if (!path)
+ return -ENOMEM;
+ }
+
*ret = path;
return 0;
}
@@ -334,9 +374,10 @@ int pull_verify(PullJob *main_job,
log_info("SHA256 checksum of %s is valid.", main_job->url);
- assert(!settings_job || settings_job->state == PULL_JOB_DONE);
+ assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
if (settings_job &&
+ settings_job->state == PULL_JOB_DONE &&
settings_job->error == 0 &&
!settings_job->etag_exists) {
diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c
index 0dab184af1..831470ff13 100644
--- a/src/import/pull-dkr.c
+++ b/src/import/pull-dkr.c
@@ -23,22 +23,29 @@
#include <sys/prctl.h>
#include "sd-daemon.h"
-#include "json.h"
-#include "strv.h"
+
+#include "alloc-util.h"
+#include "aufs-util.h"
#include "btrfs-util.h"
-#include "utf8.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
+#include "json.h"
#include "mkdir.h"
-#include "rm-rf.h"
#include "path-util.h"
-#include "import-util.h"
-#include "curl-util.h"
-#include "aufs-util.h"
-#include "pull-job.h"
+#include "process-util.h"
#include "pull-common.h"
-#include "import-common.h"
#include "pull-dkr.h"
-#include "process-util.h"
-#include "hostname-util.h"
+#include "pull-job.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "web-util.h"
typedef enum DkrProgress {
DKR_SEARCHING,
@@ -476,13 +483,13 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
if (!i->final_path) {
i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL);
if (!i->final_path)
- return log_oom();
+ return -ENOMEM;
}
if (version == DKR_PULL_V2) {
- r = path_get_parent(i->image_root, &p);
- if (r < 0)
- return r;
+ p = dirname_malloc(i->image_root);
+ if (!p)
+ return -ENOMEM;
}
r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local);
@@ -490,10 +497,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
return r;
if (version == DKR_PULL_V2) {
- char **k = NULL;
+ char **k;
+
STRV_FOREACH(k, i->ancestry) {
- _cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL);
- r = btrfs_subvol_remove(d, false);
+ _cleanup_free_ char *d;
+
+ d = strjoin(i->image_root, "/.dkr-", *k, NULL);
+ if (!d)
+ return -ENOMEM;
+
+ r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA);
if (r < 0)
return r;
}
@@ -531,12 +544,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) {
const char *base_path;
base_path = strjoina(i->image_root, "/.dkr-", base);
- r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
+ r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA);
} else
r = btrfs_subvol_make(i->temp_path);
if (r < 0)
return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
+ (void) import_assign_pool_quota_and_warn(i->temp_path);
+
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (j->disk_fd < 0)
return j->disk_fd;
diff --git a/src/import/pull-job.c b/src/import/pull-job.c
index 42939f2104..824fa246ec 100644
--- a/src/import/pull-job.c
+++ b/src/import/pull-job.c
@@ -21,9 +21,16 @@
#include <sys/xattr.h>
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
#include "machine-pool.h"
+#include "parse-util.h"
#include "pull-job.h"
+#include "string-util.h"
+#include "strv.h"
+#include "xattr-util.h"
PullJob* pull_job_unref(PullJob *j) {
if (!j)
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index 0e77197e34..03bfb51756 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -19,28 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/xattr.h>
-#include <linux/fs.h>
#include <curl/curl.h>
+#include <linux/fs.h>
+#include <sys/xattr.h>
#include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "util.h"
+#include "chattr-util.h"
+#include "copy.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
#include "macro.h"
#include "mkdir.h"
-#include "rm-rf.h"
#include "path-util.h"
-#include "hostname-util.h"
-#include "import-util.h"
-#include "import-common.h"
-#include "curl-util.h"
-#include "qcow2-util.h"
-#include "pull-job.h"
#include "pull-common.h"
+#include "pull-job.h"
#include "pull-raw.h"
+#include "qcow2-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "util.h"
+#include "web-util.h"
typedef enum RawProgress {
RAW_DOWNLOADING,
@@ -236,7 +244,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", t);
+ log_warning_errno(r, "Failed to set file attributes on %s: %m", t);
log_info("Unpacking QCOW2 file.");
@@ -312,7 +320,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
* writes. */
r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp);
+ log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true);
if (r < 0) {
@@ -327,8 +335,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
r = rename(tp, p);
if (r < 0) {
+ r = log_error_errno(errno, "Failed to move writable image into place: %m");
unlink(tp);
- return log_error_errno(errno, "Failed to move writable image into place: %m");
+ return r;
}
log_info("Created new local image '%s'.", i->local);
@@ -349,9 +358,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
-
- log_info("Create new settings file '%s.nspawn'", i->local);
+ log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
+ else
+ log_info("Created new settings file '%s.nspawn'", i->local);
}
return 0;
@@ -503,7 +512,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path);
+ log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
return 0;
}
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index 563765d83d..e7fcd293f1 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -23,23 +23,30 @@
#include <curl/curl.h>
#include "sd-daemon.h"
-#include "utf8.h"
-#include "strv.h"
-#include "copy.h"
+
+#include "alloc-util.h"
#include "btrfs-util.h"
-#include "util.h"
+#include "copy.h"
+#include "curl-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "import-common.h"
+#include "import-util.h"
#include "macro.h"
#include "mkdir.h"
-#include "rm-rf.h"
#include "path-util.h"
#include "process-util.h"
-#include "hostname-util.h"
-#include "import-util.h"
-#include "import-common.h"
-#include "curl-util.h"
-#include "pull-job.h"
#include "pull-common.h"
+#include "pull-job.h"
#include "pull-tar.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+#include "util.h"
+#include "web-util.h"
typedef enum TarProgress {
TAR_DOWNLOADING,
@@ -247,9 +254,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
-
- log_info("Create new settings file '%s.nspawn'", i->local);
+ log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
+ else
+ log_info("Created new settings file '%s.nspawn'", i->local);
}
return 0;
@@ -409,7 +416,9 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
if (mkdir(i->temp_path, 0755) < 0)
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
} else if (r < 0)
- return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
+ return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path);
+ else
+ (void) import_assign_pool_quota_and_warn(i->temp_path);
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (j->disk_fd < 0)
diff --git a/src/import/pull.c b/src/import/pull.c
index 98c22aeec9..39f5b2d8e4 100644
--- a/src/import/pull.c
+++ b/src/import/pull.c
@@ -22,16 +22,20 @@
#include <getopt.h>
#include "sd-event.h"
+
+#include "alloc-util.h"
#include "event-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "signal-util.h"
#include "hostname-util.h"
-#include "machine-image.h"
#include "import-util.h"
-#include "pull-tar.h"
-#include "pull-raw.h"
+#include "machine-image.h"
+#include "parse-util.h"
#include "pull-dkr.h"
+#include "pull-raw.h"
+#include "pull-tar.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "verbs.h"
+#include "web-util.h"
static bool arg_force = false;
static const char *arg_image_root = "/var/lib/machines";
@@ -381,9 +385,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORCE:
arg_force = true;
diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c
index fd3cf1b0e3..47dabaa86e 100644
--- a/src/import/qcow2-util.c
+++ b/src/import/qcow2-util.c
@@ -21,10 +21,11 @@
#include <zlib.h>
-#include "util.h"
-#include "sparse-endian.h"
-#include "qcow2-util.h"
+#include "alloc-util.h"
#include "btrfs-util.h"
+#include "qcow2-util.h"
+#include "sparse-endian.h"
+#include "util.h"
#define QCOW2_MAGIC 0x514649fb
diff --git a/src/import/test-qcow2.c b/src/import/test-qcow2.c
index 9a6c3e8b35..4b60079619 100644
--- a/src/import/test-qcow2.c
+++ b/src/import/test-qcow2.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "fd-util.h"
#include "log.h"
-#include "util.h"
-
#include "qcow2-util.h"
+#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_close_ int sfd = -1, dfd = -1;
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index 6d08db74ef..d4f8673187 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -25,18 +25,20 @@
#include <sys/epoll.h>
#include <ctype.h>
-#include "sd-daemon.h"
#include "sd-bus.h"
+#include "sd-daemon.h"
-#include "util.h"
-#include "log.h"
-#include "list.h"
-#include "initreq.h"
-#include "special.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-util.h"
#include "def.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "initreq.h"
+#include "list.h"
+#include "log.h"
+#include "special.h"
+#include "util.h"
#define SERVER_FD_MAX 16
#define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
@@ -210,8 +212,7 @@ static int fifo_process(Fifo *f) {
if (errno == EAGAIN)
return 0;
- log_warning_errno(errno, "Failed to read from fifo: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to read from fifo: %m");
}
f->bytes_read += l;
@@ -318,7 +319,7 @@ static int server_init(Server *s, unsigned n_sockets) {
s->n_fifos ++;
}
- r = bus_open_system_systemd(&s->bus);
+ r = bus_connect_system_systemd(&s->bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 4e5572db0b..6b93a758f6 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -19,30 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
-
-#include <microhttpd.h>
-
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-#include "sd-journal.h"
-#include "sd-daemon.h"
#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
+#include "sd-daemon.h"
+#include "sd-journal.h"
+
+#include "alloc-util.h"
#include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hostname-util.h"
+#include "log.h"
#include "logs-show.h"
#include "microhttpd-util.h"
-#include "build.h"
-#include "fileio.h"
+#include "parse-util.h"
#include "sigbus.h"
-#include "hostname-util.h"
+#include "util.h"
static char *arg_key_pem = NULL;
static char *arg_cert_pem = NULL;
@@ -909,9 +910,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_KEY:
if (arg_key_pem) {
@@ -1014,7 +1013,22 @@ int main(int argc, char *argv[]) {
{ MHD_OPTION_END, 0, NULL },
{ MHD_OPTION_END, 0, NULL }};
int opts_pos = 2;
- int flags = MHD_USE_THREAD_PER_CONNECTION|MHD_USE_POLL|MHD_USE_DEBUG;
+
+ /* We force MHD_USE_PIPE_FOR_SHUTDOWN here, in order
+ * to make sure libmicrohttpd doesn't use shutdown()
+ * on our listening socket, which would break socket
+ * re-activation. See
+ *
+ * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
+ * https://github.com/systemd/systemd/pull/1286
+ */
+
+ int flags =
+ MHD_USE_DEBUG |
+ MHD_USE_DUAL_STACK |
+ MHD_USE_PIPE_FOR_SHUTDOWN |
+ MHD_USE_POLL |
+ MHD_USE_THREAD_PER_CONNECTION;
if (n > 0)
opts[opts_pos++] = (struct MHD_OptionItem)
diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c
index 2e0f78701a..3ff40228a0 100644
--- a/src/journal-remote/journal-remote-parse.c
+++ b/src/journal-remote/journal-remote-parse.c
@@ -19,8 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "fd-util.h"
#include "journal-remote-parse.h"
#include "journald-native.h"
+#include "parse-util.h"
+#include "string-util.h"
#define LINE_CHUNK 8*1024u
diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c
index 40f4ff8e58..d8250378b0 100644
--- a/src/journal-remote/journal-remote-write.c
+++ b/src/journal-remote/journal-remote-write.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "journal-remote.h"
int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) {
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index d6ebca20ec..6eb0ee9d9e 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -21,31 +21,39 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <unistd.h>
-#include <getopt.h>
-
-#include "sd-daemon.h"
-#include "signal-util.h"
-#include "journal-file.h"
-#include "journald-native.h"
-#include "socket-util.h"
-#include "build.h"
-#include "macro.h"
-#include "strv.h"
-#include "fileio.h"
-#include "conf-parser.h"
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
-#include "journal-remote.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "journal-file.h"
#include "journal-remote-write.h"
+#include "journal-remote.h"
+#include "journald-native.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
@@ -138,7 +146,7 @@ static int spawn_curl(const char* url) {
r = spawn_child("curl", argv);
if (r < 0)
- log_error_errno(errno, "Failed to spawn curl: %m");
+ log_error_errno(r, "Failed to spawn curl: %m");
return r;
}
@@ -157,7 +165,7 @@ static int spawn_getter(const char *getter, const char *url) {
r = spawn_child(words[0], words);
if (r < 0)
- log_error_errno(errno, "Failed to spawn getter %s: %m", getter);
+ log_error_errno(r, "Failed to spawn getter %s: %m", getter);
return r;
}
@@ -641,16 +649,18 @@ static int setup_microhttpd_server(RemoteServer *s,
{ MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
{ MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
{ MHD_OPTION_LISTEN_SOCKET, fd},
+ { MHD_OPTION_CONNECTION_MEMORY_LIMIT, DATA_SIZE_MAX},
{ MHD_OPTION_END},
{ MHD_OPTION_END},
{ MHD_OPTION_END},
{ MHD_OPTION_END}};
- int opts_pos = 3;
+ int opts_pos = 4;
int flags =
MHD_USE_DEBUG |
- MHD_USE_PEDANTIC_CHECKS |
+ MHD_USE_DUAL_STACK |
MHD_USE_EPOLL_LINUX_ONLY |
- MHD_USE_DUAL_STACK;
+ MHD_USE_PEDANTIC_CHECKS |
+ MHD_USE_PIPE_FOR_SHUTDOWN;
const union MHD_DaemonInfo *info;
int r, epoll_fd;
@@ -954,7 +964,7 @@ static int remoteserver_init(RemoteServer *s,
}
if (s->active == 0) {
- log_error("Zarro sources specified");
+ log_error("Zero sources specified");
return -EINVAL;
}
@@ -1259,9 +1269,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0 /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case ARG_URL:
if (arg_url) {
@@ -1409,18 +1417,21 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_GNUTLS_LOG: {
#ifdef HAVE_GNUTLS
- const char *word, *state;
- size_t size;
+ const char* p = optarg;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *cat;
+ r = extract_first_word(&p, &word, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m");
- cat = strndup(word, size);
- if (!cat)
- return log_oom();
+ if (r == 0)
+ break;
- if (strv_consume(&arg_gnutls_log, cat) < 0)
+ if (strv_push(&arg_gnutls_log, word) < 0)
return log_oom();
+
+ word = NULL;
}
break;
#else
diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c
index 6b3ad924a7..3ee6d32bf7 100644
--- a/src/journal-remote/journal-upload-journal.c
+++ b/src/journal-remote/journal-upload-journal.c
@@ -1,11 +1,33 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
#include <stdbool.h>
#include <curl/curl.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "journal-upload.h"
#include "log.h"
#include "utf8.h"
-#include "journal-upload.h"
+#include "util.h"
/**
* Write up to size bytes to buf. Return negative on error, and number of
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 311bd3fdda..42d14dc7c4 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -19,23 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <curl/curl.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
+#include <stdio.h>
+#include <sys/stat.h>
#include "sd-daemon.h"
-#include "log.h"
-#include "util.h"
-#include "build.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "formats-util.h"
+#include "glob-util.h"
+#include "journal-upload.h"
+#include "log.h"
#include "mkdir.h"
-#include "conf-parser.h"
+#include "parse-util.h"
#include "sigbus.h"
-#include "formats-util.h"
#include "signal-util.h"
-#include "journal-upload.h"
+#include "string-util.h"
+#include "util.h"
#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
#define CERT_FILE CERTIFICATE_ROOT "/certs/journal-upload.pem"
@@ -619,9 +625,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0 /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case 'u':
if (arg_url) {
diff --git a/src/journal-remote/log-generator.py b/src/journal-remote/log-generator.py
index 9a8fb07c7f..fd6964e758 100755
--- a/src/journal-remote/log-generator.py
+++ b/src/journal-remote/log-generator.py
@@ -6,6 +6,8 @@ import argparse
PARSER = argparse.ArgumentParser()
PARSER.add_argument('n', type=int)
PARSER.add_argument('--dots', action='store_true')
+PARSER.add_argument('--data-size', type=int, default=4000)
+PARSER.add_argument('--data-type', choices={'random', 'simple'})
OPTIONS = PARSER.parse_args()
template = """\
@@ -38,10 +40,16 @@ facility = 6
src = open('/dev/urandom', 'rb')
bytes = 0
+counter = 0
for i in range(OPTIONS.n):
message = repr(src.read(2000))
- data = repr(src.read(4000))
+ if OPTIONS.data_type == 'random':
+ data = repr(src.read(OPTIONS.data_size))
+ else:
+ # keep the pattern non-repeating so we get a different blob every time
+ data = '{:0{}}'.format(counter, OPTIONS.data_size)
+ counter += 1
entry = template.format(m=m,
realtime_ts=realtime_ts,
diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c
index 8a11fba044..b2c398a845 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/journal-remote/microhttpd-util.c
@@ -24,17 +24,19 @@
#include <stdio.h>
#include <string.h>
-#include "microhttpd-util.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "strv.h"
-
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#endif
+#include "alloc-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+#include "microhttpd-util.h"
+
void microhttpd_logger(void *arg, const char *fmt, va_list ap) {
char *f;
diff --git a/src/journal/cat.c b/src/journal/cat.c
index be2c2e3354..7fd4198df8 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -19,17 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
+#include "fd-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
#include "util.h"
-#include "build.h"
static char *arg_identifier = NULL;
static int arg_priority = LOG_INFO;
@@ -76,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 't':
free(arg_identifier);
@@ -95,7 +96,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_priority = log_level_from_string(optarg);
if (arg_priority < 0) {
log_error("Failed to parse priority value.");
- return arg_priority;
+ return -EINVAL;
}
break;
@@ -103,10 +104,9 @@ static int parse_argv(int argc, char *argv[]) {
int k;
k = parse_boolean(optarg);
- if (k < 0) {
- log_error("Failed to parse level prefix value.");
- return k;
- }
+ if (k < 0)
+ return log_error_errno(k, "Failed to parse level prefix value.");
+
arg_level_prefix = k;
break;
}
@@ -122,7 +122,8 @@ static int parse_argv(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
- int r, fd = -1, saved_stderr = -1;
+ _cleanup_close_ int fd = -1, saved_stderr = -1;
+ int r;
log_parse_environment();
log_open();
@@ -133,8 +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_errno(fd, "Failed to create stream fd: %m");
- r = fd;
+ r = log_error_errno(fd, "Failed to create stream fd: %m");
goto finish;
}
@@ -148,25 +148,20 @@ int main(int argc, char *argv[]) {
if (fd >= 3)
safe_close(fd);
-
fd = -1;
if (argc <= optind)
- execl("/bin/cat", "/bin/cat", NULL);
+ (void) execl("/bin/cat", "/bin/cat", NULL);
else
- execvp(argv[optind], argv + optind);
-
+ (void) execvp(argv[optind], argv + optind);
r = -errno;
/* Let's try to restore a working stderr, so we can print the error message */
if (saved_stderr >= 0)
- dup3(saved_stderr, STDERR_FILENO, 0);
+ (void) dup3(saved_stderr, STDERR_FILENO, 0);
log_error_errno(r, "Failed to execute process: %m");
finish:
- safe_close(fd);
- safe_close(saved_stderr);
-
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index a3e51e2f52..fcaa54aa0c 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -19,25 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <fcntl.h>
+#include <locale.h>
#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
#include <string.h>
#include <sys/mman.h>
-#include <locale.h>
+#include <unistd.h>
-#include "util.h"
-#include "log.h"
-#include "sparse-endian.h"
#include "sd-id128.h"
-#include "hashmap.h"
-#include "strv.h"
-#include "strbuf.h"
+
+#include "alloc-util.h"
+#include "catalog.h"
#include "conf-files.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "log.h"
#include "mkdir.h"
-#include "catalog.h"
+#include "path-util.h"
#include "siphash24.h"
+#include "sparse-endian.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
const char * const catalog_file_dirs[] = {
"/usr/local/lib/systemd/catalog/",
@@ -62,21 +68,11 @@ typedef struct CatalogItem {
le64_t offset;
} CatalogItem;
-static unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void catalog_hash_func(const void *p, struct siphash *state) {
const CatalogItem *i = p;
- uint64_t u;
- size_t l, sz;
- void *v;
- l = strlen(i->language);
- sz = sizeof(i->id) + l;
- v = alloca(sz);
-
- memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l);
-
- siphash24((uint8_t*) &u, v, sz, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&i->id, sizeof(i->id), state);
+ siphash24_compress(i->language, strlen(i->language), state);
}
static int catalog_compare_func(const void *a, const void *b) {
@@ -212,7 +208,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
r = catalog_file_lang(path, &deflang);
if (r < 0)
- log_error_errno(errno, "Failed to determine language for file %s: %m", path);
+ log_error_errno(r, "Failed to determine language for file %s: %m", path);
if (r == 1)
log_debug("File %s has language %s.", path, deflang);
@@ -225,8 +221,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
if (feof(f))
break;
- log_error_errno(errno, "Failed to read file %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to read file %s: %m", path);
}
n++;
@@ -323,8 +318,8 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
return 0;
}
-static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
- CatalogItem *items, size_t n) {
+static int64_t write_catalog(const char *database, struct strbuf *sb,
+ CatalogItem *items, size_t n) {
CatalogHeader header;
_cleanup_fclose_ FILE *w = NULL;
int r;
@@ -348,7 +343,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
header.catalog_item_size = htole64(sizeof(CatalogItem));
- header.n_items = htole64(hashmap_size(h));
+ header.n_items = htole64(n);
r = -EIO;
@@ -383,7 +378,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
goto error;
}
- return ftell(w);
+ return ftello(w);
error:
(void) unlink(p);
@@ -399,7 +394,8 @@ int catalog_update(const char* database, const char* root, const char* const* di
CatalogItem *i;
Iterator j;
unsigned n;
- long r;
+ int r;
+ int64_t sz;
h = hashmap_new(&catalog_hash_ops);
sb = strbuf_new();
@@ -419,8 +415,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
log_debug("Reading file '%s'", *f);
r = catalog_import_file(h, sb, *f);
if (r < 0) {
- log_error("Failed to import file '%s': %s.",
- *f, strerror(-r));
+ log_error_errno(r, "Failed to import file '%s': %m", *f);
goto finish;
}
}
@@ -450,18 +445,19 @@ int catalog_update(const char* database, const char* root, const char* const* di
assert(n == hashmap_size(h));
qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
- r = write_catalog(database, h, sb, items, n);
- if (r < 0)
- log_error_errno(r, "Failed to write %s: %m", database);
- else
- log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
- database, n, sb->len, r);
+ sz = write_catalog(database, sb, items, n);
+ if (sz < 0)
+ r = log_error_errno(sz, "Failed to write %s: %m", database);
+ else {
+ r = 0;
+ log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total size.",
+ database, n, sb->len, sz);
+ }
finish:
- if (sb)
- strbuf_cleanup(sb);
+ strbuf_cleanup(sb);
- return r < 0 ? r : 0;
+ return r;
}
static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
@@ -676,8 +672,7 @@ 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_errno(k, "Failed to parse id128 '%s': %m",
- *item);
+ log_error_errno(k, "Failed to parse id128 '%s': %m", *item);
if (r == 0)
r = k;
continue;
@@ -685,9 +680,8 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items
k = catalog_get(database, id, &msg);
if (k < 0) {
- log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
- "Failed to retrieve catalog entry for '%s': %s",
- *item, strerror(-k));
+ log_full_errno(k == -ENOENT ? LOG_NOTICE : LOG_ERR, k,
+ "Failed to retrieve catalog entry for '%s': %m", *item);
if (r == 0)
r = k;
continue;
diff --git a/src/journal/compress.c b/src/journal/compress.c
index c66043e503..e1ca0a8818 100644
--- a/src/journal/compress.c
+++ b/src/journal/compress.c
@@ -21,21 +21,33 @@
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <unistd.h>
#ifdef HAVE_XZ
-# include <lzma.h>
+#include <lzma.h>
#endif
#ifdef HAVE_LZ4
-# include <lz4.h>
+#include <lz4.h>
+#include <lz4frame.h>
#endif
+#include "alloc-util.h"
#include "compress.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "journal-def.h"
#include "macro.h"
-#include "util.h"
#include "sparse-endian.h"
-#include "journal-def.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+
+#ifdef HAVE_LZ4
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext);
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
+#endif
#define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
@@ -50,10 +62,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_
#ifdef HAVE_XZ
static const lzma_options_lzma opt = {
1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
- LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4};
- static const lzma_filter filters[2] = {
- {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt},
- {LZMA_VLI_UNKNOWN, NULL}
+ LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4
+ };
+ static const lzma_filter filters[] = {
+ { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt },
+ { LZMA_VLI_UNKNOWN, NULL }
};
lzma_ret ret;
size_t out_pos = 0;
@@ -416,81 +429,96 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
#endif
}
-#define LZ4_BUFSIZE (512*1024)
+#define LZ4_BUFSIZE (512*1024u)
int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
#ifdef HAVE_LZ4
+ LZ4F_errorCode_t c;
+ _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
+ _cleanup_free_ char *buf = NULL;
+ char *src = NULL;
+ size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size;
+ struct stat st;
+ int r;
+ static const LZ4F_compressOptions_t options = {
+ .stableSrc = 1,
+ };
+ static const LZ4F_preferences_t preferences = {
+ .frameInfo.blockSizeID = 5,
+ };
- _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL;
- char *buf;
- LZ4_stream_t lz4_data = {};
- le32_t header;
- size_t total_in = 0, total_out = sizeof(header);
- ssize_t n;
+ c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
+ if (LZ4F_isError(c))
+ return -ENOMEM;
- assert(fdf >= 0);
- assert(fdt >= 0);
+ if (fstat(fdf, &st) < 0)
+ return log_debug_errno(errno, "fstat() failed: %m");
- buf1 = malloc(LZ4_BUFSIZE);
- buf2 = malloc(LZ4_BUFSIZE);
- out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE));
- if (!buf1 || !buf2 || !out)
- return log_oom();
+ frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences);
+ size = frame_size + 64*1024; /* add some space for header and trailer */
+ buf = malloc(size);
+ if (!buf)
+ return -ENOMEM;
- buf = buf1;
- for (;;) {
- size_t m;
- int r;
+ n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences);
+ if (LZ4F_isError(n))
+ return -EINVAL;
- m = LZ4_BUFSIZE;
- if (max_bytes != (uint64_t) -1 && (uint64_t) m > (max_bytes - total_in))
- m = (size_t) (max_bytes - total_in);
+ src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0);
+ if (src == MAP_FAILED)
+ return -errno;
- n = read(fdf, buf, m);
- if (n < 0)
- return -errno;
- if (n == 0)
- break;
+ log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n);
- total_in += n;
+ while (total_in < (size_t) st.st_size) {
+ ssize_t k;
- r = LZ4_compress_continue(&lz4_data, buf, out, n);
- if (r == 0) {
- log_error("LZ4 compression failed.");
- return -EBADMSG;
+ k = MIN(LZ4_BUFSIZE, st.st_size - total_in);
+ n = LZ4F_compressUpdate(ctx, buf + offset, size - offset,
+ src + total_in, k, &options);
+ if (LZ4F_isError(n)) {
+ r = -ENOTRECOVERABLE;
+ goto cleanup;
}
- header = htole32(r);
- errno = 0;
-
- n = write(fdt, &header, sizeof(header));
- if (n < 0)
- return -errno;
- if (n != sizeof(header))
- return errno ? -errno : -EIO;
+ total_in += k;
+ offset += n;
+ total_out += n;
- n = loop_write(fdt, out, r, false);
- if (n < 0)
- return n;
+ if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+ log_debug("Compressed stream longer than %zd bytes", max_bytes);
+ return -EFBIG;
+ }
- total_out += sizeof(header) + r;
+ if (size - offset < frame_size + 4) {
+ k = loop_write(fdt, buf, offset, false);
+ if (k < 0) {
+ r = k;
+ goto cleanup;
+ }
+ offset = 0;
+ }
+ }
- buf = buf == buf1 ? buf2 : buf1;
+ n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options);
+ if (LZ4F_isError(n)) {
+ r = -ENOTRECOVERABLE;
+ goto cleanup;
}
- header = htole32(0);
- n = write(fdt, &header, sizeof(header));
- if (n < 0)
- return -errno;
- if (n != sizeof(header))
- return errno ? -errno : -EIO;
+ offset += n;
+ total_out += n;
+ r = loop_write(fdt, buf, offset, false);
+ if (r < 0)
+ goto cleanup;
log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
total_in, total_out,
(double) total_out / total_in * 100);
-
- return 0;
+ cleanup:
+ munmap(src, st.st_size);
+ return r;
#else
return -EPROTONOSUPPORT;
#endif
@@ -510,7 +538,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
if (ret != LZMA_OK) {
- log_error("Failed to initialize XZ decoder: code %u", ret);
+ log_debug("Failed to initialize XZ decoder: code %u", ret);
return -ENOMEM;
}
@@ -536,7 +564,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
ret = lzma_code(&s, action);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
- log_error("Decompression failed: code %u", ret);
+ log_debug("Decompression failed: code %u", ret);
return -EBADMSG;
}
@@ -566,14 +594,14 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
}
}
#else
- log_error("Cannot decompress file. Compiled without XZ support.");
+ log_debug("Cannot decompress file. Compiled without XZ support.");
return -EPROTONOSUPPORT;
#endif
}
-int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
-
#ifdef HAVE_LZ4
+static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) {
+
_cleanup_free_ char *buf = NULL, *out = NULL;
size_t buf_size = 0;
LZ4_streamDecode_t lz4_data = {};
@@ -585,7 +613,7 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
out = malloc(4*LZ4_BUFSIZE);
if (!out)
- return log_oom();
+ return -ENOMEM;
for (;;) {
ssize_t m;
@@ -606,22 +634,24 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
* not accept buffers compressed by newer binaries then.
*/
if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
- log_error("Compressed stream block too big: %zd bytes", m);
- return -EBADMSG;
+ log_debug("Compressed stream block too big: %zd bytes", m);
+ return -ENOBUFS;
}
total_in += sizeof(header) + m;
if (!GREEDY_REALLOC(buf, buf_size, m))
- return log_oom();
+ return -ENOMEM;
r = loop_read_exact(fdf, buf, m, false);
if (r < 0)
return r;
r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
- if (r <= 0)
- log_error("LZ4 decompression failed.");
+ if (r <= 0) {
+ log_debug("LZ4 decompression failed (legacy format).");
+ return -EBADMSG;
+ }
total_out += r;
@@ -635,13 +665,80 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
return r;
}
- log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+ log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)",
total_in, total_out,
(double) total_out / total_in * 100);
return 0;
+}
+
+static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) {
+ size_t c;
+ _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
+ _cleanup_free_ char *buf = NULL;
+ char *src;
+ struct stat st;
+ int r = 0;
+ size_t total_in = 0, total_out = 0;
+
+ c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
+ if (LZ4F_isError(c))
+ return -ENOMEM;
+
+ if (fstat(in, &st) < 0)
+ return log_debug_errno(errno, "fstat() failed: %m");
+
+ buf = malloc(LZ4_BUFSIZE);
+ if (!buf)
+ return -ENOMEM;
+
+ src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0);
+ if (src == MAP_FAILED)
+ return -errno;
+
+ while (total_in < (size_t) st.st_size) {
+ size_t produced = LZ4_BUFSIZE;
+ size_t used = st.st_size - total_in;
+
+ c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL);
+ if (LZ4F_isError(c)) {
+ r = -EBADMSG;
+ goto cleanup;
+ }
+
+ total_in += used;
+ total_out += produced;
+
+ if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+ log_debug("Decompressed stream longer than %zd bytes", max_bytes);
+ r = -EFBIG;
+ goto cleanup;
+ }
+
+ r = loop_write(out, buf, produced, false);
+ if (r < 0)
+ goto cleanup;
+ }
+
+ log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+ total_in, total_out,
+ (double) total_out / total_in * 100);
+ cleanup:
+ munmap(src, st.st_size);
+ return r;
+}
+#endif
+
+int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
+#ifdef HAVE_LZ4
+ int r;
+
+ r = decompress_stream_lz4_v2(fdf, fdt, max_bytes);
+ if (r == -EBADMSG)
+ r = decompress_stream_lz4_v1(fdf, fdt, max_bytes);
+ return r;
#else
- log_error("Cannot decompress file. Compiled without LZ4 support.");
+ log_debug("Cannot decompress file. Compiled without LZ4 support.");
return -EPROTONOSUPPORT;
#endif
}
diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c
index efe418615a..39bc2e4270 100644
--- a/src/journal/coredump-vacuum.c
+++ b/src/journal/coredump-vacuum.c
@@ -21,12 +21,16 @@
#include <sys/statvfs.h>
-#include "util.h"
-#include "time-util.h"
+#include "alloc-util.h"
+#include "coredump-vacuum.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "hashmap.h"
#include "macro.h"
-
-#include "coredump-vacuum.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "user-util.h"
+#include "util.h"
#define DEFAULT_MAX_USE_LOWER (uint64_t) (1ULL*1024ULL*1024ULL) /* 1 MiB */
#define DEFAULT_MAX_USE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
diff --git a/src/journal/coredump.c b/src/journal/coredump.c
index e1e66b9826..4c83e311db 100644
--- a/src/journal/coredump.c
+++ b/src/journal/coredump.c
@@ -20,10 +20,10 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/xattr.h>
+#include <unistd.h>
#ifdef HAVE_ELFUTILS
# include <dwarf.h>
@@ -32,23 +32,34 @@
#include "sd-journal.h"
#include "sd-login.h"
-#include "log.h"
-#include "util.h"
-#include "fileio.h"
-#include "strv.h"
-#include "macro.h"
-#include "mkdir.h"
-#include "special.h"
+
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "capability-util.h"
#include "cgroup-util.h"
+#include "compress.h"
#include "conf-parser.h"
#include "copy.h"
-#include "stacktrace.h"
-#include "compress.h"
-#include "acl-util.h"
-#include "capability.h"
-#include "journald-native.h"
#include "coredump-vacuum.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "io-util.h"
+#include "journald-native.h"
+#include "log.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "special.h"
+#include "stacktrace.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
/* The maximum size up to which we process coredumps */
#define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
@@ -128,6 +139,7 @@ static int fix_acl(int fd, uid_t uid) {
_cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
acl_permset_t permset;
+ int r;
assert(fd >= 0);
@@ -149,11 +161,12 @@ static int fix_acl(int fd, uid_t uid) {
}
if (acl_get_permset(entry, &permset) < 0 ||
- acl_add_perm(permset, ACL_READ) < 0 ||
- calc_acl_mask_if_needed(&acl) < 0) {
- log_warning_errno(errno, "Failed to patch ACL: %m");
- return -errno;
- }
+ acl_add_perm(permset, ACL_READ) < 0)
+ return log_warning_errno(errno, "Failed to patch ACL: %m");
+
+ r = calc_acl_mask_if_needed(&acl);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to patch ACL: %m");
if (acl_set_fd(fd, acl) < 0)
return log_error_errno(errno, "Failed to apply ACL: %m");
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index 6628e82421..1df28d774a 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -19,27 +19,33 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
+#include <getopt.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
-#include <getopt.h>
-#include <fcntl.h>
#include <unistd.h>
#include "sd-journal.h"
-#include "build.h"
-#include "set.h"
-#include "util.h"
+
+#include "alloc-util.h"
+#include "compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "journal-internal.h"
#include "log.h"
-#include "path-util.h"
-#include "pager.h"
#include "macro.h"
-#include "journal-internal.h"
-#include "compress.h"
-#include "sigbus.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
+#include "set.h"
+#include "sigbus.h"
#include "signal-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
static enum {
ACTION_NONE,
@@ -84,37 +90,35 @@ static Set *new_matches(void) {
}
static int add_match(Set *set, const char *match) {
- int r = -ENOMEM;
- unsigned pid;
- const char* prefix;
- char *pattern = NULL;
_cleanup_free_ char *p = NULL;
+ char *pattern = NULL;
+ const char* prefix;
+ pid_t pid;
+ int r;
if (strchr(match, '='))
prefix = "";
else if (strchr(match, '/')) {
- p = path_make_absolute_cwd(match);
- if (!p)
+ r = path_make_absolute_cwd(match, &p);
+ if (r < 0)
goto fail;
-
match = p;
prefix = "COREDUMP_EXE=";
- }
- else if (safe_atou(match, &pid) == 0)
+ } else if (parse_pid(match, &pid) >= 0)
prefix = "COREDUMP_PID=";
else
prefix = "COREDUMP_COMM=";
pattern = strjoin(prefix, match, NULL);
- if (!pattern)
+ if (!pattern) {
+ r = -ENOMEM;
goto fail;
+ }
log_debug("Adding pattern: %s", pattern);
r = set_consume(set, pattern);
- if (r < 0) {
- log_error_errno(r, "Failed to add pattern: %m");
+ if (r < 0)
goto fail;
- }
return 0;
fail:
@@ -175,9 +179,7 @@ static int parse_argv(int argc, char *argv[], Set *matches) {
case ARG_VERSION:
arg_action = ACTION_NONE;
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -615,7 +617,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
if (fdt < 0)
- return log_error_errno(errno, "Failed to create temporary file: %m");
+ return log_error_errno(fdt, "Failed to create temporary file: %m");
log_debug("Created temporary file %s", temp);
fd = fdt;
@@ -774,7 +776,7 @@ static int run_gdb(sd_journal *j) {
r = wait_for_terminate(pid, &st);
if (r < 0) {
- log_error_errno(errno, "Failed to wait for gdb: %m");
+ log_error_errno(r, "Failed to wait for gdb: %m");
goto finish;
}
diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h
index 150d034828..5959b1fed2 100644
--- a/src/journal/fsprg.h
+++ b/src/journal/fsprg.h
@@ -29,6 +29,7 @@
#include <inttypes.h>
#include "macro.h"
+#include "util.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index cdc80e2d26..0c4ac5cdc3 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -22,10 +22,12 @@
#include <fcntl.h>
#include <sys/mman.h>
+#include "fd-util.h"
+#include "fsprg.h"
+#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
-#include "journal-authenticate.h"
-#include "fsprg.h"
+#include "hexdecoct.h"
static uint64_t journal_file_tag_seqnum(JournalFile *f) {
uint64_t r;
diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 39c9dd0dbf..c003ac05dd 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -21,11 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sparse-endian.h"
-
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
#include "macro.h"
+#include "sparse-endian.h"
/*
* If you change this file you probably should also change its documentation:
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 73d3a4bb9d..f9ff9545dd 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -19,22 +19,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mman.h>
#include <errno.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <sys/statvfs.h>
#include <fcntl.h>
-#include <stddef.h>
#include <linux/fs.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/statvfs.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include "alloc-util.h"
#include "btrfs-util.h"
+#include "chattr-util.h"
+#include "compress.h"
+#include "fd-util.h"
+#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
-#include "journal-authenticate.h"
#include "lookup3.h"
-#include "compress.h"
+#include "parse-util.h"
#include "random-util.h"
+#include "string-util.h"
+#include "xattr-util.h"
#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
#define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem))
@@ -42,13 +48,16 @@
#define COMPRESSION_SIZE_THRESHOLD (512ULL)
/* This is the minimum journal file size */
-#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL) /* 4 MiB */
+#define JOURNAL_FILE_SIZE_MIN (512ULL*1024ULL) /* 512 KiB */
/* These are the lower and upper bounds if we deduce the max_use value
* from the file system size */
#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */
#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
+/* This is the default minimal use limit, how much we'll use even if keep_free suggests otherwise. */
+#define DEFAULT_MIN_USE (1ULL*1024ULL*1024ULL) /* 1 MiB */
+
/* This is the upper bound if we deduce max_size from max_use */
#define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */
@@ -60,6 +69,9 @@
* size */
#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */
+/* This is the default maximum number of journal files to keep around. */
+#define DEFAULT_N_MAX_FILES (100)
+
/* n_data was the first entry we added after the initial file format design */
#define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data))
@@ -128,7 +140,7 @@ int journal_file_set_offline(JournalFile *f) {
return 0;
}
-void journal_file_close(JournalFile *f) {
+JournalFile* journal_file_close(JournalFile *f) {
assert(f);
#ifdef HAVE_GCRYPT
@@ -179,6 +191,7 @@ void journal_file_close(JournalFile *f) {
#endif
free(f);
+ return NULL;
}
static int journal_file_init_header(JournalFile *f, JournalFile *template) {
@@ -398,12 +411,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
if (fstatvfs(f->fd, &svfs) >= 0) {
uint64_t available;
- available = svfs.f_bfree * svfs.f_bsize;
-
- if (available >= f->metrics.keep_free)
- available -= f->metrics.keep_free;
- else
- available = 0;
+ available = LESS_BY((uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize, f->metrics.keep_free);
if (new_size - old_size > available)
return -E2BIG;
@@ -604,10 +612,10 @@ static int journal_file_setup_data_hash_table(JournalFile *f) {
assert(f);
- /* We estimate that we need 1 hash table entry per 768 of
- journal file and we want to make sure we never get beyond
- 75% fill level. Calculate the hash table size for the
- maximum file size based on these metrics. */
+ /* We estimate that we need 1 hash table entry per 768 bytes
+ of journal file and we want to make sure we never get
+ beyond 75% fill level. Calculate the hash table size for
+ the maximum file size based on these metrics. */
s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem);
if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
@@ -1055,7 +1063,7 @@ static int journal_file_append_data(
r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p);
if (r < 0)
return r;
- else if (r > 0) {
+ if (r > 0) {
if (ret)
*ret = o;
@@ -1074,23 +1082,24 @@ static int journal_file_append_data(
o->data.hash = htole64(hash);
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
- if (f->compress_xz &&
- size >= COMPRESSION_SIZE_THRESHOLD) {
+ if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) {
size_t rsize = 0;
compression = compress_blob(data, size, o->data.payload, &rsize);
- if (compression) {
+ if (compression >= 0) {
o->object.size = htole64(offsetof(Object, data.payload) + rsize);
o->object.flags |= compression;
log_debug("Compressed data object %"PRIu64" -> %zu using %s",
size, rsize, object_compressed_to_string(compression));
- }
+ } else
+ /* Compression didn't work, we don't really care why, let's continue without compression */
+ compression = 0;
}
#endif
- if (!compression && size > 0)
+ if (compression == 0 && size > 0)
memcpy(o->data.payload, data, size);
r = journal_file_link_data(f, o, p, hash);
@@ -2696,7 +2705,7 @@ int journal_file_open(
}
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
- r = -EIO;
+ r = -ENODATA;
goto fail;
}
@@ -2833,8 +2842,7 @@ int journal_file_open_reliably(
size_t l;
_cleanup_free_ char *p = NULL;
- r = journal_file_open(fname, flags, mode, compress, seal,
- metrics, mmap_cache, template, ret);
+ r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
if (!IN_SET(r,
-EBADMSG, /* corrupted */
-ENODATA, /* truncated */
@@ -2864,8 +2872,7 @@ int journal_file_open_reliably(
random_u64()) < 0)
return -ENOMEM;
- r = rename(fname, p);
- if (r < 0)
+ if (rename(fname, p) < 0)
return -errno;
/* btrfs doesn't cope well with our write pattern and
@@ -2874,10 +2881,9 @@ int journal_file_open_reliably(
(void) chattr_path(p, false, FS_NOCOW_FL);
(void) btrfs_defrag(p);
- log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
+ log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
- return journal_file_open(fname, flags, mode, compress, seal,
- metrics, mmap_cache, template, ret);
+ return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
}
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
@@ -2964,16 +2970,35 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
return r;
}
+void journal_reset_metrics(JournalMetrics *m) {
+ assert(m);
+
+ /* Set everything to "pick automatic values". */
+
+ *m = (JournalMetrics) {
+ .min_use = (uint64_t) -1,
+ .max_use = (uint64_t) -1,
+ .min_size = (uint64_t) -1,
+ .max_size = (uint64_t) -1,
+ .keep_free = (uint64_t) -1,
+ .n_max_files = (uint64_t) -1,
+ };
+}
+
void journal_default_metrics(JournalMetrics *m, int fd) {
- uint64_t fs_size = 0;
+ char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX], e[FORMAT_BYTES_MAX];
struct statvfs ss;
- char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX];
+ uint64_t fs_size;
assert(m);
assert(fd >= 0);
if (fstatvfs(fd, &ss) >= 0)
fs_size = ss.f_frsize * ss.f_blocks;
+ else {
+ log_debug_errno(errno, "Failed to detremine disk size: %m");
+ fs_size = 0;
+ }
if (m->max_use == (uint64_t) -1) {
@@ -2990,10 +3015,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
} else {
m->max_use = PAGE_ALIGN(m->max_use);
- if (m->max_use < JOURNAL_FILE_SIZE_MIN*2)
+ if (m->max_use != 0 && m->max_use < JOURNAL_FILE_SIZE_MIN*2)
m->max_use = JOURNAL_FILE_SIZE_MIN*2;
}
+ if (m->min_use == (uint64_t) -1)
+ m->min_use = DEFAULT_MIN_USE;
+
+ if (m->min_use > m->max_use)
+ m->min_use = m->max_use;
+
if (m->max_size == (uint64_t) -1) {
m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */
@@ -3002,11 +3033,13 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
} else
m->max_size = PAGE_ALIGN(m->max_size);
- if (m->max_size < JOURNAL_FILE_SIZE_MIN)
- m->max_size = JOURNAL_FILE_SIZE_MIN;
+ if (m->max_size != 0) {
+ if (m->max_size < JOURNAL_FILE_SIZE_MIN)
+ m->max_size = JOURNAL_FILE_SIZE_MIN;
- if (m->max_size*2 > m->max_use)
- m->max_use = m->max_size*2;
+ if (m->max_use != 0 && m->max_size*2 > m->max_use)
+ m->max_use = m->max_size*2;
+ }
if (m->min_size == (uint64_t) -1)
m->min_size = JOURNAL_FILE_SIZE_MIN;
@@ -3016,7 +3049,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
if (m->min_size < JOURNAL_FILE_SIZE_MIN)
m->min_size = JOURNAL_FILE_SIZE_MIN;
- if (m->min_size > m->max_size)
+ if (m->max_size != 0 && m->min_size > m->max_size)
m->max_size = m->min_size;
}
@@ -3032,11 +3065,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
m->keep_free = DEFAULT_KEEP_FREE;
}
- log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s",
- format_bytes(a, sizeof(a), m->max_use),
- format_bytes(b, sizeof(b), m->max_size),
- format_bytes(c, sizeof(c), m->min_size),
- format_bytes(d, sizeof(d), m->keep_free));
+ if (m->n_max_files == (uint64_t) -1)
+ m->n_max_files = DEFAULT_N_MAX_FILES;
+
+ log_debug("Fixed min_use=%s max_use=%s max_size=%s min_size=%s keep_free=%s n_max_files=%" PRIu64,
+ format_bytes(a, sizeof(a), m->min_use),
+ format_bytes(b, sizeof(b), m->max_use),
+ format_bytes(c, sizeof(c), m->max_size),
+ format_bytes(d, sizeof(d), m->min_size),
+ format_bytes(e, sizeof(e), m->keep_free),
+ m->n_max_files);
}
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) {
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index e92b75eabe..898d12d992 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -36,11 +36,13 @@
#include "hashmap.h"
typedef struct JournalMetrics {
- uint64_t max_use;
- uint64_t use;
- uint64_t max_size;
- uint64_t min_size;
- uint64_t keep_free;
+ /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */
+ uint64_t max_size; /* how large journal files grow at max */
+ uint64_t min_size; /* how large journal files grow at least */
+ uint64_t max_use; /* how much disk space to use in total at max, keep_free permitting */
+ uint64_t min_use; /* how much disk space to use in total at least, even if keep_free says not to */
+ uint64_t keep_free; /* how much to keep free on disk */
+ uint64_t n_max_files; /* how many files to keep around at max */
} JournalMetrics;
typedef enum direction {
@@ -136,7 +138,7 @@ int journal_file_open(
JournalFile **ret);
int journal_file_set_offline(JournalFile *f);
-void journal_file_close(JournalFile *j);
+JournalFile* journal_file_close(JournalFile *j);
int journal_file_open_reliably(
const char *fname,
@@ -223,6 +225,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal);
void journal_file_post_change(JournalFile *f);
+void journal_reset_metrics(JournalMetrics *m);
void journal_default_metrics(JournalMetrics *m, int fd);
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to);
@@ -232,3 +235,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec);
int journal_file_map_data_hash_table(JournalFile *f);
int journal_file_map_field_hash_table(JournalFile *f);
+
+static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) {
+ assert(f);
+ return f->compress_xz || f->compress_lz4;
+}
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index b51ecdb600..06847402e0 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -25,14 +25,14 @@
#include <inttypes.h>
#include <stdbool.h>
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
+#include "sd-journal.h"
+#include "hashmap.h"
#include "journal-def.h"
+#include "journal-file.h"
#include "list.h"
-#include "hashmap.h"
#include "set.h"
-#include "journal-file.h"
-#include "sd-journal.h"
typedef struct Match Match;
typedef struct Location Location;
@@ -121,7 +121,7 @@ struct sd_journal {
Hashmap *directories_by_path;
Hashmap *directories_by_wd;
- Set *errors;
+ Hashmap *errors;
};
char *journal_make_match_string(sd_journal *j);
diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h
index 3ff6a3ad4a..7d14e8754b 100644
--- a/src/journal/journal-qrcode.h
+++ b/src/journal/journal-qrcode.h
@@ -21,8 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
#include <stdio.h>
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine);
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index 1e3a463504..fa5dee73c3 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -19,20 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <sys/un.h>
#include <errno.h>
-#include <stddef.h>
-#include <unistd.h>
#include <fcntl.h>
#include <printf.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
#define SD_JOURNAL_SUPPRESS_LOCATION
#include "sd-journal.h"
-#include "util.h"
-#include "socket-util.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "io-util.h"
#include "memfd-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
@@ -212,11 +219,6 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
};
ssize_t k;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control;
- struct cmsghdr *cmsg;
bool have_syslog_identifier = false;
bool seal = true;
@@ -335,26 +337,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
return r;
}
- mh.msg_iov = NULL;
- mh.msg_iovlen = 0;
-
- zero(control);
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- k = sendmsg(fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return -errno;
-
- return 0;
+ return send_one_fd(fd, buffer_fd, 0);
}
static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 17499bbc30..4b5fc76eb1 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -23,20 +23,27 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "journal-def.h"
#include "journal-file.h"
#include "journal-vacuum.h"
-#include "sd-id128.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "util.h"
+#include "xattr-util.h"
struct vacuum_info {
uint64_t usage;
char *filename;
uint64_t realtime;
+
sd_id128_t seqnum_id;
uint64_t seqnum;
-
bool have_seqnum;
};
@@ -67,19 +74,18 @@ static int vacuum_compare(const void *_a, const void *_b) {
}
static void patch_realtime(
- const char *dir,
+ int fd,
const char *fn,
const struct stat *st,
unsigned long long *realtime) {
- _cleanup_free_ char *path = NULL;
usec_t x, crtime = 0;
/* The timestamp was determined by the file name, but let's
* see if the file might actually be older than the file name
* suggested... */
- assert(dir);
+ assert(fd >= 0);
assert(fn);
assert(st);
assert(realtime);
@@ -101,14 +107,7 @@ static void patch_realtime(
* unfortunately there's currently no sane API to query
* it. Hence let's implement this manually... */
- /* Unfortunately there is is not fgetxattrat(), so we need to
- * go via path here. :-( */
-
- path = strjoin(dir, "/", fn, NULL);
- if (!path)
- return;
-
- if (path_getcrtime(path, &crtime) >= 0) {
+ if (fd_getcrtime_at(fd, fn, &crtime, 0) >= 0) {
if (crtime < *realtime)
*realtime = crtime;
}
@@ -120,9 +119,13 @@ static int journal_file_empty(int dir_fd, const char *name) {
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;
+ fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK|O_NOATIME);
+ if (fd < 0) {
+ /* Maybe failed due to O_NOATIME and lack of privileges? */
+ fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+ }
if (fstat(fd, &st) < 0)
return -errno;
@@ -144,22 +147,24 @@ static int journal_file_empty(int dir_fd, const char *name) {
int journal_directory_vacuum(
const char *directory,
uint64_t max_use,
+ uint64_t n_max_files,
usec_t max_retention_usec,
usec_t *oldest_usec,
bool verbose) {
_cleanup_closedir_ DIR *d = NULL;
- int r = 0;
struct vacuum_info *list = NULL;
- unsigned n_list = 0, i;
+ unsigned n_list = 0, i, n_active_files = 0;
size_t n_allocated = 0;
uint64_t sum = 0, freed = 0;
usec_t retention_limit = 0;
char sbytes[FORMAT_BYTES_MAX];
+ struct dirent *de;
+ int r;
assert(directory);
- if (max_use <= 0 && max_retention_usec <= 0)
+ if (max_use <= 0 && max_retention_usec <= 0 && n_max_files <= 0)
return 0;
if (max_retention_usec > 0) {
@@ -174,27 +179,20 @@ int journal_directory_vacuum(
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
- size_t q;
- struct stat st;
- char *p;
+ FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
+
unsigned long long seqnum = 0, realtime;
+ _cleanup_free_ char *p = NULL;
sd_id128_t seqnum_id;
bool have_seqnum;
+ uint64_t size;
+ struct stat st;
+ size_t q;
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- goto finish;
- }
-
- if (!de)
- break;
-
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ log_debug_errno(errno, "Failed to stat file %s while vacuuming, ignoring: %m", de->d_name);
continue;
+ }
if (!S_ISREG(st.st_mode))
continue;
@@ -203,15 +201,20 @@ int journal_directory_vacuum(
if (endswith(de->d_name, ".journal")) {
- /* Vacuum archived files */
+ /* Vacuum archived files. Active files are
+ * left around */
- if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
+ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) {
+ n_active_files++;
continue;
+ }
if (de->d_name[q-8-16-1] != '-' ||
de->d_name[q-8-16-1-16-1] != '-' ||
- de->d_name[q-8-16-1-16-1-32-1] != '@')
+ de->d_name[q-8-16-1-16-1-32-1] != '@') {
+ n_active_files++;
continue;
+ }
p = strdup(de->d_name);
if (!p) {
@@ -221,12 +224,12 @@ int journal_directory_vacuum(
de->d_name[q-8-16-1-16-1] = 0;
if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
- free(p);
+ n_active_files++;
continue;
}
if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
- free(p);
+ n_active_files++;
continue;
}
@@ -237,12 +240,16 @@ int journal_directory_vacuum(
/* Vacuum corrupted files */
- if (q < 1 + 16 + 1 + 16 + 8 + 1)
+ if (q < 1 + 16 + 1 + 16 + 8 + 1) {
+ n_active_files ++;
continue;
+ }
if (de->d_name[q-1-8-16-1] != '-' ||
- de->d_name[q-1-8-16-1-16-1] != '@')
+ de->d_name[q-1-8-16-1-16-1] != '@') {
+ n_active_files ++;
continue;
+ }
p = strdup(de->d_name);
if (!p) {
@@ -251,55 +258,68 @@ int journal_directory_vacuum(
}
if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
- free(p);
+ n_active_files ++;
continue;
}
have_seqnum = false;
- } else
- /* We do not vacuum active files or unknown files! */
+ } else {
+ /* We do not vacuum unknown files! */
+ log_debug("Not vacuuming unknown file %s.", de->d_name);
continue;
+ }
- if (journal_file_empty(dirfd(d), p)) {
- /* Always vacuum empty non-online files. */
+ size = 512UL * (uint64_t) st.st_blocks;
- uint64_t size = 512UL * (uint64_t) st.st_blocks;
+ r = journal_file_empty(dirfd(d), p);
+ if (r < 0) {
+ log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p);
+ continue;
+ }
+ if (r > 0) {
+ /* Always vacuum empty non-online files. */
if (unlinkat(dirfd(d), p, 0) >= 0) {
- log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), 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_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p);
- free(p);
continue;
}
- patch_realtime(directory, p, &st, &realtime);
+ patch_realtime(dirfd(d), p, &st, &realtime);
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;
+ list[n_list].usage = size;
list[n_list].seqnum = seqnum;
list[n_list].realtime = realtime;
list[n_list].seqnum_id = seqnum_id;
list[n_list].have_seqnum = have_seqnum;
-
- sum += list[n_list].usage;
-
n_list ++;
+
+ p = NULL;
+ sum += size;
}
qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
for (i = 0; i < n_list; i++) {
+ unsigned left;
+
+ left = n_active_files + n_list - i;
+
if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
- (max_use <= 0 || sum <= max_use))
+ (max_use <= 0 || sum <= max_use) &&
+ (n_max_files <= 0 || left <= n_max_files))
break;
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
@@ -318,6 +338,8 @@ int journal_directory_vacuum(
if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
*oldest_usec = list[i].realtime;
+ r = 0;
+
finish:
for (i = 0; i < n_list; i++)
free(list[i].filename);
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
index c45cc31d0e..49ab90af91 100644
--- a/src/journal/journal-vacuum.h
+++ b/src/journal/journal-vacuum.h
@@ -21,5 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
+#include <stdbool.h>
-int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
+#include "time-util.h"
+
+int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t n_max_files, usec_t max_retention_usec, usec_t *oldest_usec, bool verbose);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 32d59c716f..3676cb8788 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -24,15 +24,18 @@
#include <fcntl.h>
#include <stddef.h>
-#include "util.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "compress.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
-#include "journal-authenticate.h"
#include "journal-verify.h"
#include "lookup3.h"
-#include "compress.h"
+#include "macro.h"
#include "terminal-util.h"
+#include "util.h"
static void draw_progress(uint64_t p, usec_t *last_usec) {
unsigned n, i, j, k;
@@ -839,19 +842,19 @@ int journal_file_verify(
data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
- r = log_error_errno(errno, "Failed to create data file: %m");
+ r = log_error_errno(data_fd, "Failed to create data file: %m");
goto fail;
}
entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
- r = log_error_errno(errno, "Failed to create entry file: %m");
+ r = log_error_errno(entry_fd, "Failed to create entry file: %m");
goto fail;
}
entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
- r = log_error_errno(errno,
+ r = log_error_errno(entry_array_fd,
"Failed to create entry array file: %m");
goto fail;
}
@@ -897,7 +900,7 @@ int journal_file_verify(
r = journal_file_object_verify(f, p, o);
if (r < 0) {
- error(p, "Envalid object contents: %s", strerror(-r));
+ error(p, "Invalid object contents: %s", strerror(-r));
goto fail;
}
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index b38b151485..277adba904 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -19,48 +19,58 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <locale.h>
+#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
-#include <errno.h>
+#include <getopt.h>
+#include <linux/fs.h>
+#include <locale.h>
+#include <poll.h>
+#include <signal.h>
#include <stddef.h>
-#include <string.h>
#include <stdio.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <getopt.h>
-#include <signal.h>
-#include <poll.h>
-#include <sys/stat.h>
+#include <string.h>
#include <sys/inotify.h>
-#include <linux/fs.h>
+#include <sys/stat.h>
+#include <unistd.h>
-#include "sd-journal.h"
#include "sd-bus.h"
-#include "log.h"
-#include "logs-show.h"
-#include "util.h"
+#include "sd-journal.h"
+
#include "acl-util.h"
-#include "path-util.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "catalog.h"
+#include "chattr-util.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "build.h"
-#include "pager.h"
-#include "strv.h"
-#include "set.h"
-#include "sigbus.h"
-#include "journal-internal.h"
+#include "fs-util.h"
+#include "fsprg.h"
+#include "glob-util.h"
+#include "hostname-util.h"
+#include "io-util.h"
#include "journal-def.h"
-#include "journal-verify.h"
+#include "journal-internal.h"
#include "journal-qrcode.h"
#include "journal-vacuum.h"
-#include "fsprg.h"
-#include "unit-name.h"
-#include "catalog.h"
+#include "journal-verify.h"
+#include "locale-util.h"
+#include "log.h"
+#include "logs-show.h"
#include "mkdir.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "rlimit-util.h"
+#include "set.h"
+#include "sigbus.h"
+#include "strv.h"
+#include "syslog-util.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "unit-name.h"
+#include "user-util.h"
#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
@@ -105,10 +115,11 @@ static const char *arg_field = NULL;
static bool arg_catalog = false;
static bool arg_reverse = false;
static int arg_journal_type = 0;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
static const char *arg_machine = NULL;
-static uint64_t arg_vacuum_size = (uint64_t) -1;
-static usec_t arg_vacuum_time = USEC_INFINITY;
+static uint64_t arg_vacuum_size = 0;
+static uint64_t arg_vacuum_n_files = 0;
+static usec_t arg_vacuum_time = 0;
static enum {
ACTION_SHOW,
@@ -122,6 +133,7 @@ static enum {
ACTION_UPDATE_CATALOG,
ACTION_LIST_BOOTS,
ACTION_FLUSH,
+ ACTION_ROTATE,
ACTION_VACUUM,
} arg_action = ACTION_SHOW;
@@ -193,8 +205,8 @@ static void help(void) {
" --system Show the system journal\n"
" --user Show the user journal for the current user\n"
" -M --machine=CONTAINER Operate on local container\n"
- " --since=DATE Show entries not older than the specified date\n"
- " --until=DATE Show entries not newer than the specified date\n"
+ " -S --since=DATE Show entries not older than the specified date\n"
+ " -U --until=DATE Show entries not newer than the specified date\n"
" -c --cursor=CURSOR Show entries starting at the specified cursor\n"
" --after-cursor=CURSOR Show entries after the specified cursor\n"
" --show-cursor Print the cursor after all the entries\n"
@@ -217,7 +229,7 @@ static void help(void) {
" -x --catalog Add message explanations where available\n"
" --no-full Ellipsize fields\n"
" -a --all Show all fields, including long and unprintable\n"
- " -q --quiet Do not show privilege warning\n"
+ " -q --quiet Do not show info messages and privilege warning\n"
" --no-pager Do not pipe output into a pager\n"
" -m --merge Show entries from all available journals\n"
" -D --directory=PATH Show journal files from directory\n"
@@ -235,8 +247,10 @@ static void help(void) {
" --new-id128 Generate a new 128-bit ID\n"
" --disk-usage Show total disk usage of all journal files\n"
" --vacuum-size=BYTES Reduce disk usage below specified size\n"
- " --vacuum-time=TIME Remove journal files older than specified date\n"
+ " --vacuum-files=INT Leave only the specified number of journal files\n"
+ " --vacuum-time=TIME Remove journal files older than specified time\n"
" --flush Flush all journal data from /run into /var\n"
+ " --rotate Request immediate rotation of the journal files\n"
" --header Show journal header information\n"
" --list-catalog Show all message IDs in the catalog\n"
" --dump-catalog Show entries in the message catalog\n"
@@ -267,8 +281,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERIFY,
ARG_VERIFY_KEY,
ARG_DISK_USAGE,
- ARG_SINCE,
- ARG_UNTIL,
ARG_AFTER_CURSOR,
ARG_SHOW_CURSOR,
ARG_USER_UNIT,
@@ -278,7 +290,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_UTC,
ARG_FLUSH,
+ ARG_ROTATE,
ARG_VACUUM_SIZE,
+ ARG_VACUUM_FILES,
ARG_VACUUM_TIME,
};
@@ -318,8 +332,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "cursor", required_argument, NULL, 'c' },
{ "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
{ "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
- { "since", required_argument, NULL, ARG_SINCE },
- { "until", required_argument, NULL, ARG_UNTIL },
+ { "since", required_argument, NULL, 'S' },
+ { "until", required_argument, NULL, 'U' },
{ "unit", required_argument, NULL, 'u' },
{ "user-unit", required_argument, NULL, ARG_USER_UNIT },
{ "field", required_argument, NULL, 'F' },
@@ -331,7 +345,9 @@ 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 },
+ { "rotate", no_argument, NULL, ARG_ROTATE },
{ "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
+ { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{}
};
@@ -341,7 +357,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0)
switch (c) {
@@ -350,9 +366,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -502,7 +516,9 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- arg_root = optarg;
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case 'c':
@@ -539,6 +555,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_VACUUM;
break;
+ case ARG_VACUUM_FILES:
+ r = safe_atou64(optarg, &arg_vacuum_n_files);
+ if (r < 0) {
+ log_error("Failed to parse vacuum files: %s", optarg);
+ return r;
+ }
+
+ arg_action = ACTION_VACUUM;
+ break;
+
case ARG_VACUUM_TIME:
r = parse_sec(optarg, &arg_vacuum_time);
if (r < 0) {
@@ -631,7 +657,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
- case ARG_SINCE:
+ case 'S':
r = parse_timestamp(optarg, &arg_since);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
@@ -640,7 +666,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_since_set = true;
break;
- case ARG_UNTIL:
+ case 'U':
r = parse_timestamp(optarg, &arg_until);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
@@ -699,6 +725,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_FLUSH;
break;
+ case ARG_ROTATE:
+ arg_action = ACTION_ROTATE;
+ break;
+
case '?':
return -EINVAL;
@@ -729,7 +759,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_action != ACTION_SHOW && optind < argc) {
+ if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
log_error("Extraneous arguments starting with '%s'", argv[optind]);
return -EINVAL;
}
@@ -1453,7 +1483,7 @@ static int setup_keys(void) {
safe_close(fd);
fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- r = log_error_errno(errno, "Failed to open %s: %m", k);
+ r = log_error_errno(fd, "Failed to open %s: %m", k);
goto finish;
}
@@ -1461,7 +1491,7 @@ static int setup_keys(void) {
* writing and in-place updating */
r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
if (r < 0)
- log_warning_errno(errno, "Failed to set file attributes: %m");
+ log_warning_errno(r, "Failed to set file attributes: %m");
zero(h);
memcpy(h.signature, "KSHHRHLP", 8);
@@ -1580,7 +1610,7 @@ static int verify(sd_journal *j) {
/* If the key was invalid give up right-away. */
return k;
} else if (k < 0) {
- log_warning("FAIL: %s (%s)", f->path, strerror(-k));
+ log_warning_errno(k, "FAIL: %s (%m)", f->path);
r = k;
} else {
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
@@ -1678,36 +1708,50 @@ static int access_check_var_log_journal(sd_journal *j) {
static int access_check(sd_journal *j) {
Iterator it;
void *code;
+ char *path;
int r = 0;
assert(j);
- if (set_isempty(j->errors)) {
+ if (hashmap_isempty(j->errors)) {
if (ordered_hashmap_isempty(j->files))
log_notice("No journal files were found.");
return 0;
}
- if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
+ if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) {
(void) access_check_var_log_journal(j);
if (ordered_hashmap_isempty(j->files))
r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
}
- SET_FOREACH(code, j->errors, it) {
+ HASHMAP_FOREACH_KEY(path, code, j->errors, it) {
int err;
- err = -PTR_TO_INT(code);
- assert(err > 0);
+ err = abs(PTR_TO_INT(code));
- if (err == EACCES)
+ switch (err) {
+ case EACCES:
continue;
- log_warning_errno(err, "Error was encountered while opening journal files: %m");
- if (r == 0)
- r = -err;
+ case ENODATA:
+ log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
+ break;
+
+ case EPROTONOSUPPORT:
+ log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
+ break;
+
+ case EBADMSG:
+ log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
+ break;
+
+ default:
+ log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+ break;
+ }
}
return r;
@@ -1725,7 +1769,7 @@ 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);
+ r = bus_connect_system_systemd(&bus);
if (r < 0)
return log_error_errno(r, "Failed to get D-Bus connection: %m");
@@ -1772,6 +1816,30 @@ static int flush_to_var(void) {
return 0;
}
+static int rotate(void) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ int r;
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "KillUnit",
+ &error,
+ NULL,
+ "ssi", "systemd-journald.service", "main", SIGUSR2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r;
_cleanup_journal_close_ sd_journal *j = NULL;
@@ -1807,6 +1875,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (arg_action == ACTION_ROTATE) {
+ r = rotate();
+ goto finish;
+ }
+
if (arg_action == ACTION_SETUP_KEYS) {
r = setup_keys();
goto finish;
@@ -1831,6 +1904,7 @@ int main(int argc, char *argv[]) {
} else {
bool oneline = arg_action == ACTION_LIST_CATALOG;
+ pager_open_if_enabled();
if (optind < argc)
r = catalog_list_items(stdout, database,
oneline, argv + optind);
@@ -1895,9 +1969,9 @@ int main(int argc, char *argv[]) {
if (d->is_root)
continue;
- q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
+ q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true);
if (q < 0) {
- log_error_errno(q, "Failed to vacuum: %m");
+ log_error_errno(q, "Failed to vacuum %s: %m", d->path);
r = q;
}
}
@@ -2200,5 +2274,7 @@ finish:
strv_free(arg_system_units);
strv_free(arg_user_units);
+ free(arg_root);
+
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c
index fe8ae194c9..3c13fe0d67 100644
--- a/src/journal/journald-audit.c
+++ b/src/journal/journald-audit.c
@@ -19,9 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "missing.h"
-#include "journald-audit.h"
+#include "alloc-util.h"
#include "audit-type.h"
+#include "fd-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
+#include "journald-audit.h"
+#include "missing.h"
+#include "string-util.h"
typedef struct MapField {
const char *audit_field;
diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c
index 307bdc3949..89f3d4b42f 100644
--- a/src/journal/journald-console.c
+++ b/src/journal/journald-console.c
@@ -23,11 +23,16 @@
#include <fcntl.h>
#include <sys/socket.h>
+#include "alloc-util.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "journald-server.h"
-#include "journald-console.h"
#include "formats-util.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-server.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "stdio-util.h"
#include "terminal-util.h"
static bool prefix_timestamp(void) {
@@ -101,7 +106,7 @@ void server_forward_console(
fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0) {
- log_debug_errno(errno, "Failed to open %s for logging: %m", tty);
+ log_debug_errno(fd, "Failed to open %s for logging: %m", tty);
return;
}
diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf
index bf7c773009..c154610c54 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/journal/journald-gperf.gperf
@@ -24,9 +24,11 @@ Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_li
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size)
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.keep_free)
+Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Server, system_metrics.n_max_files)
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_use)
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_size)
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.keep_free)
+Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Server, runtime_metrics.n_max_files)
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec)
Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec)
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 51fe3aa50a..e048e04716 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -19,20 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <sys/epoll.h>
#include <fcntl.h>
+#include <sys/epoll.h>
#include <sys/mman.h>
#include <sys/socket.h>
+#include <unistd.h>
-#include "systemd/sd-messages.h"
-#include <libudev.h>
+#include "libudev.h"
+#include "sd-messages.h"
-#include "journald-server.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
#include "journald-kmsg.h"
+#include "journald-server.h"
#include "journald-syslog.h"
-#include "formats-util.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
void server_forward_kmsg(
Server *s,
@@ -341,8 +347,7 @@ static int server_read_dev_kmsg(Server *s) {
if (errno == EAGAIN || errno == EINTR || errno == EPIPE)
return 0;
- log_error_errno(errno, "Failed to read from kernel: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to read from kernel: %m");
}
dev_kmsg_record(s, buffer, l);
@@ -436,6 +441,7 @@ fail:
int server_open_kernel_seqnum(Server *s) {
_cleanup_close_ int fd;
uint64_t *p;
+ int r;
assert(s);
@@ -449,8 +455,9 @@ int server_open_kernel_seqnum(Server *s) {
return 0;
}
- if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) {
- log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m");
+ r = posix_fallocate(fd, 0, sizeof(uint64_t));
+ if (r != 0) {
+ log_error_errno(r, "Failed to allocate sequential number file, ignoring: %m");
return 0;
}
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index 3e8a7a05f6..1e3774dafb 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -19,21 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stddef.h>
#include <sys/epoll.h>
#include <sys/mman.h>
+#include <unistd.h>
-#include "socket-util.h"
-#include "path-util.h"
-#include "selinux-util.h"
-#include "journald-server.h"
-#include "journald-native.h"
-#include "journald-kmsg.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "io-util.h"
#include "journald-console.h"
+#include "journald-kmsg.h"
+#include "journald-native.h"
+#include "journald-server.h"
#include "journald-syslog.h"
#include "journald-wall.h"
#include "memfd-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "string-util.h"
bool valid_user_field(const char *p, size_t l, bool allow_protected) {
const char *a;
@@ -338,7 +344,7 @@ void server_process_native_file(
r = readlink_malloc(sl, &k);
if (r < 0) {
- log_error_errno(errno, "readlink(%s) failed: %m", sl);
+ log_error_errno(r, "readlink(%s) failed: %m", sl);
return;
}
@@ -407,7 +413,7 @@ void server_process_native_file(
n = pread(fd, p, st.st_size, 0);
if (n < 0)
- log_error_errno(n, "Failed to read file, ignoring: %m");
+ log_error_errno(errno, "Failed to read file, ignoring: %m");
else if (n > 0)
server_process_native_message(s, p, n, ucred, tv, label, label_len);
}
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index 6f83035a4e..434ddc8ac9 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -19,14 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
+#include <string.h>
-#include "journald-rate-limit.h"
-#include "list.h"
-#include "util.h"
+#include "alloc-util.h"
#include "hashmap.h"
+#include "list.h"
#include "random-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "journald-rate-limit.h"
#define POOLS_MAX 5
#define BUCKETS_MAX 127
@@ -57,7 +59,7 @@ struct JournalRateLimitGroup {
char *id;
JournalRateLimitPool pools[POOLS_MAX];
- unsigned long hash;
+ uint64_t hash;
LIST_FIELDS(JournalRateLimitGroup, bucket);
LIST_FIELDS(JournalRateLimitGroup, lru);
@@ -145,6 +147,7 @@ static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) {
static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) {
JournalRateLimitGroup *g;
+ struct siphash state;
assert(r);
assert(id);
@@ -157,7 +160,9 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r,
if (!g->id)
goto fail;
- g->hash = string_hash_func(g->id, r->hash_key);
+ siphash24_init(&state, r->hash_key);
+ string_hash_func(g->id, &state);
+ siphash24_finalize((uint8_t*)&g->hash, &state);
journal_rate_limit_vacuum(r, ts);
@@ -204,9 +209,10 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) {
}
int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) {
- unsigned long h;
+ uint64_t h;
JournalRateLimitGroup *g;
JournalRateLimitPool *p;
+ struct siphash state;
unsigned burst;
usec_t ts;
@@ -222,7 +228,9 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
ts = now(CLOCK_MONOTONIC);
- h = string_hash_func(id, r->hash_key);
+ siphash24_init(&state, r->hash_key);
+ string_hash_func(id, &state);
+ siphash24_finalize((uint8_t*)&h, &state);
g = r->buckets[h % BUCKETS_MAX];
LIST_FOREACH(bucket, g, g)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index fa2e9b9825..7a70dcbc57 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -19,45 +19,55 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/signalfd.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <sys/statvfs.h>
-#include <sys/mman.h>
-
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/signalfd.h>
+#include <sys/statvfs.h>
+#include <linux/sockios.h>
-#include <libudev.h>
-
+#include "libudev.h"
+#include "sd-daemon.h"
#include "sd-journal.h"
#include "sd-messages.h"
-#include "sd-daemon.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "hashmap.h"
-#include "journal-file.h"
-#include "socket-util.h"
+
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "audit-util.h"
#include "cgroup-util.h"
-#include "missing.h"
#include "conf-parser.h"
-#include "selinux-util.h"
-#include "acl-util.h"
+#include "dirent-util.h"
+#include "extract-word.h"
+#include "fd-util.h"
#include "formats-util.h"
-#include "process-util.h"
+#include "fs-util.h"
+#include "hashmap.h"
#include "hostname-util.h"
-#include "signal-util.h"
+#include "io-util.h"
+#include "journal-authenticate.h"
+#include "journal-file.h"
#include "journal-internal.h"
#include "journal-vacuum.h"
-#include "journal-authenticate.h"
-#include "journald-rate-limit.h"
+#include "journald-audit.h"
#include "journald-kmsg.h"
-#include "journald-syslog.h"
-#include "journald-stream.h"
#include "journald-native.h"
-#include "journald-audit.h"
+#include "journald-rate-limit.h"
#include "journald-server.h"
+#include "journald-stream.h"
+#include "journald-syslog.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "rm-rf.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
#define USER_JOURNALS_MAX 1024
@@ -66,88 +76,63 @@
#define DEFAULT_RATE_LIMIT_BURST 1000
#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
-#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
+#define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
-static const char* const storage_table[_STORAGE_MAX] = {
- [STORAGE_AUTO] = "auto",
- [STORAGE_VOLATILE] = "volatile",
- [STORAGE_PERSISTENT] = "persistent",
- [STORAGE_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
-
-static const char* const split_mode_table[_SPLIT_MAX] = {
- [SPLIT_LOGIN] = "login",
- [SPLIT_UID] = "uid",
- [SPLIT_NONE] = "none",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
+#define NOTIFY_SNDBUF_SIZE (8*1024*1024)
-static uint64_t available_space(Server *s, bool verbose) {
- char ids[33];
- _cleanup_free_ char *p = NULL;
- sd_id128_t machine;
- struct statvfs ss;
- uint64_t sum = 0, ss_avail = 0, avail = 0;
- int r;
+static int determine_space_for(
+ Server *s,
+ JournalMetrics *metrics,
+ const char *path,
+ const char *name,
+ bool verbose,
+ bool patch_min_use,
+ uint64_t *available,
+ uint64_t *limit) {
+
+ uint64_t sum = 0, ss_avail, avail;
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ struct statvfs ss;
+ const char *p;
usec_t ts;
- const char *f;
- JournalMetrics *m;
-
- ts = now(CLOCK_MONOTONIC);
- if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts
- && !verbose)
- return s->cached_available_space;
+ assert(s);
+ assert(metrics);
+ assert(path);
+ assert(name);
- r = sd_id128_get_machine(&machine);
- if (r < 0)
- return 0;
+ ts = now(CLOCK_MONOTONIC);
- if (s->system_journal) {
- f = "/var/log/journal/";
- m = &s->system_metrics;
- } else {
- f = "/run/log/journal/";
- m = &s->runtime_metrics;
- }
+ if (!verbose && s->cached_space_timestamp + RECHECK_SPACE_USEC > ts) {
- assert(m);
+ if (available)
+ *available = s->cached_space_available;
+ if (limit)
+ *limit = s->cached_space_limit;
- p = strappend(f, sd_id128_to_string(machine, ids));
- if (!p)
return 0;
+ }
+ p = strjoina(path, SERVER_MACHINE_ID(s));
d = opendir(p);
if (!d)
- return 0;
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open %s: %m", p);
if (fstatvfs(dirfd(d), &ss) < 0)
- return 0;
+ return log_error_errno(errno, "Failed to fstatvfs(%s): %m", p);
- for (;;) {
+ FOREACH_DIRENT_ALL(de, d, break) {
struct stat st;
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return 0;
-
- if (!de)
- break;
if (!endswith(de->d_name, ".journal") &&
!endswith(de->d_name, ".journal~"))
continue;
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", p, de->d_name);
continue;
+ }
if (!S_ISREG(st.st_mode))
continue;
@@ -155,45 +140,72 @@ static uint64_t available_space(Server *s, bool verbose) {
sum += (uint64_t) st.st_blocks * 512UL;
}
- ss_avail = ss.f_bsize * ss.f_bavail;
-
- /* If we reached a high mark, we will always allow this much
- * again, unless usage goes above max_use. This watermark
- * value is cached so that we don't give up space on pressure,
- * but hover below the maximum usage. */
+ /* If request, then let's bump the min_use limit to the
+ * current usage on disk. We do this when starting up and
+ * first opening the journal files. This way sudden spikes in
+ * disk usage will not cause journald to vacuum files without
+ * bounds. Note that this means that only a restart of
+ * journald will make it reset this value. */
- if (m->use < sum)
- m->use = sum;
+ if (patch_min_use)
+ metrics->min_use = MAX(metrics->min_use, sum);
- avail = LESS_BY(ss_avail, m->keep_free);
+ ss_avail = ss.f_bsize * ss.f_bavail;
+ avail = LESS_BY(ss_avail, metrics->keep_free);
- s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
- s->cached_available_space_timestamp = ts;
+ s->cached_space_limit = MIN(MAX(sum + avail, metrics->min_use), metrics->max_use);
+ s->cached_space_available = LESS_BY(s->cached_space_limit, sum);
+ s->cached_space_timestamp = ts;
if (verbose) {
char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
- fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
+ fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX];
server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
- "%s is currently using %s.\n"
+ "%s (%s) is currently using %s.\n"
"Maximum allowed usage is set to %s.\n"
"Leaving at least %s free (of currently available %s of space).\n"
- "Enforced usage limit is thus %s.",
- s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)",
+ "Enforced usage limit is thus %s, of which %s are still available.",
+ name, path,
format_bytes(fb1, sizeof(fb1), sum),
- format_bytes(fb2, sizeof(fb2), m->max_use),
- format_bytes(fb3, sizeof(fb3), m->keep_free),
+ format_bytes(fb2, sizeof(fb2), metrics->max_use),
+ format_bytes(fb3, sizeof(fb3), metrics->keep_free),
format_bytes(fb4, sizeof(fb4), ss_avail),
- format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
+ format_bytes(fb5, sizeof(fb5), s->cached_space_limit),
+ format_bytes(fb6, sizeof(fb6), s->cached_space_available));
}
- return s->cached_available_space;
+ if (available)
+ *available = s->cached_space_available;
+ if (limit)
+ *limit = s->cached_space_limit;
+
+ return 1;
+}
+
+static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t *available, uint64_t *limit) {
+ JournalMetrics *metrics;
+ const char *path, *name;
+
+ assert(s);
+
+ if (s->system_journal) {
+ path = "/var/log/journal/";
+ metrics = &s->system_metrics;
+ name = "System journal";
+ } else {
+ path = "/run/log/journal/";
+ metrics = &s->runtime_metrics;
+ name = "Runtime journal";
+ }
+
+ return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit);
}
void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
int r;
#ifdef HAVE_ACL
- acl_t acl;
+ _cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
acl_permset_t permset;
#endif
@@ -202,7 +214,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
r = fchmod(f->fd, 0640);
if (r < 0)
- log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path);
#ifdef HAVE_ACL
if (uid <= SYSTEM_UID_MAX)
@@ -221,24 +233,27 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
acl_set_tag_type(entry, ACL_USER) < 0 ||
acl_set_qualifier(entry, &uid) < 0) {
log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
- goto finish;
+ return;
}
}
/* We do not recalculate the mask unconditionally here,
* so that the fchmod() mask above stays intact. */
if (acl_get_permset(entry, &permset) < 0 ||
- acl_add_perm(permset, ACL_READ) < 0 ||
- calc_acl_mask_if_needed(&acl) < 0) {
+ acl_add_perm(permset, ACL_READ) < 0) {
log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
- goto finish;
+ return;
+ }
+
+ r = calc_acl_mask_if_needed(&acl);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path);
+ return;
}
if (acl_set_fd(f->fd, acl) < 0)
log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
-finish:
- acl_free(acl);
#endif
}
@@ -328,8 +343,8 @@ void server_rotate(Server *s) {
log_debug("Rotating...");
- do_rotate(s, &s->runtime_journal, "runtime", false, 0);
- do_rotate(s, &s->system_journal, "system", s->seal, 0);
+ (void) do_rotate(s, &s->runtime_journal, "runtime", false, 0);
+ (void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
@@ -350,13 +365,13 @@ void server_sync(Server *s) {
if (s->system_journal) {
r = journal_file_set_offline(s->system_journal);
if (r < 0)
- log_error_errno(r, "Failed to sync system journal: %m");
+ log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
}
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = journal_file_set_offline(f);
if (r < 0)
- log_error_errno(r, "Failed to sync user journal: %m");
+ log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
}
if (s->sync_event_source) {
@@ -370,43 +385,50 @@ void server_sync(Server *s) {
static void do_vacuum(
Server *s,
- const char *id,
JournalFile *f,
- const char* path,
- JournalMetrics *metrics) {
+ JournalMetrics *metrics,
+ const char *path,
+ const char *name,
+ bool verbose,
+ bool patch_min_use) {
const char *p;
+ uint64_t limit;
int r;
+ assert(s);
+ assert(metrics);
+ assert(path);
+ assert(name);
+
if (!f)
return;
- p = strjoina(path, id);
- r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
+ p = strjoina(path, SERVER_MACHINE_ID(s));
+
+ limit = metrics->max_use;
+ (void) determine_space_for(s, metrics, path, name, verbose, patch_min_use, NULL, &limit);
+
+ r = journal_directory_vacuum(p, limit, metrics->n_max_files, s->max_retention_usec, &s->oldest_file_usec, verbose);
if (r < 0 && r != -ENOENT)
- log_error_errno(r, "Failed to vacuum %s: %m", p);
+ log_warning_errno(r, "Failed to vacuum %s, ignoring: %m", p);
}
-void server_vacuum(Server *s) {
- char ids[33];
- sd_id128_t machine;
- int r;
+int server_vacuum(Server *s, bool verbose, bool patch_min_use) {
+ assert(s);
log_debug("Vacuuming...");
s->oldest_file_usec = 0;
- r = sd_id128_get_machine(&machine);
- if (r < 0) {
- log_error_errno(r, "Failed to get machine ID: %m");
- return;
- }
- sd_id128_to_string(machine, ids);
+ do_vacuum(s, s->system_journal, &s->system_metrics, "/var/log/journal/", "System journal", verbose, patch_min_use);
+ do_vacuum(s, s->runtime_journal, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", verbose, patch_min_use);
- do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics);
- do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics);
+ s->cached_space_limit = 0;
+ s->cached_space_available = 0;
+ s->cached_space_timestamp = 0;
- s->cached_available_space_timestamp = 0;
+ return 0;
}
static void server_cache_machine_id(Server *s) {
@@ -504,7 +526,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
if (journal_file_rotate_suggested(f, s->max_file_usec)) {
log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
vacuumed = true;
f = find_journal(s, uid);
@@ -524,7 +546,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
}
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
f = find_journal(s, uid);
if (!f)
@@ -825,7 +847,7 @@ static void dispatch_message_real(
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
char mid[11 + 32 + 1];
char buffer[16 + LINE_MAX + 1];
- struct iovec iovec[N_IOVEC_META_FIELDS + 4];
+ struct iovec iovec[N_IOVEC_META_FIELDS + 6];
int n = 0;
va_list ap;
struct ucred ucred = {};
@@ -833,6 +855,9 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
assert(s);
assert(format);
+ IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3");
+ IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald");
+
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
@@ -866,6 +891,7 @@ void server_dispatch_message(
int rl, r;
_cleanup_free_ char *path = NULL;
+ uint64_t available = 0;
char *c;
assert(s);
@@ -905,9 +931,8 @@ void server_dispatch_message(
}
}
- rl = journal_rate_limit_test(s->rate_limit, path,
- priority & LOG_PRIMASK, available_space(s, false));
-
+ (void) determine_space(s, false, false, &available, NULL);
+ rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available);
if (rl == 0)
return;
@@ -922,16 +947,8 @@ finish:
static int system_journal_open(Server *s, bool flush_requested) {
- int r;
- char *fn;
- sd_id128_t machine;
- char ids[33];
-
- r = sd_id128_get_machine(&machine);
- if (r < 0)
- return log_error_errno(r, "Failed to get machine id: %m");
-
- sd_id128_to_string(machine, ids);
+ const char *fn;
+ int r = 0;
if (!s->system_journal &&
(s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) &&
@@ -947,15 +964,15 @@ static int system_journal_open(Server *s, bool flush_requested) {
if (s->storage == STORAGE_PERSISTENT)
(void) mkdir_p("/var/log/journal/", 0755);
- fn = strjoina("/var/log/journal/", ids);
+ fn = strjoina("/var/log/journal/", SERVER_MACHINE_ID(s));
(void) mkdir(fn, 0755);
fn = strjoina(fn, "/system.journal");
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
-
- if (r >= 0)
+ if (r >= 0) {
server_fix_perms(s, s->system_journal, 0);
- else if (r < 0) {
+ (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL);
+ } else if (r < 0) {
if (r != -ENOENT && r != -EROFS)
log_warning_errno(r, "Failed to open system journal: %m");
@@ -966,9 +983,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
if (!s->runtime_journal &&
(s->storage != STORAGE_NONE)) {
- fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
- if (!fn)
- return -ENOMEM;
+ fn = strjoina("/run/log/journal/", SERVER_MACHINE_ID(s), "/system.journal");
if (s->system_journal) {
@@ -977,8 +992,6 @@ static int system_journal_open(Server *s, bool flush_requested) {
* it into the system journal */
r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
- free(fn);
-
if (r < 0) {
if (r != -ENOENT)
log_warning_errno(r, "Failed to open runtime journal: %m");
@@ -996,18 +1009,16 @@ static int system_journal_open(Server *s, bool flush_requested) {
(void) mkdir_parents(fn, 0750);
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)
return log_error_errno(r, "Failed to open runtime journal: %m");
}
- if (s->runtime_journal)
+ if (s->runtime_journal) {
server_fix_perms(s, s->runtime_journal, 0);
+ (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL);
+ }
}
- available_space(s, true);
-
return r;
}
@@ -1028,7 +1039,7 @@ int server_flush_to_var(Server *s) {
if (!s->runtime_journal)
return 0;
- system_journal_open(s, true);
+ (void) system_journal_open(s, true);
if (!s->system_journal)
return 0;
@@ -1072,7 +1083,7 @@ int server_flush_to_var(Server *s) {
}
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
if (!s->system_journal) {
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
@@ -1088,11 +1099,12 @@ int server_flush_to_var(Server *s) {
}
}
+ r = 0;
+
finish:
journal_file_post_change(s->system_journal);
- journal_file_close(s->runtime_journal);
- s->runtime_journal = NULL;
+ s->runtime_journal = journal_file_close(s->runtime_journal);
if (r >= 0)
(void) rm_rf("/run/log/journal", REMOVE_ROOT);
@@ -1235,9 +1247,9 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
server_flush_to_var(s);
server_sync(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
- touch("/run/systemd/journal/flushed");
+ (void) touch("/run/systemd/journal/flushed");
return 0;
}
@@ -1249,7 +1261,7 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *
log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid);
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, true, true);
return 0;
}
@@ -1293,8 +1305,7 @@ static int setup_signals(Server *s) {
static int server_parse_proc_cmdline(Server *s) {
_cleanup_free_ char *line = NULL;
- const char *w, *state;
- size_t l;
+ const char *p;
int r;
r = proc_cmdline(&line);
@@ -1303,12 +1314,16 @@ static int server_parse_proc_cmdline(Server *s) {
return 0;
}
- FOREACH_WORD_QUOTED(w, l, line, state) {
+ p = line;
+ for(;;) {
_cleanup_free_ char *word;
- word = strndup(w, l);
- if (!word)
- return -ENOMEM;
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse journald syntax \"%s\": %m", line);
+
+ if (r == 0)
+ break;
if (startswith(word, "systemd.journald.forward_to_syslog=")) {
r = parse_boolean(word + 35);
@@ -1337,8 +1352,8 @@ static int server_parse_proc_cmdline(Server *s) {
} else if (startswith(word, "systemd.journald"))
log_warning("Invalid systemd.journald parameter. Ignoring.");
}
- /* do not warn about state here, since probably systemd already did */
+ /* do not warn about state here, since probably systemd already did */
return 0;
}
@@ -1434,8 +1449,7 @@ static int server_open_hostname(Server *s) {
/* kernels prior to 3.2 don't support polling this file. Ignore
* the failure. */
if (r == -EPERM) {
- log_warning("Failed to register hostname fd in event loop: %s. Ignoring.",
- strerror(-r));
+ log_warning_errno(r, "Failed to register hostname fd in event loop, ignoring: %m");
s->hostname_fd = safe_close(s->hostname_fd);
return 0;
}
@@ -1450,17 +1464,189 @@ static int server_open_hostname(Server *s) {
return 0;
}
+static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+ assert(s->notify_event_source == es);
+ assert(s->notify_fd == fd);
+
+ if (revents != EPOLLOUT) {
+ log_error("Invalid events on notify file descriptor.");
+ return -EINVAL;
+ }
+
+ /* The $NOTIFY_SOCKET is writable again, now send exactly one
+ * message on it. Either it's the wtachdog event, the initial
+ * READY=1 event or an stdout stream event. If there's nothing
+ * to write anymore, turn our event source off. The next time
+ * there's something to send it will be turned on again. */
+
+ if (!s->sent_notify_ready) {
+ static const char p[] =
+ "READY=1\n"
+ "STATUS=Processing requests...";
+ ssize_t l;
+
+ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ return log_error_errno(errno, "Failed to send READY=1 notification message: %m");
+ }
+
+ s->sent_notify_ready = true;
+ log_debug("Sent READY=1 notification.");
+
+ } else if (s->send_watchdog) {
+
+ static const char p[] =
+ "WATCHDOG=1";
+
+ ssize_t l;
+
+ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m");
+ }
+
+ s->send_watchdog = false;
+ log_debug("Sent WATCHDOG=1 notification.");
+
+ } else if (s->stdout_streams_notify_queue)
+ /* Dispatch one stream notification event */
+ stdout_stream_send_notify(s->stdout_streams_notify_queue);
+
+ /* Leave us enabled if there's still more to to do. */
+ if (s->send_watchdog || s->stdout_streams_notify_queue)
+ return 0;
+
+ /* There was nothing to do anymore, let's turn ourselves off. */
+ r = sd_event_source_set_enabled(es, SD_EVENT_OFF);
+ if (r < 0)
+ return log_error_errno(r, "Failed to turn off notify event source: %m");
+
+ return 0;
+}
+
+static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+
+ s->send_watchdog = true;
+
+ r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON);
+ if (r < 0)
+ log_warning_errno(r, "Failed to turn on notify event source: %m");
+
+ r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to restart watchdog event source: %m");
+
+ r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable watchdog event source: %m");
+
+ return 0;
+}
+
+static int server_connect_notify(Server *s) {
+ union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ };
+ const char *e;
+ int r;
+
+ assert(s);
+ assert(s->notify_fd < 0);
+ assert(!s->notify_event_source);
+
+ /*
+ So here's the problem: we'd like to send notification
+ messages to PID 1, but we cannot do that via sd_notify(),
+ since that's synchronous, and we might end up blocking on
+ it. Specifically: given that PID 1 might block on
+ dbus-daemon during IPC, and dbus-daemon is logging to us,
+ and might hence block on us, we might end up in a deadlock
+ if we block on sending PID 1 notification messages -- by
+ generating a full blocking circle. To avoid this, let's
+ create a non-blocking socket, and connect it to the
+ notification socket, and then wait for POLLOUT before we
+ send anything. This should efficiently avoid any deadlocks,
+ as we'll never block on PID 1, hence PID 1 can safely block
+ on dbus-daemon which can safely block on us again.
+
+ Don't think that this issue is real? It is, see:
+ https://github.com/systemd/systemd/issues/1505
+ */
+
+ e = getenv("NOTIFY_SOCKET");
+ if (!e)
+ return 0;
+
+ if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+ log_error("NOTIFY_SOCKET set to an invalid value: %s", e);
+ return -EINVAL;
+ }
+
+ if (strlen(e) > sizeof(sa.un.sun_path)) {
+ log_error("NOTIFY_SOCKET path too long: %s", e);
+ return -EINVAL;
+ }
+
+ s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (s->notify_fd < 0)
+ return log_error_errno(errno, "Failed to create notify socket: %m");
+
+ (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE);
+
+ strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path));
+ if (sa.un.sun_path[0] == '@')
+ sa.un.sun_path[0] = 0;
+
+ r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+ if (r < 0)
+ return log_error_errno(errno, "Failed to connect to notify socket: %m");
+
+ r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch notification socket: %m");
+
+ if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) {
+ s->send_watchdog = true;
+
+ r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec*3/4, dispatch_watchdog, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add watchdog time event: %m");
+ }
+
+ /* This should fire pretty soon, which we'll use to send the
+ * READY=1 event. */
+
+ return 0;
+}
+
int server_init(Server *s) {
_cleanup_fdset_free_ FDSet *fds = NULL;
int n, r, fd;
+ bool no_sockets;
assert(s);
zero(*s);
- s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
+ s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
s->compress = true;
s->seal = true;
+ s->watchdog_usec = USEC_INFINITY;
+
s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
s->sync_scheduled = false;
@@ -1477,18 +1663,19 @@ int server_init(Server *s) {
s->max_level_console = LOG_INFO;
s->max_level_wall = LOG_EMERG;
- memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
- memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
+ journal_reset_metrics(&s->system_metrics);
+ journal_reset_metrics(&s->runtime_metrics);
server_parse_config_file(s);
server_parse_proc_cmdline(s);
+
if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) {
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
s->rate_limit_interval, s->rate_limit_burst);
s->rate_limit_interval = s->rate_limit_burst = 0;
}
- mkdir_p("/run/systemd/journal", 0755);
+ (void) mkdir_p("/run/systemd/journal", 0755);
s->user_journals = ordered_hashmap_new(NULL);
if (!s->user_journals)
@@ -1502,8 +1689,6 @@ int server_init(Server *s) {
if (r < 0)
return log_error_errno(r, "Failed to create event loop: %m");
- sd_event_set_watchdog(s->event, true);
-
n = sd_listen_fds(true);
if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
@@ -1561,30 +1746,44 @@ int server_init(Server *s) {
}
}
- r = server_open_stdout_socket(s, fds);
- if (r < 0)
- return r;
+ /* Try to restore streams, but don't bother if this fails */
+ (void) server_restore_streams(s, fds);
if (fdset_size(fds) > 0) {
log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds));
fds = fdset_free(fds);
}
+ no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0;
+
+ /* always open stdout, syslog, native, and kmsg sockets */
+
+ /* systemd-journald.socket: /run/systemd/journal/stdout */
+ r = server_open_stdout_socket(s);
+ if (r < 0)
+ return r;
+
+ /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */
r = server_open_syslog_socket(s);
if (r < 0)
return r;
+ /* systemd-journald.socket: /run/systemd/journal/socket */
r = server_open_native_socket(s);
if (r < 0)
return r;
+ /* /dev/ksmg */
r = server_open_dev_kmsg(s);
if (r < 0)
return r;
- r = server_open_audit(s);
- if (r < 0)
- return r;
+ /* Unless we got *some* sockets and not audit, open audit socket */
+ if (s->audit_fd >= 0 || no_sockets) {
+ r = server_open_audit(s);
+ if (r < 0)
+ return r;
+ }
r = server_open_kernel_seqnum(s);
if (r < 0)
@@ -1614,11 +1813,9 @@ int server_init(Server *s) {
server_cache_boot_id(s);
server_cache_machine_id(s);
- r = system_journal_open(s, false);
- if (r < 0)
- return r;
+ (void) server_connect_notify(s);
- return 0;
+ return system_journal_open(s, false);
}
void server_maybe_append_tags(Server *s) {
@@ -1666,6 +1863,8 @@ void server_done(Server *s) {
sd_event_source_unref(s->sigterm_event_source);
sd_event_source_unref(s->sigint_event_source);
sd_event_source_unref(s->hostname_event_source);
+ sd_event_source_unref(s->notify_event_source);
+ sd_event_source_unref(s->watchdog_event_source);
sd_event_unref(s->event);
safe_close(s->syslog_fd);
@@ -1674,6 +1873,7 @@ void server_done(Server *s) {
safe_close(s->dev_kmsg_fd);
safe_close(s->audit_fd);
safe_close(s->hostname_fd);
+ safe_close(s->notify_fd);
if (s->rate_limit)
journal_rate_limit_free(s->rate_limit);
@@ -1691,3 +1891,22 @@ void server_done(Server *s) {
udev_unref(s->udev);
}
+
+static const char* const storage_table[_STORAGE_MAX] = {
+ [STORAGE_AUTO] = "auto",
+ [STORAGE_VOLATILE] = "volatile",
+ [STORAGE_PERSISTENT] = "persistent",
+ [STORAGE_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
+
+static const char* const split_mode_table[_SPLIT_MAX] = {
+ [SPLIT_LOGIN] = "login",
+ [SPLIT_UID] = "uid",
+ [SPLIT_NONE] = "none",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index d954c5190d..03a61bd2ed 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -25,10 +25,13 @@
#include <sys/types.h>
#include "sd-event.h"
-#include "journal-file.h"
+
+typedef struct Server Server;
+
#include "hashmap.h"
-#include "audit.h"
+#include "journal-file.h"
#include "journald-rate-limit.h"
+#include "journald-stream.h"
#include "list.h"
typedef enum Storage {
@@ -48,15 +51,14 @@ typedef enum SplitMode {
_SPLIT_INVALID = -1
} SplitMode;
-typedef struct StdoutStream StdoutStream;
-
-typedef struct Server {
+struct Server {
int syslog_fd;
int native_fd;
int stdout_fd;
int dev_kmsg_fd;
int audit_fd;
int hostname_fd;
+ int notify_fd;
sd_event *event;
@@ -71,6 +73,8 @@ typedef struct Server {
sd_event_source *sigterm_event_source;
sd_event_source *sigint_event_source;
sd_event_source *hostname_event_source;
+ sd_event_source *notify_event_source;
+ sd_event_source *watchdog_event_source;
JournalFile *runtime_journal;
JournalFile *system_journal;
@@ -100,8 +104,9 @@ typedef struct Server {
unsigned n_forward_syslog_missed;
usec_t last_warn_forward_syslog_missed;
- uint64_t cached_available_space;
- usec_t cached_available_space_timestamp;
+ uint64_t cached_space_available;
+ uint64_t cached_space_limit;
+ usec_t cached_space_timestamp;
uint64_t var_available_timestamp;
@@ -110,6 +115,7 @@ typedef struct Server {
usec_t oldest_file_usec;
LIST_HEAD(StdoutStream, stdout_streams);
+ LIST_HEAD(StdoutStream, stdout_streams_notify_queue);
unsigned n_stdout_streams;
char *tty_path;
@@ -125,13 +131,14 @@ typedef struct Server {
MMapCache *mmap;
- bool dev_kmsg_readable;
+ struct udev *udev;
uint64_t *kernel_seqnum;
+ bool dev_kmsg_readable:1;
- struct udev *udev;
-
- bool sync_scheduled;
+ bool send_watchdog:1;
+ bool sent_notify_ready:1;
+ bool sync_scheduled:1;
char machine_id_field[sizeof("_MACHINE_ID=") + 32];
char boot_id_field[sizeof("_BOOT_ID=") + 32];
@@ -139,7 +146,11 @@ typedef struct Server {
/* Cached cgroup root, so that we don't have to query that all the time */
char *cgroup_root;
-} Server;
+
+ usec_t watchdog_usec;
+};
+
+#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
#define N_IOVEC_META_FIELDS 20
#define N_IOVEC_KERNEL_FIELDS 64
@@ -166,7 +177,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid);
int server_init(Server *s);
void server_done(Server *s);
void server_sync(Server *s);
-void server_vacuum(Server *s);
+int server_vacuum(Server *s, bool verbose, bool patch_min_use);
void server_rotate(Server *s);
int server_schedule_sync(Server *s, int priority);
int server_flush_to_var(Server *s);
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 69e2d41863..fb800782fb 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -19,25 +19,35 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stddef.h>
+#include <unistd.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
-#include "sd-event.h"
#include "sd-daemon.h"
-#include "socket-util.h"
-#include "selinux-util.h"
-#include "mkdir.h"
+#include "sd-event.h"
+
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-kmsg.h"
#include "journald-server.h"
#include "journald-stream.h"
#include "journald-syslog.h"
-#include "journald-kmsg.h"
-#include "journald-console.h"
#include "journald-wall.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
#define STDOUT_STREAMS_MAX 4096
@@ -69,6 +79,7 @@ struct StdoutStream {
bool forward_to_console:1;
bool fdstore:1;
+ bool in_notify_queue:1;
char buffer[LINE_MAX+1];
size_t length;
@@ -78,6 +89,7 @@ struct StdoutStream {
char *state_file;
LIST_FIELDS(StdoutStream, stdout_stream);
+ LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
};
void stdout_stream_free(StdoutStream *s) {
@@ -88,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) {
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams --;
LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
+
+ if (s->in_notify_queue)
+ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
}
if (s->event_source) {
@@ -111,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) {
return;
if (s->state_file)
- unlink(s->state_file);
+ (void) unlink(s->state_file);
stdout_stream_free(s);
}
@@ -190,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) {
goto fail;
}
- /* Store the connection fd in PID 1, so that we get it passed
- * in again on next start */
- if (!s->fdstore) {
- sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
- s->fdstore = true;
+ if (!s->fdstore && !s->in_notify_queue) {
+ LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+ s->in_notify_queue = true;
+
+ if (s->server->notify_event_source) {
+ r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable notify event source: %m");
+ }
}
return 0;
@@ -519,8 +538,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
if (errno == EAGAIN)
return 0;
- log_error_errno(errno, "Failed to accept stdout connection: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to accept stdout connection: %m");
}
if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) {
@@ -627,7 +645,7 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) {
return 0;
}
-static int server_restore_streams(Server *s, FDSet *fds) {
+int server_restore_streams(Server *s, FDSet *fds) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r;
@@ -681,7 +699,7 @@ fail:
return log_error_errno(errno, "Failed to read streams directory: %m");
}
-int server_open_stdout_socket(Server *s, FDSet *fds) {
+int server_open_stdout_socket(Server *s) {
int r;
assert(s);
@@ -717,8 +735,52 @@ int server_open_stdout_socket(Server *s, FDSet *fds) {
if (r < 0)
return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
- /* Try to restore streams, but don't bother if this fails */
- (void) server_restore_streams(s, fds);
-
return 0;
}
+
+void stdout_stream_send_notify(StdoutStream *s) {
+ struct iovec iovec = {
+ .iov_base = (char*) "FDSTORE=1",
+ .iov_len = strlen("FDSTORE=1"),
+ };
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ };
+ struct cmsghdr *cmsg;
+ ssize_t l;
+
+ assert(s);
+ assert(!s->fdstore);
+ assert(s->in_notify_queue);
+ assert(s->server);
+ assert(s->server->notify_fd >= 0);
+
+ /* Store the connection fd in PID 1, so that we get it passed
+ * in again on next start */
+
+ msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
+ msghdr.msg_control = alloca0(msghdr.msg_controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+ memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int));
+
+ l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return;
+
+ log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m");
+ } else {
+ log_debug("Successfully sent stream file descriptor to service manager.");
+ s->fdstore = 1;
+ }
+
+ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+ s->in_notify_queue = false;
+
+}
diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h
index 94bf955d78..e3497f0ded 100644
--- a/src/journal/journald-stream.h
+++ b/src/journal/journald-stream.h
@@ -21,9 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+typedef struct StdoutStream StdoutStream;
+
#include "fdset.h"
#include "journald-server.h"
-int server_open_stdout_socket(Server *s, FDSet *fds);
+int server_open_stdout_socket(Server *s);
+int server_restore_streams(Server *s, FDSet *fds);
void stdout_stream_free(StdoutStream *s);
+void stdout_stream_send_notify(StdoutStream *s);
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index ffba451955..f3ac1a7ae0 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -19,20 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <stddef.h>
#include <sys/epoll.h>
+#include <unistd.h>
-#include "systemd/sd-messages.h"
-#include "socket-util.h"
-#include "selinux-util.h"
+#include "sd-messages.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
+#include "journald-console.h"
+#include "journald-kmsg.h"
#include "journald-server.h"
#include "journald-syslog.h"
-#include "journald-kmsg.h"
-#include "journald-console.h"
#include "journald-wall.h"
-#include "formats-util.h"
#include "process-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
/* Warn once every 30s if we missed syslog message */
#define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC)
diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c
index 7863766ae7..69540f1141 100644
--- a/src/journal/journald-wall.c
+++ b/src/journal/journald-wall.c
@@ -19,11 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "utmp-wtmp.h"
-#include "journald-server.h"
-#include "journald-wall.h"
+#include "alloc-util.h"
#include "formats-util.h"
+#include "journald-server.h"
#include "process-util.h"
+#include "string-util.h"
+#include "utmp-wtmp.h"
+#include "journald-wall.h"
void server_forward_wall(
Server *s,
diff --git a/src/journal/journald.c b/src/journal/journald.c
index b2624c6d28..b137e3c7be 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -21,8 +21,8 @@
#include <unistd.h>
-#include "systemd/sd-messages.h"
-#include "systemd/sd-daemon.h"
+#include "sd-messages.h"
+#include "sd-daemon.h"
#include "journal-authenticate.h"
#include "journald-server.h"
@@ -54,17 +54,13 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- server_vacuum(&server);
+ server_vacuum(&server, false, false);
server_flush_to_var(&server);
server_flush_dev_kmsg(&server);
log_debug("systemd-journald running as pid "PID_FMT, getpid());
server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started");
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
-
for (;;) {
usec_t t = USEC_INFINITY, n;
@@ -82,7 +78,7 @@ int main(int argc, char *argv[]) {
if (server.oldest_file_usec + server.max_retention_usec < n) {
log_info("Retention time reached.");
server_rotate(&server);
- server_vacuum(&server);
+ server_vacuum(&server, false, false);
continue;
}
@@ -117,10 +113,6 @@ int main(int argc, char *argv[]) {
server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped");
finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
-
server_done(&server);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 47eefe91c1..7beb96c671 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -22,9 +22,11 @@
#SystemMaxUse=
#SystemKeepFree=
#SystemMaxFileSize=
+#SystemMaxFiles=100
#RuntimeMaxUse=
#RuntimeKeepFree=
#RuntimeMaxFileSize=
+#RuntimeMaxFiles=100
#MaxRetentionSec=
#MaxFileSec=1month
#ForwardToSyslog=no
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index 22f75540b8..3cb1dfa986 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <sys/mman.h>
+#include "alloc-util.h"
#include "hashmap.h"
#include "list.h"
#include "log.h"
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 13fa9b52fc..5cde7f17f7 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -21,29 +21,38 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/magic.h>
+#include <poll.h>
#include <stddef.h>
-#include <unistd.h>
#include <sys/inotify.h>
-#include <poll.h>
#include <sys/vfs.h>
-#include <linux/magic.h>
+#include <unistd.h>
#include "sd-journal.h"
+
+#include "alloc-util.h"
+#include "catalog.h"
+#include "compress.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "fs-util.h"
+#include "hashmap.h"
+#include "hostname-util.h"
+#include "io-util.h"
#include "journal-def.h"
#include "journal-file.h"
-#include "hashmap.h"
+#include "journal-internal.h"
#include "list.h"
-#include "strv.h"
-#include "path-util.h"
#include "lookup3.h"
-#include "compress.h"
-#include "journal-internal.h"
#include "missing.h"
-#include "catalog.h"
+#include "path-util.h"
#include "replace-var.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "hostname-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
#define JOURNAL_FILES_MAX 7168
@@ -64,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) {
return j->original_pid != getpid();
}
-/* We return an error here only if we didn't manage to
- memorize the real error. */
-static int set_put_error(sd_journal *j, int r) {
+static int journal_put_error(sd_journal *j, int r, const char *path) {
+ char *copy;
int k;
+ /* Memorize an error we encountered, and store which
+ * file/directory it was generated from. Note that we store
+ * only *one* path per error code, as the error code is the
+ * key into the hashmap, and the path is the value. This means
+ * we keep track only of all error kinds, but not of all error
+ * locations. This has the benefit that the hashmap cannot
+ * grow beyond bounds.
+ *
+ * We return an error here only if we didn't manage to
+ * memorize the real error. */
+
if (r >= 0)
return r;
- k = set_ensure_allocated(&j->errors, NULL);
+ k = hashmap_ensure_allocated(&j->errors, NULL);
if (k < 0)
return k;
- return set_put(j->errors, INT_TO_PTR(r));
+ if (path) {
+ copy = strdup(path);
+ if (!copy)
+ return -ENOMEM;
+ } else
+ copy = NULL;
+
+ k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
+ if (k < 0) {
+ free(copy);
+
+ if (k == -EEXIST)
+ return 0;
+
+ return k;
+ }
+
+ return 0;
}
static void detach_location(sd_journal *j) {
@@ -1016,8 +1052,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
_public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
int r;
- const char *word, *state;
- size_t l;
Object *o;
assert_return(j, -EINVAL);
@@ -1031,20 +1065,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
if (r < 0)
return r;
- FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
+ for(;;) {
_cleanup_free_ char *item = NULL;
- sd_id128_t id;
unsigned long long ll;
+ sd_id128_t id;
int k = 0;
- if (l < 2 || word[1] != '=')
- return -EINVAL;
+ r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
- item = strndup(word, l);
- if (!item)
- return -ENOMEM;
+ if (r == 0)
+ break;
- switch (word[0]) {
+ if (strlen(item) < 2 || item[1] != '=')
+ return -EINVAL;
+
+ switch (item[0]) {
case 's':
k = sd_id128_from_string(item+2, &id);
@@ -1173,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
}
static bool file_type_wanted(int flags, const char *filename) {
+ assert(filename);
+
if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
return false;
@@ -1197,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) {
static int add_any_file(sd_journal *j, const char *path) {
JournalFile *f = NULL;
- int r;
+ int r, k;
assert(j);
assert(path);
@@ -1206,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) {
return 0;
if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
- log_warning("Too many open journal files, not adding %s.", path);
- return set_put_error(j, -ETOOMANYREFS);
+ log_debug("Too many open journal files, not adding %s.", path);
+ r = -ETOOMANYREFS;
+ goto fail;
}
r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_debug_errno(r, "Failed to open journal file %s: %m", path);
+ goto fail;
+ }
/* journal_file_dump(f); */
r = ordered_hashmap_put(j->files, f->path, f);
if (r < 0) {
journal_file_close(f);
- return r;
+ goto fail;
}
log_debug("File %s added.", f->path);
@@ -1229,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) {
j->current_invalidate_counter ++;
return 0;
+
+fail:
+ k = journal_put_error(j, r, path);
+ if (k < 0)
+ return k;
+
+ return r;
}
static int add_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path = NULL;
- int r;
+ const char *path;
assert(j);
assert(prefix);
@@ -1243,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
!file_type_wanted(j->flags, filename))
return 0;
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
- r = add_any_file(j, path);
- if (r == -ENOENT)
- return 0;
- return r;
+ path = strjoina(prefix, "/", filename);
+ return add_any_file(j, path);
}
-static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path;
+static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
+ const char *path;
JournalFile *f;
assert(j);
assert(prefix);
assert(filename);
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
+ path = strjoina(prefix, "/", filename);
f = ordered_hashmap_get(j->files, path);
if (!f)
- return 0;
+ return;
remove_file_real(j, f);
- return 0;
}
static void remove_file_real(sd_journal *j, JournalFile *f) {
@@ -1299,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
j->current_invalidate_counter ++;
}
+static int dirname_is_machine_id(const char *fn) {
+ sd_id128_t id, machine;
+ int r;
+
+ r = sd_id128_get_machine(&machine);
+ if (r < 0)
+ return r;
+
+ r = sd_id128_from_string(fn, &id);
+ if (r < 0)
+ return r;
+
+ return sd_id128_equal(id, machine);
+}
+
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
_cleanup_free_ char *path = NULL;
- int r;
_cleanup_closedir_ DIR *d = NULL;
- sd_id128_t id, mid;
+ struct dirent *de = NULL;
Directory *m;
+ int r, k;
assert(j);
assert(prefix);
@@ -1313,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
log_debug("Considering %s/%s.", prefix, dirname);
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
- (sd_id128_from_string(dirname, &id) < 0 ||
- sd_id128_get_machine(&mid) < 0 ||
- !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
+ !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
return 0;
path = strjoin(prefix, "/", dirname, NULL);
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ r = -ENOMEM;
+ goto fail;
+ }
d = opendir(path);
if (!d) {
- log_debug_errno(errno, "Failed to open %s: %m", path);
- if (errno == ENOENT)
- return 0;
- return -errno;
+ r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
+ goto fail;
}
m = hashmap_get(j->directories_by_path, path);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = false;
m->path = path;
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
path = NULL; /* avoid freeing in cleanup */
@@ -1363,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
inotify_rm_watch(j->inotify_fd, m->wd);
}
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, path ?: dirname);
+ if (k < 0)
+ return k;
+
+ return r;
}
-static int add_root_directory(sd_journal *j, const char *p) {
+static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
Directory *m;
- int r;
+ int r, k;
assert(j);
assert(p);
@@ -1410,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) {
p = strjoina(j->prefix, p);
d = opendir(p);
- if (!d)
- return -errno;
+ if (!d) {
+ if (errno == ENOENT && missing_ok)
+ return 0;
+
+ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+ goto fail;
+ }
m = hashmap_get(j->directories_by_path, p);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = true;
m->path = strdup(p);
if (!m->path) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m->path);
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
j->current_invalidate_counter ++;
@@ -1452,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) {
if (j->no_new_files)
return 0;
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
sd_id128_t id;
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
-
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
- sd_id128_from_string(de->d_name, &id) >= 0) {
-
- r = add_directory(j, m->path, de->d_name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
+ else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
+ sd_id128_from_string(de->d_name, &id) >= 0)
+ (void) add_directory(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, p);
+ if (k < 0)
+ return k;
+
+ return r;
}
static void remove_directory(sd_journal *j, Directory *d) {
@@ -1512,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) {
}
static int add_search_paths(sd_journal *j) {
- int r;
- const char search_paths[] =
+
+ static const char search_paths[] =
"/run/log/journal\0"
"/var/log/journal\0";
const char *p;
@@ -1523,14 +1560,8 @@ static int add_search_paths(sd_journal *j) {
/* We ignore most errors here, since the idea is to only open
* what's actually accessible, and ignore the rest. */
- NULSTR_FOREACH(p, search_paths) {
- r = add_root_directory(j, p);
- if (r < 0 && r != -ENOENT) {
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ NULSTR_FOREACH(p, search_paths)
+ (void) add_root_directory(j, p, true);
return 0;
}
@@ -1554,17 +1585,14 @@ static int add_current_paths(sd_journal *j) {
if (!dir)
return -ENOMEM;
- r = add_root_directory(j, dir);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, dir, true);
+ if (r < 0)
return r;
- }
}
return 0;
}
-
static int allocate_inotify(sd_journal *j) {
assert(j);
@@ -1692,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
if (!j)
return -ENOMEM;
- r = add_root_directory(j, path);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, path, false);
+ if (r < 0)
goto fail;
- }
*ret = j;
return 0;
@@ -1721,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
STRV_FOREACH(path, paths) {
r = add_any_file(j, *path);
- if (r < 0) {
- log_error_errno(r, "Failed to open %s: %m", *path);
+ if (r < 0)
goto fail;
- }
}
j->no_new_files = true;
@@ -1741,6 +1765,7 @@ fail:
_public_ void sd_journal_close(sd_journal *j) {
Directory *d;
JournalFile *f;
+ char *p;
if (!j)
return;
@@ -1768,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) {
mmap_cache_unref(j->mmap);
}
+ while ((p = hashmap_steal_first(j->errors)))
+ free(p);
+ hashmap_free(j->errors);
+
free(j->path);
free(j->prefix);
free(j->unique_field);
- set_free(j->errors);
free(j);
}
@@ -2064,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
if (j->no_new_files)
r = add_current_paths(j);
else if (j->path)
- r = add_root_directory(j, j->path);
+ r = add_root_directory(j, j->path, true);
else
r = add_search_paths(j);
if (r < 0)
@@ -2111,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
Directory *d;
- int r;
assert(j);
assert(e);
@@ -2127,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for a journal file */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_file(j, d->path, e->name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- d->path, e->name);
- set_put_error(j, r);
- }
-
- } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
-
- r = remove_file(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_file(j, d->path, e->name);
+ else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
+ remove_file(j, d->path, e->name);
} else if (!d->is_root && e->len == 0) {
@@ -2153,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for root directory */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_directory(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_directory(j, d->path, e->name);
}
return;
@@ -2166,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
if (e->mask & IN_IGNORED)
return;
- log_warning("Unknown inotify event.");
+ log_debug("Unknown inotify event.");
}
static int determine_change(sd_journal *j) {
diff --git a/src/journal/stacktrace.c b/src/journal/stacktrace.c
index 98a54ff269..4305462f80 100644
--- a/src/journal/stacktrace.c
+++ b/src/journal/stacktrace.c
@@ -22,10 +22,13 @@
#include <dwarf.h>
#include <elfutils/libdwfl.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "macro.h"
#include "stacktrace.h"
-#include "formats-util.h"
+#include "string-util.h"
+#include "util.h"
#define FRAMES_MAX 64
#define THREADS_MAX 64
diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c
index dbfdea609d..aea8fd15e6 100644
--- a/src/journal/test-catalog.c
+++ b/src/journal/test-catalog.c
@@ -25,11 +25,16 @@
#include <errno.h>
#include <fcntl.h>
-#include "util.h"
-#include "log.h"
-#include "macro.h"
#include "sd-messages.h"
+
+#include "alloc-util.h"
#include "catalog.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "util.h"
static const char *catalog_dirs[] = {
CATALOG_DIR,
diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c
index c8e5b76c6c..93ea9c6318 100644
--- a/src/journal/test-compress-benchmark.c
+++ b/src/journal/test-compress-benchmark.c
@@ -1,3 +1,5 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
/***
This file is part of systemd
@@ -17,30 +19,73 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "compress.h"
-#include "util.h"
#include "macro.h"
+#include "parse-util.h"
+#include "random-util.h"
+#include "string-util.h"
+#include "util.h"
typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size);
typedef int (decompress_t)(const void *src, uint64_t src_size,
void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max);
+static usec_t arg_duration = 2 * USEC_PER_SEC;
+static size_t arg_start;
+
#define MAX_SIZE (1024*1024LU)
+#define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */
+
+static size_t _permute(size_t x) {
+ size_t residue;
+
+ if (x >= PRIME)
+ return x;
+
+ residue = x*x % PRIME;
+ if (x <= PRIME / 2)
+ return residue;
+ else
+ return PRIME - residue;
+}
+
+static size_t permute(size_t x) {
+ return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345);
+}
-static char* make_buf(size_t count) {
+static char* make_buf(size_t count, const char *type) {
char *buf;
size_t i;
buf = malloc(count);
assert_se(buf);
- for (i = 0; i < count; i++)
- buf[i] = 'a' + i % ('z' - 'a' + 1);
+ if (streq(type, "zeros"))
+ memzero(buf, count);
+ else if (streq(type, "simple"))
+ for (i = 0; i < count; i++)
+ buf[i] = 'a' + i % ('z' - 'a' + 1);
+ else if (streq(type, "random")) {
+ size_t step = count / 10;
+
+ random_bytes(buf, step);
+ memzero(buf + 1*step, step);
+ random_bytes(buf + 2*step, step);
+ memzero(buf + 3*step, step);
+ random_bytes(buf + 4*step, step);
+ memzero(buf + 5*step, step);
+ random_bytes(buf + 6*step, step);
+ memzero(buf + 7*step, step);
+ random_bytes(buf + 8*step, step);
+ memzero(buf + 9*step, step);
+ } else
+ assert_not_reached("here");
return buf;
}
-static void test_compress_decompress(const char* label,
+static void test_compress_decompress(const char* label, const char* type,
compress_t compress, decompress_t decompress) {
usec_t n, n2 = 0;
float dt;
@@ -50,64 +95,85 @@ static void test_compress_decompress(const char* label,
size_t buf2_allocated = 0;
size_t skipped = 0, compressed = 0, total = 0;
- text = make_buf(MAX_SIZE);
+ text = make_buf(MAX_SIZE, type);
buf = calloc(MAX_SIZE + 1, 1);
assert_se(text && buf);
n = now(CLOCK_MONOTONIC);
- for (size_t i = 1; i <= MAX_SIZE; i += (i < 2048 ? 1 : 217)) {
- size_t j = 0, k = 0;
+ for (size_t i = 0; i <= MAX_SIZE; i++) {
+ size_t j = 0, k = 0, size;
int r;
- r = compress(text, i, buf, &j);
+ size = permute(i);
+
+ log_debug("%s %zu %zu", type, i, size);
+
+ memzero(buf, MIN(size + 1000, MAX_SIZE));
+
+ r = compress(text, size, buf, &j);
/* assume compression must be successful except for small inputs */
- assert_se(r == 0 || (i < 2048 && r == -ENOBUFS));
+ assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
+
/* check for overwrites */
- assert_se(buf[i] == 0);
+ assert_se(buf[size] == 0);
if (r != 0) {
- skipped += i;
+ skipped += size;
continue;
}
assert_se(j > 0);
- if (j >= i)
- log_error("%s \"compressed\" %zu -> %zu", label, i, j);
+ if (j >= size)
+ log_error("%s \"compressed\" %zu -> %zu", label, size, j);
r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0);
assert_se(r == 0);
assert_se(buf2_allocated >= k);
- assert_se(k == i);
+ assert_se(k == size);
- assert_se(memcmp(text, buf2, i) == 0);
+ assert_se(memcmp(text, buf2, size) == 0);
- total += i;
+ total += size;
compressed += j;
n2 = now(CLOCK_MONOTONIC);
- if (n2 - n > 60 * USEC_PER_SEC)
+ if (n2 - n > arg_duration)
break;
}
dt = (n2-n) / 1e6;
- log_info("%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
+ log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
"mean compresion %.2f%%, skipped %zu bytes",
- label, total, dt,
+ label, type, total, dt,
total / 1024. / 1024 / dt,
100 - compressed * 100. / total,
skipped);
}
int main(int argc, char *argv[]) {
+ const char *i;
- log_set_max_level(LOG_DEBUG);
+ log_set_max_level(LOG_INFO);
+ if (argc >= 2) {
+ unsigned x;
+
+ assert_se(safe_atou(argv[1], &x) >= 0);
+ arg_duration = x * USEC_PER_SEC;
+ }
+ if (argc == 3)
+ (void) safe_atolu(argv[2], &arg_start);
+ else
+ arg_start = getpid();
+
+ NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
#ifdef HAVE_XZ
- test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz);
+ test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
#endif
#ifdef HAVE_LZ4
- test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4);
+ test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
#endif
+ }
return 0;
}
diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c
index f17c00e60d..b9d90a8988 100644
--- a/src/journal/test-compress.c
+++ b/src/journal/test-compress.c
@@ -17,10 +17,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "compress.h"
-#include "util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "macro.h"
#include "random-util.h"
+#include "util.h"
#ifdef HAVE_XZ
# define XZ_OK 0
@@ -144,8 +147,8 @@ static void test_compress_stream(int compression,
const char *srcfile) {
_cleanup_close_ int src = -1, dst = -1, dst2 = -1;
- char pattern[] = "/tmp/systemd-test.xz.XXXXXX",
- pattern2[] = "/tmp/systemd-test.xz.XXXXXX";
+ char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
+ pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
int r;
_cleanup_free_ char *cmd = NULL, *cmd2;
struct stat st = {};
@@ -185,7 +188,7 @@ static void test_compress_stream(int compression,
assert_se(lseek(dst, 1, SEEK_SET) == 1);
r = decompress(dst, dst2, st.st_size);
- assert_se(r == -EBADMSG);
+ assert_se(r == -EBADMSG || r == 0);
assert_se(lseek(dst, 0, SEEK_SET) == 0);
assert_se(lseek(dst2, 0, SEEK_SET) == 0);
@@ -236,8 +239,7 @@ int main(int argc, char *argv[]) {
compress_blob_lz4, decompress_startswith_lz4,
data, sizeof(data), true);
- /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */
- test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL,
+ test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
compress_stream_lz4, decompress_stream_lz4, argv[0]);
#else
log_info("/* LZ4 test skipped */");
diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c
index cde2025ae9..040c7d58fb 100644
--- a/src/journal/test-journal-enum.c
+++ b/src/journal/test-journal-enum.c
@@ -21,8 +21,9 @@
#include <stdio.h>
-#include "log.h"
#include "sd-journal.h"
+
+#include "log.h"
#include "macro.h"
#include "journal-internal.h"
diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c
index 2d4f531e9b..03d1522e23 100644
--- a/src/journal/test-journal-flush.c
+++ b/src/journal/test-journal-flush.c
@@ -22,9 +22,12 @@
#include <fcntl.h>
#include "sd-journal.h"
-#include "macro.h"
+
+#include "alloc-util.h"
#include "journal-file.h"
#include "journal-internal.h"
+#include "macro.h"
+#include "string-util.h"
int main(int argc, char *argv[]) {
_cleanup_free_ char *fn = NULL;
diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c
index e6599f366d..142da85041 100644
--- a/src/journal/test-journal-init.c
+++ b/src/journal/test-journal-init.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
#include "log.h"
-#include "util.h"
+#include "parse-util.h"
#include "rm-rf.h"
+#include "util.h"
int main(int argc, char *argv[]) {
sd_journal *j;
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index adefa1b026..4ad89fe4b6 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -24,11 +24,14 @@
#include <fcntl.h>
#include "sd-journal.h"
+
+#include "alloc-util.h"
#include "journal-file.h"
#include "journal-vacuum.h"
-#include "util.h"
#include "log.h"
+#include "parse-util.h"
#include "rm-rf.h"
+#include "util.h"
/* This program tests skipping around in a multi-file journal.
*/
@@ -197,7 +200,7 @@ static void test_skip(void (*setup)(void)) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
@@ -282,7 +285,7 @@ static void test_sequence_numbers(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c
index a3187053c9..abefedb992 100644
--- a/src/journal/test-journal-match.c
+++ b/src/journal/test-journal-match.c
@@ -21,11 +21,13 @@
#include <stdio.h>
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
+#include "alloc-util.h"
#include "journal-internal.h"
-#include "util.h"
#include "log.h"
+#include "string-util.h"
+#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_journal_close_ sd_journal*j;
diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c
index 81ca47ed8d..694376670d 100644
--- a/src/journal/test-journal-send.c
+++ b/src/journal/test-journal-send.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "systemd/sd-journal.h"
#include <stdlib.h>
#include <unistd.h>
+#include "sd-journal.h"
+
#include "log.h"
int main(int argc, char *argv[]) {
diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c
index b5ecf2f375..0cbef4b8c5 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/journal/test-journal-stream.c
@@ -19,16 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <fcntl.h>
+#include <unistd.h>
#include "sd-journal.h"
-#include "util.h"
+
+#include "alloc-util.h"
+#include "journal-file.h"
+#include "journal-internal.h"
#include "log.h"
#include "macro.h"
+#include "parse-util.h"
#include "rm-rf.h"
-#include "journal-file.h"
-#include "journal-internal.h"
+#include "util.h"
#define N_ENTRIES 200
diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c
index c99ca0654b..1784187fe9 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/journal/test-journal-syslog.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "journald-syslog.h"
#include "macro.h"
+#include "string-util.h"
static void test_syslog_parse_identifier(const char* str,
const char *ident, const char*pid, int ret) {
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index d89123dc64..887a83efe1 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -23,12 +23,13 @@
#include <unistd.h>
#include <fcntl.h>
-#include "util.h"
-#include "log.h"
-#include "rm-rf.h"
+#include "fd-util.h"
#include "journal-file.h"
#include "journal-verify.h"
+#include "log.h"
+#include "rm-rf.h"
#include "terminal-util.h"
+#include "util.h"
#define N_ENTRIES 6000
#define RANDOM_RANGE 77
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index caaab258c9..01d4bc968a 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -116,7 +116,7 @@ static void test_non_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
@@ -155,7 +155,7 @@ static void test_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c
index 3258b22702..fdd48e531c 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/journal/test-mmap-cache.c
@@ -19,14 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
-#include <fcntl.h>
+#include "fd-util.h"
+#include "fileio.h"
#include "macro.h"
-#include "util.h"
#include "mmap-cache.h"
+#include "util.h"
int main(int argc, char *argv[]) {
int x, y, z, r;
diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c
index 2f5b9b3731..4660c7ea09 100644
--- a/src/libsystemd-network/arp-util.c
+++ b/src/libsystemd-network/arp-util.c
@@ -21,8 +21,9 @@
#include <linux/filter.h>
#include <arpa/inet.h>
-#include "util.h"
#include "arp-util.h"
+#include "fd-util.h"
+#include "util.h"
int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
struct sock_filter filter[] = {
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index 7d9cad2a70..51ee7bcce4 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -19,18 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-#include "sd-id128.h"
#include "libudev.h"
-#include "udev-util.h"
-
-#include "virt.h"
-#include "sparse-endian.h"
-#include "siphash24.h"
+#include "sd-id128.h"
-#include "dhcp6-protocol.h"
#include "dhcp-identifier.h"
+#include "dhcp6-protocol.h"
#include "network-internal.h"
+#include "siphash24.h"
+#include "sparse-endian.h"
+#include "udev-util.h"
+#include "virt.h"
#define SYSTEMD_PEN 43793
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
@@ -58,7 +56,6 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
return 0;
}
-
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
/* name is a pointer to memory in the udev_device struct, so must
have the same scope */
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h
index 95117915f4..2291736f8b 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-identifier.h
@@ -21,11 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-id128.h"
#include "macro.h"
#include "sparse-endian.h"
#include "unaligned.h"
-#include "sd-id128.h"
/* RFC 3315 section 9.1:
* A DUID can be no more than 128 octets long (not including the type code).
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index df6f882af5..a5daaa543a 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -22,15 +22,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdint.h>
#include <linux/if_packet.h>
-#include <net/if_arp.h>
#include <net/ethernet.h>
-
-#include "socket-util.h"
+#include <net/if_arp.h>
+#include <stdint.h>
#include "sd-dhcp-client.h"
+
#include "dhcp-protocol.h"
+#include "socket-util.h"
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr,
diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c
index 7f10838de1..fac25e0fa2 100644
--- a/src/libsystemd-network/dhcp-network.c
+++ b/src/libsystemd-network/dhcp-network.c
@@ -18,18 +18,18 @@
***/
#include <errno.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <linux/if_packet.h>
-#include <linux/if_infiniband.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
#include <linux/filter.h>
-
-#include "socket-util.h"
+#include <linux/if_infiniband.h>
+#include <linux/if_packet.h>
#include "dhcp-internal.h"
+#include "fd-util.h"
+#include "socket-util.h"
static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
uint32_t xid, const uint8_t *mac_addr,
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index 5dc3c7aa26..3b88b93d9a 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -96,5 +96,5 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
DHCPRequest *req, DHCPPacket *packet,
int type, size_t optoffset);
-unsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
+void client_id_hash_func(const void *p, struct siphash *state);
int client_id_compare_func(const void *_a, const void *_b);
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 83e8192f58..ecc220f2f6 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -24,10 +24,11 @@
#include <net/ethernet.h>
#include <netinet/in.h>
-#include "sparse-endian.h"
#include "sd-event.h"
+
#include "list.h"
#include "macro.h"
+#include "sparse-endian.h"
typedef struct DHCP6Address DHCP6Address;
@@ -58,9 +59,6 @@ typedef struct DHCP6IA DHCP6IA;
#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
-int dhcp_network_icmp6_bind_router_solicitation(int index);
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
-
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia);
diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c
index 187975364b..318ee9c4b4 100644
--- a/src/libsystemd-network/dhcp6-network.c
+++ b/src/libsystemd-network/dhcp6-network.c
@@ -18,116 +18,19 @@
***/
#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <linux/if_packet.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <netinet/ip6.h>
-#include <netinet/icmp6.h>
-#include <netinet/in.h>
-
-#include "socket-util.h"
+#include <linux/if_packet.h>
#include "dhcp6-internal.h"
#include "dhcp6-protocol.h"
-
-#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
- { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
-
-#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
- { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
-
-int dhcp_network_icmp6_bind_router_solicitation(int index) {
- struct icmp6_filter filter = { };
- struct ipv6_mreq mreq = {
- .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
- .ipv6mr_interface = index,
- };
- _cleanup_close_ int s = -1;
- int r, zero = 0, hops = 255;
-
- s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
- IPPROTO_ICMPV6);
- if (s < 0)
- return -errno;
-
- ICMP6_FILTER_SETBLOCKALL(&filter);
- ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
- r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
- sizeof(filter));
- if (r < 0)
- return -errno;
-
- /* RFC 3315, section 6.7, bullet point 2 may indicate that an
- IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
- Empirical experiments indicates otherwise and therefore an
- IPV6_MULTICAST_IF socket option is used here instead */
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
- sizeof(index));
- if (r < 0)
- return -errno;
-
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
- sizeof(zero));
- if (r < 0)
- return -errno;
-
- r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
- sizeof(hops));
- if (r < 0)
- return -errno;
-
- r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq));
- if (r < 0)
- return -errno;
-
- r = s;
- s = -1;
- return r;
-}
-
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
- struct sockaddr_in6 dst = {
- .sin6_family = AF_INET6,
- .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
- };
- struct {
- struct nd_router_solicit rs;
- struct nd_opt_hdr rs_opt;
- struct ether_addr rs_opt_mac;
- } _packed_ rs = {
- .rs.nd_rs_type = ND_ROUTER_SOLICIT,
- };
- struct iovec iov[1] = {
- { &rs, },
- };
- struct msghdr msg = {
- .msg_name = &dst,
- .msg_namelen = sizeof(dst),
- .msg_iov = iov,
- .msg_iovlen = 1,
- };
- int r;
-
- if (ether_addr) {
- memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
- rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
- rs.rs_opt.nd_opt_len = 1;
- iov[0].iov_len = sizeof(rs);
- } else
- iov[0].iov_len = sizeof(rs.rs);
-
- r = sendmsg(s, &msg, 0);
- if (r < 0)
- return -errno;
-
- return 0;
-}
+#include "fd-util.h"
+#include "socket-util.h"
int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
struct in6_pktinfo pktinfo = {
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index f41bebced0..0f46df6a1b 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -23,14 +23,14 @@
#include <errno.h>
#include <string.h>
-#include "sparse-endian.h"
-#include "unaligned.h"
-#include "util.h"
-#include "strv.h"
-
+#include "alloc-util.h"
#include "dhcp6-internal.h"
#include "dhcp6-protocol.h"
#include "dns-domain.h"
+#include "sparse-endian.h"
+#include "strv.h"
+#include "unaligned.h"
+#include "util.h"
#define DHCP6_OPTION_IA_NA_LEN 12
#define DHCP6_OPTION_IA_TA_LEN 4
@@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
int r;
assert_return(optlen > 1, -ENODATA);
- assert_return(optval[optlen] == '\0', -EINVAL);
+ assert_return(optval[optlen - 1] == '\0', -EINVAL);
while (pos < optlen) {
_cleanup_free_ char *ret = NULL;
diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c
new file mode 100644
index 0000000000..91308bf6c3
--- /dev/null
+++ b/src/libsystemd-network/icmp6-util.c
@@ -0,0 +1,129 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <linux/if_packet.h>
+
+#include "fd-util.h"
+#include "icmp6-util.h"
+#include "socket-util.h"
+
+#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
+ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
+
+#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
+ { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
+
+int icmp6_bind_router_solicitation(int index) {
+ struct icmp6_filter filter = { };
+ struct ipv6_mreq mreq = {
+ .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
+ .ipv6mr_interface = index,
+ };
+ _cleanup_close_ int s = -1;
+ int r, zero = 0, hops = 255;
+
+ s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ IPPROTO_ICMPV6);
+ if (s < 0)
+ return -errno;
+
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+ r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
+ sizeof(filter));
+ if (r < 0)
+ return -errno;
+
+ /* RFC 3315, section 6.7, bullet point 2 may indicate that an
+ IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
+ Empirical experiments indicates otherwise and therefore an
+ IPV6_MULTICAST_IF socket option is used here instead */
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index,
+ sizeof(index));
+ if (r < 0)
+ return -errno;
+
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero,
+ sizeof(zero));
+ if (r < 0)
+ return -errno;
+
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops,
+ sizeof(hops));
+ if (r < 0)
+ return -errno;
+
+ r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq));
+ if (r < 0)
+ return -errno;
+
+ r = s;
+ s = -1;
+ return r;
+}
+
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+ struct sockaddr_in6 dst = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
+ };
+ struct {
+ struct nd_router_solicit rs;
+ struct nd_opt_hdr rs_opt;
+ struct ether_addr rs_opt_mac;
+ } _packed_ rs = {
+ .rs.nd_rs_type = ND_ROUTER_SOLICIT,
+ };
+ struct iovec iov[1] = {
+ { &rs, },
+ };
+ struct msghdr msg = {
+ .msg_name = &dst,
+ .msg_namelen = sizeof(dst),
+ .msg_iov = iov,
+ .msg_iovlen = 1,
+ };
+ int r;
+
+ if (ether_addr) {
+ memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN);
+ rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+ rs.rs_opt.nd_opt_len = 1;
+ iov[0].iov_len = sizeof(rs);
+ } else
+ iov[0].iov_len = sizeof(rs.rs);
+
+ r = sendmsg(s, &msg, 0);
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/src/libsystemd-network/icmp6-util.h b/src/libsystemd-network/icmp6-util.h
new file mode 100644
index 0000000000..4eb17e152e
--- /dev/null
+++ b/src/libsystemd-network/icmp6-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 (C) 2014-2015 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <net/ethernet.h>
+
+int icmp6_bind_router_solicitation(int index);
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c
index 3c04898e92..583be2f55d 100644
--- a/src/libsystemd-network/lldp-internal.c
+++ b/src/libsystemd-network/lldp-internal.c
@@ -20,6 +20,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-lldp.h"
+
+#include "alloc-util.h"
#include "lldp-internal.h"
/* We store maximum 1K chassis entries */
@@ -28,207 +31,6 @@
/* Maximum Ports can be attached to any chassis */
#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
-int lldp_read_chassis_id(tlv_packet *tlv,
- uint8_t *type,
- uint16_t *length,
- uint8_t **data) {
- uint8_t subtype;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
- if (r < 0)
- goto out2;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out1;
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out1;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out1:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out2:
- return r;
-}
-
-int lldp_read_port_id(tlv_packet *tlv,
- uint8_t *type,
- uint16_t *length,
- uint8_t **data) {
- uint8_t subtype;
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
- if (r < 0)
- goto out2;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out1;
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
- case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out1;
-
- *data = (uint8_t *) s;
-
- break;
- case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out1;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out1:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out2:
- return r;
-}
-
-int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_TTL);
- if (r < 0)
- goto out;
-
- r = tlv_packet_read_u16(tlv, ttl);
-
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out:
- return r;
-}
-
-int lldp_read_system_name(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_NAME);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_system_description(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_port_description(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_DESCRIPTION);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) {
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, data);
- if (r < 0)
- goto out;
-
- return 0;
- out:
-
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
/* 10.5.5.2.2 mibUpdateObjects ()
* The mibUpdateObjects () procedure updates the MIB objects corresponding to
* the TLVs contained in the received LLDPDU for the LLDP remote system
@@ -244,7 +46,7 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -253,13 +55,13 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
- tlv_packet_free(p->packet);
+ sd_lldp_packet_unref(p->packet);
p->packet = tlv;
prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
@@ -281,7 +83,7 @@ int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -312,11 +114,11 @@ int lldp_mib_add_objects(Prioq *by_expiry,
assert_return(neighbour_mib, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_chassis_id(tlv, &subtype, &length, &data);
+ r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length);
if (r < 0)
goto drop;
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
goto drop;
@@ -401,7 +203,7 @@ int lldp_mib_add_objects(Prioq *by_expiry,
return 0;
drop:
- tlv_packet_free(tlv);
+ sd_lldp_packet_unref(tlv);
if (new_chassis)
hashmap_remove(neighbour_mib, &c->chassis_id);
@@ -435,7 +237,7 @@ void lldp_neighbour_port_free(lldp_neighbour_port *p) {
if(!p)
return;
- tlv_packet_free(p->packet);
+ sd_lldp_packet_unref(p->packet);
free(p->data);
free(p);
@@ -452,11 +254,11 @@ int lldp_neighbour_port_new(lldp_chassis *c,
assert(tlv);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
@@ -505,7 +307,7 @@ int lldp_chassis_new(tlv_packet *tlv,
assert(tlv);
- r = lldp_read_chassis_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -531,3 +333,30 @@ int lldp_chassis_new(tlv_packet *tlv,
return 0;
}
+
+int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ _cleanup_lldp_packet_unref_ tlv_packet *packet = NULL;
+ tlv_packet *p;
+ uint16_t length;
+ int r;
+
+ assert(fd);
+ assert(userdata);
+
+ r = tlv_packet_new(&packet);
+ if (r < 0)
+ return r;
+
+ length = read(fd, &packet->pdu, sizeof(packet->pdu));
+
+ /* Silently drop the packet */
+ if ((size_t) length > ETHER_MAX_LEN)
+ return 0;
+
+ packet->userdata = userdata;
+
+ p = packet;
+ packet = NULL;
+
+ return lldp_handle_packet(p, (uint16_t) length);
+}
diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h
index f4eadbb87e..5d19fa0fea 100644
--- a/src/libsystemd-network/lldp-internal.h
+++ b/src/libsystemd-network/lldp-internal.h
@@ -22,9 +22,11 @@
#pragma once
-#include "log.h"
+#include "sd-event.h"
+
#include "list.h"
#include "lldp-tlv.h"
+#include "log.h"
#include "prioq.h"
typedef struct lldp_neighbour_port lldp_neighbour_port;
@@ -86,13 +88,6 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv);
int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv);
int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv);
-int lldp_read_chassis_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data);
-int lldp_read_port_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data);
-int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl);
-int lldp_read_system_name(tlv_packet *tlv, uint16_t *length, char **data);
-int lldp_read_system_description(tlv_packet *tlv, uint16_t *length, char **data);
-int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data);
-int lldp_read_port_description(tlv_packet *tlv, uint16_t *length, char **data);
-
int lldp_handle_packet(tlv_packet *m, uint16_t length);
+int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c
index 664d2f7867..f483cd9c8e 100644
--- a/src/libsystemd-network/lldp-network.c
+++ b/src/libsystemd-network/lldp-network.c
@@ -23,10 +23,11 @@
#include <linux/filter.h>
#include <linux/if_ether.h>
-#include "socket-util.h"
-#include "lldp-tlv.h"
-#include "lldp-network.h"
+#include "fd-util.h"
#include "lldp-internal.h"
+#include "lldp-network.h"
+#include "lldp-tlv.h"
+#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
typedef struct LLDPFrame {
@@ -82,30 +83,3 @@ int lldp_network_bind_raw_socket(int ifindex) {
return r;
}
-
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_tlv_packet_free_ tlv_packet *packet = NULL;
- tlv_packet *p;
- uint16_t length;
- int r;
-
- assert(fd);
- assert(userdata);
-
- r = tlv_packet_new(&packet);
- if (r < 0)
- return r;
-
- length = read(fd, &packet->pdu, sizeof(packet->pdu));
-
- /* Silently drop the packet */
- if ((size_t) length > ETHER_MAX_LEN)
- return 0;
-
- packet->userdata = userdata;
-
- p = packet;
- packet = NULL;
-
- return lldp_handle_packet(p, (uint16_t) length);
-}
diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h
index b7f8d3bf80..74ee13a414 100644
--- a/src/libsystemd-network/lldp-network.h
+++ b/src/libsystemd-network/lldp-network.h
@@ -25,4 +25,3 @@
#include "sd-event.h"
int lldp_network_bind_raw_socket(int ifindex);
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c
index aa6a3b9224..97b6b485d2 100644
--- a/src/libsystemd-network/lldp-port.c
+++ b/src/libsystemd-network/lldp-port.c
@@ -20,9 +20,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "async.h"
#include "lldp-port.h"
#include "lldp-network.h"
+#include "lldp-internal.h"
int lldp_port_start(lldp_port *p) {
int r;
@@ -38,19 +40,19 @@ int lldp_port_start(lldp_port *p) {
r = sd_event_add_io(p->event, &p->lldp_port_rx,
p->rawfd, EPOLLIN, lldp_receive_packet, p);
if (r < 0) {
- log_debug("Failed to allocate event source: %s", strerror(-r));
- return r;
+ log_debug_errno(r, "Failed to allocate event source: %m");
+ goto fail;
}
r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority);
if (r < 0) {
- log_debug("Failed to set event priority: %s", strerror(-r));
+ log_debug_errno(r, "Failed to set event priority: %m");
goto fail;
}
r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx");
if (r < 0) {
- log_debug("Failed to set event name: %s", strerror(-r));
+ log_debug_errno(r, "Failed to set event name: %m");
goto fail;
}
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
index 0cea5b10a6..a539b5dfea 100644
--- a/src/libsystemd-network/lldp-tlv.c
+++ b/src/libsystemd-network/lldp-tlv.c
@@ -23,8 +23,9 @@
#include <net/ethernet.h>
#include <arpa/inet.h>
-#include "macro.h"
+#include "alloc-util.h"
#include "lldp-tlv.h"
+#include "macro.h"
int tlv_section_new(tlv_section **ret) {
tlv_section *s;
@@ -54,22 +55,41 @@ int tlv_packet_new(tlv_packet **ret) {
return -ENOMEM;
LIST_HEAD_INIT(m->sections);
+ m->n_ref = 1;
*ret = m;
return 0;
}
-void tlv_packet_free(tlv_packet *m) {
+tlv_packet *sd_lldp_packet_ref(tlv_packet *m) {
+
+ if (!m)
+ return NULL;
+
+ assert(m->n_ref > 0);
+ m->n_ref++;
+
+ return m;
+}
+
+tlv_packet *sd_lldp_packet_unref(tlv_packet *m) {
tlv_section *s, *n;
if (!m)
- return;
+ return NULL;
+
+ assert(m->n_ref > 0);
+ m->n_ref--;
+
+ if (m->n_ref > 0)
+ return m;
LIST_FOREACH_SAFE(section, s, n, m->sections)
tlv_section_free(s);
free(m);
+ return NULL;
}
int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) {
@@ -221,9 +241,9 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
return r;
*data = (char *) val;
- *data_length = m->container->length;
+ *data_length = m->container->data + m->container->length - m->container->read_pos;
- m->container->read_pos += m->container->length;
+ m->container->read_pos += *data_length;
return 0;
}
@@ -239,9 +259,9 @@ int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length)
return r;
*data = (uint8_t *) val;
- *data_length = m->container->length;
+ *data_length = m->container->data + m->container->length - m->container->read_pos;
- m->container->read_pos += m->container->length;
+ m->container->read_pos += *data_length;
return 0;
}
@@ -258,7 +278,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
p = m->pdu;
- /* extract ethernet herader */
+ /* extract Ethernet header */
memcpy(&m->mac, p, ETH_ALEN);
p += sizeof(struct ether_header);
@@ -278,6 +298,17 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
}
p += 2;
+
+ if (section->type == LLDP_TYPE_PRIVATE &&
+ section->length >= LLDP_OUI_LEN + 1) {
+ section->oui = p;
+ p += LLDP_OUI_LEN;
+ section->subtype = *p++;
+
+ section->length -= LLDP_OUI_LEN + 1;
+ l += LLDP_OUI_LEN + 1;
+ }
+
section->data = p;
LIST_FIND_TAIL(section, m->sections, tail);
@@ -294,6 +325,7 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
tlv_section *s;
assert_return(m, -EINVAL);
+ assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL);
LIST_FOREACH(section, s, m->sections)
if (s->type == type)
@@ -305,7 +337,35 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
m->container->read_pos = s->data;
if (!m->container->read_pos) {
- m->container = 0;
+ m->container = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) {
+ tlv_section *s;
+
+ assert_return(m, -EINVAL);
+ assert_return(oui, -EINVAL);
+
+ LIST_FOREACH(section, s, m->sections) {
+ if (s->type == LLDP_TYPE_PRIVATE &&
+ s->oui &&
+ s->subtype == subtype &&
+ !memcmp(s->oui, oui, LLDP_OUI_LEN))
+ break;
+ }
+
+ if (!s)
+ return -1;
+
+ m->container = s;
+
+ m->container->read_pos = s->data;
+ if (!m->container->read_pos) {
+ m->container = NULL;
return -1;
}
@@ -319,3 +379,270 @@ int lldp_tlv_packet_exit_container(tlv_packet *m) {
return 0;
}
+
+static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, type);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, value);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) {
+ char *s;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, type);
+ if (r < 0)
+ return r;
+
+ r = tlv_packet_read_string(tlv, &s, length);
+ if (r < 0)
+ goto out;
+
+ *data = (char *) s;
+
+ out:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
+ uint8_t *type,
+ uint8_t **data,
+ uint16_t *length) {
+ uint8_t subtype;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
+ if (r < 0)
+ goto out2;
+
+ r = tlv_packet_read_u8(tlv, &subtype);
+ if (r < 0)
+ goto out1;
+
+ switch (subtype) {
+ case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
+
+ r = tlv_packet_read_bytes(tlv, data, length);
+ if (r < 0)
+ goto out1;
+
+ break;
+ default:
+ r = -EOPNOTSUPP;
+ break;
+ }
+
+ *type = subtype;
+
+ out1:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out2:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_port_id(tlv_packet *tlv,
+ uint8_t *type,
+ uint8_t **data,
+ uint16_t *length) {
+ uint8_t subtype;
+ char *s;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
+ if (r < 0)
+ goto out2;
+
+ r = tlv_packet_read_u8(tlv, &subtype);
+ if (r < 0)
+ goto out1;
+
+ switch (subtype) {
+ case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
+ case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
+ case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
+ case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
+
+ r = tlv_packet_read_string(tlv, &s, length);
+ if (r < 0)
+ goto out1;
+
+ *data = (uint8_t *) s;
+
+ break;
+ case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
+
+ r = tlv_packet_read_bytes(tlv, data, length);
+ if (r < 0)
+ goto out1;
+
+ break;
+ default:
+ r = -EOPNOTSUPP;
+ break;
+ }
+
+ *type = subtype;
+
+ out1:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out2:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
+ return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl);
+}
+
+int sd_lldp_packet_read_system_name(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length);
+}
+
+int sd_lldp_packet_read_system_description(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length);
+}
+
+int sd_lldp_packet_read_port_description(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length);
+}
+
+int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) {
+ return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data);
+}
+
+int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, id);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u8(tlv, flags);
+ if (r >= 0)
+ r = tlv_packet_read_u16(tlv, id);
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) {
+ int r, r2;
+ uint8_t len = 0;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, vlan_id);
+ if (r >= 0)
+ r = tlv_packet_read_u8(tlv, &len);
+ if (r >= 0)
+ r = tlv_packet_read_string(tlv, name, length);
+
+ if (r >= 0 && len < *length)
+ *length = len;
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, id);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u8(tlv, status);
+ if (r >= 0)
+ r = tlv_packet_read_u32(tlv, id);
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) {
+ assert_return(tlv, -EINVAL);
+ assert_return(dest, -EINVAL);
+
+ /* 802.1AB-2009, Table 7-1 */
+ if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE;
+ else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE;
+ else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE;
+ else
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h
index ce3334e115..ca1da113d5 100644
--- a/src/libsystemd-network/lldp-tlv.h
+++ b/src/libsystemd-network/lldp-tlv.h
@@ -28,12 +28,18 @@
#include "lldp.h"
#include "list.h"
-typedef struct tlv_packet tlv_packet;
-typedef struct tlv_section tlv_section;
+#include "sd-lldp.h"
-struct tlv_section {
+typedef struct sd_lldp_packet tlv_packet;
+typedef struct sd_lldp_section tlv_section;
+
+#define LLDP_OUI_LEN 3
+
+struct sd_lldp_section {
uint16_t type;
uint16_t length;
+ uint8_t *oui;
+ uint8_t subtype;
uint8_t *read_pos;
uint8_t *data;
@@ -41,10 +47,16 @@ struct tlv_section {
LIST_FIELDS(tlv_section, section);
};
+#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
+#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
+#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }
+
int tlv_section_new(tlv_section **ret);
void tlv_section_free(tlv_section *ret);
-struct tlv_packet {
+struct sd_lldp_packet {
+ unsigned n_ref;
+
uint16_t type;
uint16_t length;
usec_t ts;
@@ -61,10 +73,9 @@ struct tlv_packet {
};
int tlv_packet_new(tlv_packet **ret);
-void tlv_packet_free(tlv_packet *m);
-DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_free);
-#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_freep)
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref);
+#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp)
int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type);
int lldp_tlv_packet_close_container(tlv_packet *m);
@@ -76,6 +87,7 @@ int tlv_packet_append_u32(tlv_packet *m, uint32_t data);
int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size);
int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type);
+int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype);
int lldp_tlv_packet_exit_container(tlv_packet *m);
int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length);
diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h
index 5e4b283e26..19e5cc5f41 100644
--- a/src/libsystemd-network/lldp.h
+++ b/src/libsystemd-network/lldp.h
@@ -113,3 +113,16 @@ typedef enum LLDPMedCapability {
LLDP_MED_CAPABILITY_MAX,
LLDP_MED_CAPABILITY_INVALID = -1,
} LLDPMedCapability;
+
+#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
+#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
+
+enum {
+ LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1,
+ LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2,
+ LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3,
+ LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4,
+ LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5,
+ LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6,
+ LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7,
+};
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index fab4ddbde4..52d76e443e 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -19,20 +19,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
-#include <linux/if.h>
#include <arpa/inet.h>
+#include <linux/if.h>
+#include <netinet/ether.h>
-#include "strv.h"
-#include "siphash24.h"
+#include "sd-ndisc.h"
+
+#include "alloc-util.h"
+#include "condition.h"
+#include "conf-parser.h"
#include "dhcp-lease-internal.h"
#include "log.h"
+#include "network-internal.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "siphash24.h"
+#include "string-util.h"
+#include "strv.h"
#include "utf8.h"
#include "util.h"
-#include "conf-parser.h"
-#include "condition.h"
-#include "network-internal.h"
-#include "sd-icmp6-nd.h"
const char *net_get_name(struct udev_device *device) {
const char *name, *field;
@@ -196,8 +201,7 @@ int config_parse_ifname(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
return 0;
}
@@ -240,8 +244,7 @@ int config_parse_ifnames(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
free(n);
return 0;
}
@@ -278,8 +281,7 @@ int config_parse_ifalias(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
return 0;
}
@@ -324,8 +326,7 @@ int config_parse_hwaddr(const char *unit,
&n->ether_addr_octet[4],
&n->ether_addr_octet[5]);
if (r != 6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
return 0;
}
@@ -394,8 +395,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
assert(size);
for (i = 0; i < size; i++)
- fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
+ fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s",
+ SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]),
(i < (size - 1)) ? " ": "");
}
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 141b836a0d..137537253a 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -17,24 +17,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
-#include <linux/if_infiniband.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
+#include <linux/if_infiniband.h>
-#include "util.h"
-#include "random-util.h"
-#include "async.h"
+#include "sd-dhcp-client.h"
-#include "dhcp-protocol.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "dhcp-identifier.h"
#include "dhcp-internal.h"
#include "dhcp-lease-internal.h"
-#include "dhcp-identifier.h"
-#include "sd-dhcp-client.h"
+#include "dhcp-protocol.h"
+#include "random-util.h"
+#include "string-util.h"
+#include "util.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -1265,8 +1267,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "lease expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now)
@@ -1292,8 +1293,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t2_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now)
@@ -1318,8 +1318,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t1_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
return 0;
}
@@ -1518,7 +1517,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
expected_hlen = ETH_ALEN;
expected_chaddr = (const struct ether_addr *) &client->mac_addr;
} else {
- /* Non-ethernet links expect zero chaddr */
+ /* Non-Ethernet links expect zero chaddr */
expected_hlen = 0;
expected_chaddr = &zero_mac;
}
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index aa07846693..8befedc500 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -18,21 +18,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <arpa/inet.h>
#include <errno.h>
-#include <string.h>
#include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-dhcp-lease.h"
+#include "alloc-util.h"
+#include "dhcp-lease-internal.h"
+#include "dhcp-protocol.h"
+#include "dns-domain.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "unaligned.h"
-#include "in-addr-util.h"
+#include "hexdecoct.h"
#include "hostname-util.h"
-#include "dns-domain.h"
+#include "in-addr-util.h"
#include "network-internal.h"
-#include "dhcp-protocol.h"
-#include "dhcp-lease-internal.h"
-#include "sd-dhcp-lease.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "unaligned.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
@@ -314,10 +320,14 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
else {
char *string;
- if (memchr(option, 0, len))
+ /*
+ * One trailing NUL byte is OK, we don't mind. See:
+ * https://github.com/systemd/systemd/issues/1337
+ */
+ if (memchr(option, 0, len - 1))
return -EINVAL;
- string = strndup((const char *)option, len);
+ string = strndup((const char *) option, len);
if (!string)
return -ENOMEM;
@@ -941,19 +951,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (address) {
r = inet_pton(AF_INET, address, &lease->address);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address);
+ log_debug("Failed to parse address %s, ignoring.", address);
}
if (router) {
r = inet_pton(AF_INET, router, &lease->router);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router);
+ log_debug("Failed to parse router %s, ignoring.", router);
}
if (netmask) {
r = inet_pton(AF_INET, netmask, &lease->subnet_mask);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask);
+ log_debug("Failed to parse netmask %s, ignoring.", netmask);
else
lease->have_subnet_mask = true;
}
@@ -961,19 +971,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
if (server_address) {
r = inet_pton(AF_INET, server_address, &lease->server_address);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address);
+ log_debug("Failed to parse server address %s, ignoring.", server_address);
}
if (next_server) {
r = inet_pton(AF_INET, next_server, &lease->next_server);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server);
+ log_debug("Failed to parse next server %s, ignoring.", next_server);
}
if (broadcast) {
r = inet_pton(AF_INET, broadcast, &lease->broadcast);
if (r <= 0)
- log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast);
+ log_debug("Failed to parse broadcast address %s, ignoring.", broadcast);
else
lease->have_broadcast = true;
}
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 1f167485e3..8d0d9955c3 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -22,12 +22,15 @@
#include <sys/ioctl.h>
-#include "in-addr-util.h"
-#include "siphash24.h"
-
#include "sd-dhcp-server.h"
-#include "dhcp-server-internal.h"
+
+#include "alloc-util.h"
#include "dhcp-internal.h"
+#include "dhcp-server-internal.h"
+#include "fd-util.h"
+#include "in-addr-util.h"
+#include "siphash24.h"
+#include "string-util.h"
#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
@@ -93,7 +96,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
return 0;
}
-bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
+int sd_dhcp_server_is_running(sd_dhcp_server *server) {
assert_return(server, false);
return !!server->receive_message;
@@ -110,18 +113,15 @@ sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
return server;
}
-unsigned long client_id_hash_func(const void *p,
- const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
+void client_id_hash_func(const void *p, struct siphash *state) {
const DHCPClientId *id = p;
assert(id);
assert(id->length);
assert(id->data);
- siphash24((uint8_t*) &u, id->data, id->length, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&id->length, sizeof(id->length), state);
+ siphash24_compress(id->data, id->length, state);
}
int client_id_compare_func(const void *_a, const void *_b) {
@@ -743,13 +743,18 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (existing_lease)
address = existing_lease->address;
else {
+ struct siphash state;
+ uint64_t hash;
uint32_t next_offer;
/* even with no persistence of leases, we try to offer the same client
the same IP address. we do this by using the hash of the client id
as the offset into the pool of leases when finding the next free one */
- next_offer = client_id_hash_func(&req->client_id, HASH_KEY.bytes) % server->pool_size;
+ siphash24_init(&state, HASH_KEY.bytes);
+ client_id_hash_func(&req->client_id, &state);
+ siphash24_finalize((uint8_t*)&hash, &state);
+ next_offer = hash % server->pool_size;
for (i = 0; i < server->pool_size; i++) {
if (!server->bound_leases[next_offer]) {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index acb31a16c2..e29de60d24 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -24,17 +24,18 @@
#include <sys/ioctl.h>
#include <linux/if_infiniband.h>
-#include "udev.h"
-#include "udev-util.h"
-#include "util.h"
-#include "random-util.h"
-
-#include "network-internal.h"
#include "sd-dhcp6-client.h"
-#include "dhcp6-protocol.h"
+
+#include "alloc-util.h"
+#include "dhcp-identifier.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
-#include "dhcp-identifier.h"
+#include "dhcp6-protocol.h"
+#include "fd-util.h"
+#include "network-internal.h"
+#include "random-util.h"
+#include "string-table.h"
+#include "util.h"
#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
@@ -208,9 +209,8 @@ int sd_dhcp6_client_set_duid(
return 0;
}
-int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) {
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) {
assert_return(client, -EINVAL);
-
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
client->information_request = enabled;
@@ -218,7 +218,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable
return 0;
}
-int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) {
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) {
assert_return(client, -EINVAL);
assert_return(enabled, -EINVAL);
@@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
}
log_dhcp6_client(client, "Next retransmission in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- client->retransmit_time, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
@@ -1048,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t1,
@@ -1072,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
log_dhcp6_client(client, "T2 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t2,
diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c
index f34af6eaba..3f32ba35e7 100644
--- a/src/libsystemd-network/sd-dhcp6-lease.c
+++ b/src/libsystemd-network/sd-dhcp6-lease.c
@@ -22,11 +22,11 @@
#include <errno.h>
-#include "strv.h"
-#include "util.h"
-
+#include "alloc-util.h"
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
+#include "strv.h"
+#include "util.h"
int dhcp6_lease_clear_timers(DHCP6IA *ia) {
assert_return(ia, -EINVAL);
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index 95b96bfd52..5340fdc0c1 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -24,17 +24,19 @@
#include <stdlib.h>
#include <string.h>
+#include "sd-ipv4acd.h"
+
+#include "alloc-util.h"
+#include "arp-util.h"
#include "event-util.h"
+#include "fd-util.h"
#include "in-addr-util.h"
#include "list.h"
-#include "refcnt.h"
#include "random-util.h"
+#include "refcnt.h"
#include "siphash24.h"
#include "util.h"
-#include "arp-util.h"
-#include "sd-ipv4acd.h"
-
/* Constants from the RFC */
#define PROBE_WAIT 1
#define PROBE_NUM 3
@@ -468,7 +470,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
return 0;
}
-bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
+int sd_ipv4acd_is_running(sd_ipv4acd *ll) {
assert_return(ll, false);
return ll->state != IPV4ACD_STATE_INIT;
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index dd427ddd78..0d915e20e7 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -18,13 +18,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <arpa/inet.h>
#include <errno.h>
-#include <string.h>
#include <stdio.h>
-#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sd-ipv4acd.h"
+#include "sd-ipv4ll.h"
+#include "alloc-util.h"
#include "event-util.h"
+#include "in-addr-util.h"
#include "list.h"
#include "random-util.h"
#include "refcnt.h"
@@ -32,9 +37,6 @@
#include "sparse-endian.h"
#include "util.h"
-#include "sd-ipv4acd.h"
-#include "sd-ipv4ll.h"
-
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
@@ -226,12 +228,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
return 0;
}
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
+int sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, false);
return sd_ipv4acd_is_running(ll->acd);
}
+static bool ipv4ll_address_is_valid(const struct in_addr *address) {
+ uint32_t addr;
+
+ assert(address);
+
+ if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+ return false;
+
+ addr = be32toh(address->s_addr);
+
+ if ((addr & 0x0000FF00) == 0x0000 ||
+ (addr & 0x0000FF00) == 0xFF00)
+ return false;
+
+ return true;
+}
+
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ipv4ll_address_is_valid(address), -EINVAL);
+
+ r = sd_ipv4acd_set_address(ll->acd, address);
+ if (r < 0)
+ return r;
+
+ ll->address = address->s_addr;
+
+ return 0;
+}
+
static int ipv4ll_pick_address(sd_ipv4ll *ll) {
struct in_addr in_addr;
be32_t addr;
@@ -247,18 +282,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
return r;
addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
} while (addr == ll->address ||
- (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
(ntohl(addr) & 0x0000FF00) == 0x0000 ||
(ntohl(addr) & 0x0000FF00) == 0xFF00);
in_addr.s_addr = addr;
- r = sd_ipv4acd_set_address(ll->acd, &in_addr);
+ r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0)
return r;
- ll->address = addr;
-
return 0;
}
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 17512884f5..4ebe8053fa 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -22,15 +22,19 @@
#include <arpa/inet.h>
-#include "siphash24.h"
-#include "hashmap.h"
-
-#include "lldp-tlv.h"
-#include "lldp-port.h"
#include "sd-lldp.h"
-#include "prioq.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
#include "lldp-internal.h"
+#include "lldp-port.h"
+#include "lldp-tlv.h"
#include "lldp-util.h"
+#include "prioq.h"
+#include "siphash24.h"
+#include "string-util.h"
typedef enum LLDPAgentRXState {
LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
@@ -68,16 +72,14 @@ struct sd_lldp {
lldp_agent_statistics statistics;
};
-static unsigned long chassis_id_hash_func(const void *p,
- const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
+static void chassis_id_hash_func(const void *p, struct siphash *state) {
const lldp_chassis_id *id = p;
assert(id);
+ assert(id->data);
- siphash24((uint8_t *) &u, id->data, id->length, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&id->length, sizeof(id->length), state);
+ siphash24_compress(id->data, id->length, state);
}
static int chassis_id_compare_func(const void *_a, const void *_b) {
@@ -199,7 +201,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
goto out;
}
- /* skip type and lengh encoding */
+ /* skip type and length encoding */
p += 2;
q = p;
@@ -338,7 +340,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
lldp->statistics.stats_frames_in_errors_total ++;
}
- tlv_packet_free(tlv);
+ sd_lldp_packet_unref(tlv);
return 0;
}
@@ -455,7 +457,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
_cleanup_free_ char *s = NULL;
char *k, *t;
- r = lldp_read_chassis_id(p->packet, &type, &length, &mac);
+ r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length);
if (r < 0)
continue;
@@ -468,7 +470,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
goto fail;
}
- r = lldp_read_port_id(p->packet, &type, &length, &port_id);
+ r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length);
if (r < 0)
continue;
@@ -513,7 +515,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
free(s);
s = k;
- r = lldp_read_system_name(p->packet, &length, &k);
+ r = sd_lldp_packet_read_system_name(p->packet, &k, &length);
if (r < 0)
k = strappend(s, "'_NAME=N/A' ");
else {
@@ -535,7 +537,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
free(s);
s = k;
- (void) lldp_read_system_capability(p->packet, &data);
+ (void) sd_lldp_packet_read_system_capability(p->packet, &data);
sprintf(buf, "'_CAP=%x'", data);
@@ -702,3 +704,35 @@ int sd_lldp_new(int ifindex,
return 0;
}
+
+int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) {
+ lldp_neighbour_port *p;
+ lldp_chassis *c;
+ Iterator iter;
+ unsigned count = 0, i;
+
+ assert_return(lldp, -EINVAL);
+ assert_return(tlvs, -EINVAL);
+
+ HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
+ LIST_FOREACH(port, p, c->ports)
+ count++;
+ }
+
+ if (!count) {
+ *tlvs = NULL;
+ return 0;
+ }
+
+ *tlvs = new(sd_lldp_packet *, count);
+ if (!*tlvs)
+ return -ENOMEM;
+
+ i = 0;
+ HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
+ LIST_FOREACH(port, p, c->ports)
+ (*tlvs)[i++] = sd_lldp_packet_ref(p->packet);
+ }
+
+ return count;
+}
diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-ndisc.c
index bedcac8d9e..c494b9d6d8 100644
--- a/src/libsystemd-network/sd-icmp6-nd.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -18,65 +18,70 @@
***/
#include <netinet/icmp6.h>
+#include <netinet/in.h>
#include <netinet/ip6.h>
-#include <string.h>
#include <stdbool.h>
-#include <netinet/in.h>
+#include <string.h>
#include <sys/ioctl.h>
-#include "socket-util.h"
-#include "async.h"
+#include "sd-ndisc.h"
-#include "dhcp6-internal.h"
-#include "sd-icmp6-nd.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "icmp6-util.h"
+#include "list.h"
+#include "socket-util.h"
-#define ICMP6_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
-#define ICMP6_MAX_ROUTER_SOLICITATIONS 3
+#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC
+#define NDISC_MAX_ROUTER_SOLICITATIONS 3
-enum icmp6_nd_state {
- ICMP6_NEIGHBOR_DISCOVERY_IDLE = 0,
- ICMP6_ROUTER_SOLICITATION_SENT = 10,
- ICMP6_ROUTER_ADVERTISMENT_LISTEN = 11,
+enum NDiscState {
+ NDISC_STATE_IDLE,
+ NDISC_STATE_SOLICITATION_SENT,
+ NDISC_STATE_ADVERTISMENT_LISTEN,
+ _NDISC_STATE_MAX,
+ _NDISC_STATE_INVALID = -1,
};
#define IP6_MIN_MTU (unsigned)1280
-#define ICMP6_ND_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
-#define ICMP6_OPT_LEN_UNITS 8
+#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr))
+#define NDISC_OPT_LEN_UNITS 8
-typedef struct ICMP6Prefix ICMP6Prefix;
+typedef struct NDiscPrefix NDiscPrefix;
-struct ICMP6Prefix {
+struct NDiscPrefix {
unsigned n_ref;
- LIST_FIELDS(ICMP6Prefix, prefixes);
+ sd_ndisc *nd;
+
+ LIST_FIELDS(NDiscPrefix, prefixes);
uint8_t len;
- sd_event_source *timeout_valid;
+ usec_t valid_until;
struct in6_addr addr;
};
-struct sd_icmp6_nd {
+struct sd_ndisc {
unsigned n_ref;
- enum icmp6_nd_state state;
+ enum NDiscState state;
sd_event *event;
int event_priority;
int index;
struct ether_addr mac_addr;
uint32_t mtu;
- ICMP6Prefix *expired_prefix;
- LIST_HEAD(ICMP6Prefix, prefixes);
+ LIST_HEAD(NDiscPrefix, prefixes);
int fd;
sd_event_source *recv;
sd_event_source *timeout;
int nd_sent;
- sd_icmp6_nd_callback_t callback;
+ sd_ndisc_callback_t callback;
void *userdata;
};
-#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__)
-static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) {
+static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) {
if (!prefix)
return NULL;
@@ -87,22 +92,26 @@ static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) {
if (prefix->n_ref > 0)
return NULL;
- prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
+ if (prefix->nd)
+ LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix);
+
free(prefix);
+
return NULL;
}
-static int icmp6_prefix_new(ICMP6Prefix **ret) {
- _cleanup_free_ ICMP6Prefix *prefix = NULL;
+static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) {
+ _cleanup_free_ NDiscPrefix *prefix = NULL;
assert(ret);
- prefix = new0(ICMP6Prefix, 1);
+ prefix = new0(NDiscPrefix, 1);
if (!prefix)
return -ENOMEM;
prefix->n_ref = 1;
LIST_INIT(prefixes, prefix);
+ prefix->nd = nd;
*ret = prefix;
prefix = NULL;
@@ -110,12 +119,12 @@ static int icmp6_prefix_new(ICMP6Prefix **ret) {
return 0;
}
-static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) {
+static void ndisc_notify(sd_ndisc *nd, int event) {
if (nd->callback)
nd->callback(nd, event, nd->userdata);
}
-int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback,
+int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t callback,
void *userdata) {
assert(nd);
@@ -125,7 +134,7 @@ int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback,
return 0;
}
-int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) {
+int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) {
assert(nd);
assert(interface_index >= -1);
@@ -134,7 +143,7 @@ int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) {
return 0;
}
-int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) {
+int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
assert(nd);
if (mac_addr)
@@ -146,7 +155,7 @@ int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) {
}
-int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) {
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) {
int r;
assert_return(nd, -EINVAL);
@@ -165,7 +174,7 @@ int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) {
return 0;
}
-int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) {
+int sd_ndisc_detach_event(sd_ndisc *nd) {
assert_return(nd, -EINVAL);
nd->event = sd_event_unref(nd->event);
@@ -173,13 +182,13 @@ int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) {
return 0;
}
-sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) {
+sd_event *sd_ndisc_get_event(sd_ndisc *nd) {
assert(nd);
return nd->event;
}
-sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) {
+sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) {
if (!nd)
return NULL;
@@ -190,7 +199,7 @@ sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) {
return nd;
}
-static int icmp6_nd_init(sd_icmp6_nd *nd) {
+static int ndisc_init(sd_ndisc *nd) {
assert(nd);
nd->recv = sd_event_source_unref(nd->recv);
@@ -200,8 +209,8 @@ static int icmp6_nd_init(sd_icmp6_nd *nd) {
return 0;
}
-sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) {
- ICMP6Prefix *prefix, *p;
+sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) {
+ NDiscPrefix *prefix, *p;
if (!nd)
return NULL;
@@ -212,29 +221,26 @@ sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) {
if (nd->n_ref > 0)
return NULL;
- icmp6_nd_init(nd);
- sd_icmp6_nd_detach_event(nd);
-
- LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
- LIST_REMOVE(prefixes, nd->prefixes, prefix);
+ ndisc_init(nd);
+ sd_ndisc_detach_event(nd);
- prefix = icmp6_prefix_unref(prefix);
- }
+ LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes)
+ prefix = ndisc_prefix_unref(prefix);
free(nd);
return NULL;
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_icmp6_nd*, sd_icmp6_nd_unref);
-#define _cleanup_sd_icmp6_nd_free_ _cleanup_(sd_icmp6_nd_unrefp)
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref);
+#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp)
-int sd_icmp6_nd_new(sd_icmp6_nd **ret) {
- _cleanup_sd_icmp6_nd_free_ sd_icmp6_nd *nd = NULL;
+int sd_ndisc_new(sd_ndisc **ret) {
+ _cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL;
assert(ret);
- nd = new0(sd_icmp6_nd, 1);
+ nd = new0(sd_ndisc, 1);
if (!nd)
return -ENOMEM;
@@ -251,7 +257,7 @@ int sd_icmp6_nd_new(sd_icmp6_nd **ret) {
return 0;
}
-int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) {
+int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) {
assert_return(nd, -EINVAL);
assert_return(mtu, -EINVAL);
@@ -263,75 +269,9 @@ int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) {
return 0;
}
-static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec,
- void *userdata) {
- sd_icmp6_nd *nd = userdata;
- ICMP6Prefix *prefix, *p;
-
- assert(nd);
-
- LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
- if (prefix->timeout_valid != s)
- continue;
-
- log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
- prefix->len);
-
- LIST_REMOVE(prefixes, nd->prefixes, prefix);
-
- nd->expired_prefix = prefix;
- icmp6_nd_notify(nd,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED);
- nd->expired_prefix = NULL;
-
- prefix = icmp6_prefix_unref(prefix);
-
- break;
- }
-
- return 0;
-}
-
-static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd,
- ICMP6Prefix *prefix,
- usec_t valid) {
- usec_t time_now;
- int r;
-
- assert_return(prefix, -EINVAL);
-
- r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- return r;
-
- prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid);
-
- r = sd_event_add_time(nd->event, &prefix->timeout_valid,
- clock_boottime_or_monotonic(), time_now + valid,
- USEC_PER_SEC, icmp6_ra_prefix_timeout, nd);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_priority(prefix->timeout_valid,
- nd->event_priority);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_description(prefix->timeout_valid,
- "icmp6-prefix-timeout");
-
-error:
- if (r < 0)
- prefix->timeout_valid =
- sd_event_source_unref(prefix->timeout_valid);
-
- return r;
-}
-
-static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
- const struct in6_addr *addr,
- uint8_t addr_prefixlen) {
+static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
+ const struct in6_addr *addr,
+ uint8_t addr_prefixlen) {
uint8_t bytes, mask, len;
assert_return(prefix, -EINVAL);
@@ -349,69 +289,44 @@ static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen,
return 0;
}
-static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr,
- uint8_t addr_len, ICMP6Prefix **result) {
- ICMP6Prefix *prefix;
-
- LIST_FOREACH(prefixes, prefix, head) {
- if (icmp6_prefix_match(&prefix->addr, prefix->len, addr,
- addr_len) >= 0) {
- *result = prefix;
- return 0;
- }
- }
-
- return -EADDRNOTAVAIL;
-}
-
-int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
- struct in6_addr *addr) {
- return icmp6_prefix_match(prefix, prefixlen, addr,
- sizeof(addr->s6_addr) * 8);
-}
-
-int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
- uint8_t *prefixlen) {
+static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr,
+ uint8_t addr_len, NDiscPrefix **result) {
+ NDiscPrefix *prefix, *p;
+ usec_t time_now;
int r;
- ICMP6Prefix *prefix;
- assert_return(nd, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(prefixlen, -EINVAL);
+ assert(nd);
- r = icmp6_ra_prefix_match(nd->prefixes, addr,
- sizeof(addr->s6_addr) * 8, &prefix);
+ r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return r;
- *prefixlen = prefix->len;
-
- return 0;
-}
-
-int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) {
- assert_return(nd, -EINVAL);
- assert_return(addr, -EINVAL);
- assert_return(prefixlen, -EINVAL);
+ LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) {
+ if (prefix->valid_until < time_now) {
+ prefix = ndisc_prefix_unref(prefix);
- if (!nd->expired_prefix)
- return -EADDRNOTAVAIL;
+ continue;
+ }
- *addr = &nd->expired_prefix->addr;
- *prefixlen = nd->expired_prefix->len;
+ if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) {
+ *result = prefix;
+ return 0;
+ }
+ }
- return 0;
+ return -EADDRNOTAVAIL;
}
-static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
- const struct nd_opt_prefix_info *prefix_opt) {
- int r;
- ICMP6Prefix *prefix;
+static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len,
+ const struct nd_opt_prefix_info *prefix_opt) {
+ NDiscPrefix *prefix;
uint32_t lifetime;
+ usec_t time_now;
char time_string[FORMAT_TIMESPAN_MAX];
+ int r;
- assert_return(nd, -EINVAL);
- assert_return(prefix_opt, -EINVAL);
+ assert(nd);
+ assert(prefix_opt);
if (len < prefix_opt->nd_opt_pi_len)
return -ENOMSG;
@@ -421,9 +336,8 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
lifetime = be32toh(prefix_opt->nd_opt_pi_valid_time);
- r = icmp6_ra_prefix_match(nd->prefixes,
- &prefix_opt->nd_opt_pi_prefix,
- prefix_opt->nd_opt_pi_prefix_len, &prefix);
+ r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix,
+ prefix_opt->nd_opt_pi_prefix_len, &prefix);
if (r < 0 && r != -EADDRNOTAVAIL)
return r;
@@ -432,7 +346,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
callback will be called immediately to clean up the prefix */
if (r == -EADDRNOTAVAIL) {
- r = icmp6_prefix_new(&prefix);
+ r = ndisc_prefix_new(nd, &prefix);
if (r < 0)
return r;
@@ -441,11 +355,10 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
sizeof(prefix->addr));
- log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
+ log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+ SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
LIST_PREPEND(prefixes, nd->prefixes, prefix);
@@ -455,7 +368,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len);
- log_icmp6_nd(nd, "Prefix length mismatch %d/%d using %d",
+ log_ndisc(nd, "Prefix length mismatch %d/%d using %d",
prefix->len,
prefix_opt->nd_opt_pi_prefix_len,
prefixlen);
@@ -463,19 +376,22 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
prefix->len = prefixlen;
}
- log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
+ log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+ SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
}
- r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC);
+ r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
+ if (r < 0)
+ return r;
+
+ prefix->valid_until = time_now + lifetime * USEC_PER_SEC;
return r;
}
-static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
+static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra,
ssize_t len) {
void *opt;
struct nd_opt_hdr *opt_hdr;
@@ -484,8 +400,8 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
assert_return(ra, -EINVAL);
len -= sizeof(*ra);
- if (len < ICMP6_OPT_LEN_UNITS) {
- log_icmp6_nd(nd, "Router Advertisement below minimum length");
+ if (len < NDISC_OPT_LEN_UNITS) {
+ log_ndisc(nd, "Router Advertisement below minimum length");
return -ENOMSG;
}
@@ -493,7 +409,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
opt = ra + 1;
opt_hdr = opt;
- while (len != 0 && len >= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS) {
+ while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) {
struct nd_opt_mtu *opt_mtu;
uint32_t mtu;
struct nd_opt_prefix_info *opt_prefix;
@@ -510,7 +426,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
if (mtu != nd->mtu) {
nd->mtu = MAX(mtu, IP6_MIN_MTU);
- log_icmp6_nd(nd, "Router Advertisement link MTU %d using %d",
+ log_ndisc(nd, "Router Advertisement link MTU %d using %d",
mtu, nd->mtu);
}
@@ -519,29 +435,29 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra,
case ND_OPT_PREFIX_INFORMATION:
opt_prefix = opt;
- icmp6_ra_prefix_update(nd, len, opt_prefix);
+ ndisc_prefix_update(nd, len, opt_prefix);
break;
}
- len -= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS;
+ len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS;
opt = (void *)((char *)opt +
- opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS);
+ opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS);
opt_hdr = opt;
}
if (len > 0)
- log_icmp6_nd(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
+ log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len);
return 0;
}
-static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_icmp6_nd *nd = userdata;
+static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ sd_ndisc *nd = userdata;
int r, buflen = 0;
ssize_t len;
_cleanup_free_ struct nd_router_advert *ra = NULL;
- int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE;
+ int event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE;
assert(s);
assert(nd);
@@ -549,7 +465,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
r = ioctl(fd, FIONREAD, &buflen);
if (r < 0 || buflen <= 0)
- buflen = ICMP6_ND_RECV_SIZE;
+ buflen = ICMP6_RECV_SIZE;
ra = malloc(buflen);
if (!ra)
@@ -557,7 +473,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
len = read(fd, ra, buflen);
if (len < 0) {
- log_icmp6_nd(nd, "Could not receive message from UDP socket: %m");
+ log_ndisc(nd, "Could not receive message from UDP socket: %m");
return 0;
}
@@ -569,34 +485,34 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
nd->timeout = sd_event_source_unref(nd->timeout);
- nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
+ nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER )
- event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER;
+ event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER;
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
- event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED;
+ event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED;
- log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s",
+ log_ndisc(nd, "Received Router Advertisement flags %s/%s",
ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none",
ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none");
- if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) {
- r = icmp6_ra_parse(nd, ra, len);
+ if (event != SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE) {
+ r = ndisc_ra_parse(nd, ra, len);
if (r < 0) {
- log_icmp6_nd(nd, "Could not parse Router Advertisement: %s",
+ log_ndisc(nd, "Could not parse Router Advertisement: %s",
strerror(-r));
return 0;
}
}
- icmp6_nd_notify(nd, event);
+ ndisc_notify(nd, event);
return 0;
}
-static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_icmp6_nd *nd = userdata;
+static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_ndisc *nd = userdata;
uint64_t time_now, next_timeout;
struct ether_addr unset = { };
struct ether_addr *addr = NULL;
@@ -608,89 +524,80 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
nd->timeout = sd_event_source_unref(nd->timeout);
- if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) {
- icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
- nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
+ if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) {
+ ndisc_notify(nd, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
+ nd->state = NDISC_STATE_ADVERTISMENT_LISTEN;
} else {
if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
addr = &nd->mac_addr;
- r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr);
+ r = icmp6_send_router_solicitation(nd->fd, addr);
if (r < 0)
- log_icmp6_nd(nd, "Error sending Router Solicitation");
+ log_ndisc(nd, "Error sending Router Solicitation");
else {
- nd->state = ICMP6_ROUTER_SOLICITATION_SENT;
- log_icmp6_nd(nd, "Sent Router Solicitation");
+ nd->state = NDISC_STATE_SOLICITATION_SENT;
+ log_ndisc(nd, "Sent Router Solicitation");
}
nd->nd_sent++;
- r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0) {
- icmp6_nd_notify(nd, r);
- return 0;
- }
+ assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0);
- next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL;
+ next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL;
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
next_timeout, 0,
- icmp6_router_solicitation_timeout, nd);
+ ndisc_router_solicitation_timeout, nd);
if (r < 0) {
- icmp6_nd_notify(nd, r);
+ ndisc_notify(nd, r);
return 0;
}
- r = sd_event_source_set_priority(nd->timeout,
- nd->event_priority);
- if (r < 0) {
- icmp6_nd_notify(nd, r);
+ r = sd_event_source_set_priority(nd->timeout, nd->event_priority);
+ if (r < 0)
return 0;
- }
- r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
- if (r < 0) {
- icmp6_nd_notify(nd, r);
+ r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
+ if (r < 0)
return 0;
- }
}
return 0;
}
-int sd_icmp6_nd_stop(sd_icmp6_nd *nd) {
+int sd_ndisc_stop(sd_ndisc *nd) {
assert_return(nd, -EINVAL);
assert_return(nd->event, -EINVAL);
- log_icmp6_nd(client, "Stop ICMPv6");
+ log_ndisc(client, "Stop NDisc");
- icmp6_nd_init(nd);
+ ndisc_init(nd);
- nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE;
+ nd->state = NDISC_STATE_IDLE;
return 0;
}
-int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
+int sd_ndisc_router_discovery_start(sd_ndisc *nd) {
int r;
assert(nd);
assert(nd->event);
- if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE)
+ if (nd->state != NDISC_STATE_IDLE)
return -EINVAL;
if (nd->index < 1)
return -EINVAL;
- r = dhcp_network_icmp6_bind_router_solicitation(nd->index);
+ r = icmp6_bind_router_solicitation(nd->index);
if (r < 0)
return r;
nd->fd = r;
r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN,
- icmp6_router_advertisment_recv, nd);
+ ndisc_router_advertisment_recv, nd);
if (r < 0)
goto error;
@@ -698,12 +605,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
if (r < 0)
goto error;
- r = sd_event_source_set_description(nd->recv, "icmp6-receive-message");
+ r = sd_event_source_set_description(nd->recv, "ndisc-receive-message");
if (r < 0)
goto error;
r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(),
- 0, 0, icmp6_router_solicitation_timeout, nd);
+ 0, 0, ndisc_router_solicitation_timeout, nd);
if (r < 0)
goto error;
@@ -711,12 +618,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) {
if (r < 0)
goto error;
- r = sd_event_source_set_description(nd->timeout, "icmp6-timeout");
+ r = sd_event_source_set_description(nd->timeout, "ndisc-timeout");
error:
if (r < 0)
- icmp6_nd_init(nd);
+ ndisc_init(nd);
else
- log_icmp6_nd(client, "Start Router Solicitation");
+ log_ndisc(client, "Start Router Solicitation");
return r;
}
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
deleted file mode 100644
index 439d4eff38..0000000000
--- a/src/libsystemd-network/sd-pppoe.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/* See RFC 2516 */
-
-#include <sys/ioctl.h>
-#include <linux/ppp_defs.h>
-#include <linux/ppp-ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <linux/if_pppox.h>
-
-#include "sd-pppoe.h"
-
-#include "event-util.h"
-
-#include "util.h"
-#include "random-util.h"
-#include "socket-util.h"
-#include "async.h"
-#include "utf8.h"
-
-#define PPPOE_MAX_PACKET_SIZE 1484
-#define PPPOE_MAX_PADR_RESEND 16
-
-/* TODO: move this to socket-util.h without getting into
- * a mess with the includes */
-union sockaddr_union_pppox {
- struct sockaddr sa;
- struct sockaddr_pppox pppox;
-};
-
-typedef enum PPPoEState {
- PPPOE_STATE_INITIALIZING,
- PPPOE_STATE_REQUESTING,
- PPPOE_STATE_RUNNING,
- PPPOE_STATE_STOPPED,
- _PPPOE_STATE_MAX,
- _PPPOE_STATE_INVALID = -1,
-} PPPoEState;
-
-typedef struct PPPoETags {
- char *service_name;
- char *ac_name;
- uint8_t *host_uniq;
- size_t host_uniq_len;
- uint8_t *cookie;
- size_t cookie_len;
-} PPPoETags;
-
-struct sd_pppoe {
- unsigned n_ref;
-
- PPPoEState state;
- uint64_t host_uniq;
-
- int ifindex;
- char *ifname;
-
- sd_event *event;
- int event_priority;
- int fd;
- sd_event_source *io;
- sd_event_source *timeout;
- int padr_resend_count;
-
- char *service_name;
- struct ether_addr peer_mac;
- be16_t session_id;
-
- int pppoe_fd;
- int channel;
-
- sd_pppoe_cb_t cb;
- void *userdata;
-
- PPPoETags tags;
-};
-
-#define PPPOE_PACKET_LENGTH(header) \
- be16toh((header)->length)
-
-#define PPPOE_PACKET_TAIL(packet) \
- (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
-
-#define PPPOE_TAG_LENGTH(tag) \
- be16toh((tag)->tag_len)
-
-#define PPPOE_TAG_TYPE(tag) \
- (tag)->tag_type
-
-#define PPPOE_TAG_NEXT(tag) \
- (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag))
-
-#define PPPOE_TAGS_FOREACH(tag, header) \
- for (tag = (header)->tag; \
- ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) && \
- (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) && \
- (tag >= (header)->tag) && \
- (PPPOE_TAG_TYPE(tag) != PTT_EOL); \
- tag = PPPOE_TAG_NEXT(tag))
-
-static void pppoe_tags_clear(PPPoETags *tags) {
- free(tags->service_name);
- free(tags->ac_name);
- free(tags->host_uniq);
- free(tags->cookie);
-
- zero(*tags);
-}
-
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) {
- assert_return(ppp, -EINVAL);
- assert_return(ifindex > 0, -EINVAL);
-
- ppp->ifindex = ifindex;
-
- return 0;
-}
-
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) {
- char *name;
-
- assert_return(ppp, -EINVAL);
- assert_return(ifname, -EINVAL);
-
- if (strlen(ifname) > IFNAMSIZ)
- return -EINVAL;
-
- name = strdup(ifname);
- if (!name)
- return -ENOMEM;
-
- free(ppp->ifname);
- ppp->ifname = name;
-
- return 0;
-}
-
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) {
- _cleanup_free_ char *name = NULL;
-
- assert_return(ppp, -EINVAL);
-
- if (service_name) {
- name = strdup(service_name);
- if (!name)
- return -ENOMEM;
- }
-
- free(ppp->service_name);
- ppp->service_name = name;
- name = NULL;
-
- return 0;
-}
-
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) {
- int r;
-
- assert_return(ppp, -EINVAL);
- assert_return(!ppp->event, -EBUSY);
-
- if (event)
- ppp->event = sd_event_ref(event);
- else {
- r = sd_event_default(&ppp->event);
- if (r < 0)
- return r;
- }
-
- ppp->event_priority = priority;
-
- return 0;
-}
-
-int sd_pppoe_detach_event(sd_pppoe *ppp) {
- assert_return(ppp, -EINVAL);
-
- ppp->event = sd_event_unref(ppp->event);
-
- return 0;
-}
-
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) {
-
- if (!ppp)
- return NULL;
-
- assert(ppp->n_ref > 0);
- ppp->n_ref++;
-
- return ppp;
-}
-
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) {
-
- if (!ppp)
- return NULL;
-
- assert(ppp->n_ref > 0);
- ppp->n_ref--;
-
- if (ppp->n_ref > 0)
- return NULL;
-
- pppoe_tags_clear(&ppp->tags);
- free(ppp->ifname);
- free(ppp->service_name);
- sd_pppoe_stop(ppp);
- sd_pppoe_detach_event(ppp);
-
- free(ppp);
- return NULL;
-}
-
-int sd_pppoe_new (sd_pppoe **ret) {
- sd_pppoe *ppp;
-
- assert_return(ret, -EINVAL);
-
- ppp = new0(sd_pppoe, 1);
- if (!ppp)
- return -ENOMEM;
-
- ppp->n_ref = 1;
- ppp->state = _PPPOE_STATE_INVALID;
- ppp->ifindex = -1;
- ppp->fd = -1;
- ppp->pppoe_fd = -1;
- ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND;
-
- *ret = ppp;
-
- return 0;
-}
-
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) {
- assert_return(ppp, -EINVAL);
- assert_return(channel, -EINVAL);
- assert_return(ppp->pppoe_fd != -1, -EUNATCH);
- assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH);
-
- *channel = ppp->channel;
-
- return 0;
-}
-
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) {
- assert_return(ppp, -EINVAL);
-
- ppp->cb = cb;
- ppp->userdata = userdata;
-
- return 0;
-}
-
-static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) {
- struct pppoe_tag *tag;
-
- assert(packet);
- assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size);
- assert(!(!tag_data ^ !tag_len));
-
- tag = PPPOE_PACKET_TAIL(packet);
-
- tag->tag_len = htobe16(tag_len);
- tag->tag_type = tag_type;
- if (tag_data)
- memcpy(tag->tag_data, tag_data, tag_len);
-
- packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len);
-}
-
-static int pppoe_send(sd_pppoe *ppp, uint8_t code) {
- union sockaddr_union link = {
- .ll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_PPP_DISC),
- .sll_halen = ETH_ALEN,
- },
- };
- _cleanup_free_ struct pppoe_hdr *packet = NULL;
- int r;
-
- assert(ppp);
- assert(ppp->fd != -1);
- assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE));
-
- link.ll.sll_ifindex = ppp->ifindex;
- if (code == PADI_CODE)
- memset(&link.ll.sll_addr, 0xff, ETH_ALEN);
- else
- memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN);
-
- packet = malloc0(PPPOE_MAX_PACKET_SIZE);
- if (!packet)
- return -ENOMEM;
-
- packet->ver = 0x1;
- packet->type = 0x1;
- packet->code = code;
- if (code == PADT_CODE)
- packet->sid = ppp->session_id;
-
- /* Service-Name */
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME,
- ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0);
-
- /* AC-Cookie */
- if (code == PADR_CODE && ppp->tags.cookie)
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE,
- ppp->tags.cookie, ppp->tags.cookie_len);
-
- /* Host-Uniq */
- if (code != PADT_CODE) {
- ppp->host_uniq = random_u64();
-
- pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ,
- &ppp->host_uniq, sizeof(ppp->host_uniq));
- }
-
- r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet),
- 0, &link.sa, sizeof(link.ll));
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata);
-
-static int pppoe_arm_timeout(sd_pppoe *ppp) {
- _cleanup_event_source_unref_ sd_event_source *timeout = NULL;
- usec_t next_timeout = 0;
- int r;
-
- assert(ppp);
-
- r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout);
- if (r < 0)
- return r;
-
- next_timeout += 500 * USEC_PER_MSEC;
-
- r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout,
- 10 * USEC_PER_MSEC, pppoe_timeout, ppp);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(timeout, ppp->event_priority);
- if (r < 0)
- return r;
-
- sd_event_source_unref(ppp->timeout);
- ppp->timeout = timeout;
- timeout = NULL;
-
- return 0;
-}
-
-static int pppoe_send_initiation(sd_pppoe *ppp) {
- int r;
-
- r = pppoe_send(ppp, PADI_CODE);
- if (r < 0)
- return r;
-
- log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
- 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, SD_PPPOE_EVENT_RUNNING, ppp->userdata);
-
- break;
- case PPPOE_STATE_RUNNING:
- if (packet->code != PADT_CODE)
- return 0;
-
- if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0)
- return 0;
-
- if (ppp->session_id != packet->sid)
- return 0;
-
- log_debug("PPPoE: got TERMINATE");
-
- ppp->state = PPPOE_STATE_STOPPED;
-
- assert(ppp->cb);
- ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata);
-
- break;
- case PPPOE_STATE_STOPPED:
- break;
- default:
- assert_not_reached("PPPoE: invalid state when receiving message");
- }
-
- return 0;
-}
-
-static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_pppoe *ppp = userdata;
- _cleanup_free_ struct pppoe_hdr *packet = NULL;
- union sockaddr_union link = {};
- socklen_t addrlen = sizeof(link);
- int buflen = 0, len, r;
-
- assert(ppp);
- assert(fd != -1);
-
- r = ioctl(fd, FIONREAD, &buflen);
- if (r < 0)
- return r;
-
- if (buflen < 0)
- /* this can't be right */
- return -EIO;
-
- packet = malloc0(buflen);
- if (!packet)
- return -ENOMEM;
-
- len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen);
- if (len < 0) {
- log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m");
- return 0;
- } else if ((size_t)len < sizeof(struct pppoe_hdr))
- return 0;
- else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet))
- return 0;
-
- if (link.ll.sll_halen != ETH_ALEN)
- /* not ethernet? */
- return 0;
-
- r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-int sd_pppoe_start(sd_pppoe *ppp) {
- union sockaddr_union link = {
- .ll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_PPP_DISC),
- },
- };
- _cleanup_close_ int s = -1;
- _cleanup_event_source_unref_ sd_event_source *io = NULL;
- int r;
-
- assert_return(ppp, -EINVAL);
- assert_return(ppp->fd == -1, -EBUSY);
- assert_return(!ppp->io, -EBUSY);
- assert_return(ppp->ifindex > 0, -EUNATCH);
- assert_return(ppp->ifname, -EUNATCH);
- assert_return(ppp->event, -EUNATCH);
- assert_return(ppp->cb, -EUNATCH);
-
- s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- link.ll.sll_ifindex = ppp->ifindex;
-
- r = bind(s, &link.sa, sizeof(link.ll));
- if (r < 0)
- return r;
-
- r = sd_event_add_io(ppp->event, &io,
- s, EPOLLIN, pppoe_receive_message,
- ppp);
- if (r < 0)
- return r;
-
- r = sd_event_source_set_priority(io, ppp->event_priority);
- if (r < 0)
- return r;
-
- ppp->fd = s;
- s = -1;
- ppp->io = io;
- io = NULL;
-
- r = pppoe_send_initiation(ppp);
- if (r < 0)
- return r;
-
- ppp->state = PPPOE_STATE_INITIALIZING;
-
- return 0;
-}
-
-int sd_pppoe_stop(sd_pppoe *ppp) {
- assert_return(ppp, -EINVAL);
-
- if (ppp->state == PPPOE_STATE_RUNNING)
- pppoe_send_terminate(ppp);
-
- ppp->io = sd_event_source_unref(ppp->io);
- ppp->timeout = sd_event_source_unref(ppp->timeout);
- ppp->fd = asynchronous_close(ppp->fd);
- ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd);
-
- return 0;
-}
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index c112ec8134..5b52c1cbb9 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -24,14 +24,16 @@
#include <sys/socket.h>
#include <unistd.h>
-#include "util.h"
+#include "sd-dhcp-client.h"
#include "sd-event.h"
-#include "event-util.h"
+#include "alloc-util.h"
#include "dhcp-identifier.h"
-#include "dhcp-protocol.h"
#include "dhcp-internal.h"
-#include "sd-dhcp-client.h"
+#include "dhcp-protocol.h"
+#include "event-util.h"
+#include "util.h"
+#include "fd-util.h"
static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index b1ef174849..2d29e28f16 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -5,11 +5,11 @@
#include <errno.h>
#include <string.h>
-#include "util.h"
-#include "macro.h"
-
-#include "dhcp-protocol.h"
+#include "alloc-util.h"
#include "dhcp-internal.h"
+#include "dhcp-protocol.h"
+#include "macro.h"
+#include "util.h"
struct option_desc {
uint8_t sname[64];
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 7d8a1f6bd9..1a5c8c4605 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -22,11 +22,11 @@
#include <errno.h>
+#include "sd-dhcp-server.h"
#include "sd-event.h"
-#include "event-util.h"
-#include "sd-dhcp-server.h"
#include "dhcp-server-internal.h"
+#include "event-util.h"
static void test_pool(struct in_addr *address, unsigned size, int ret) {
_cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
@@ -198,6 +198,17 @@ static void test_message_handler(void) {
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
}
+static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
+ struct siphash state;
+ uint64_t hash;
+
+ siphash24_init(&state, key);
+ client_id_hash_func(id, &state);
+ siphash24_finalize((uint8_t*)&hash, &state);
+
+ return hash;
+}
+
static void test_client_id_hash(void) {
DHCPClientId a = {
.length = 4,
@@ -213,18 +224,18 @@ static void test_client_id_hash(void) {
b.data = (uint8_t*)strdup("abcd");
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
a.length = 3;
assert_se(client_id_compare_func(&a, &b) != 0);
a.length = 4;
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
b.length = 3;
assert_se(client_id_compare_func(&a, &b) != 0);
b.length = 4;
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
free(b.data);
b.data = (uint8_t*)strdup("abce");
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 0c131a9897..17ed6d58f3 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -19,23 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <net/ethernet.h>
#include <stdbool.h>
#include <stdio.h>
-#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <net/ethernet.h>
-#include "socket-util.h"
-#include "macro.h"
+#include "sd-dhcp6-client.h"
#include "sd-event.h"
-#include "event-util.h"
-#include "virt.h"
-#include "sd-dhcp6-client.h"
-#include "dhcp6-protocol.h"
#include "dhcp6-internal.h"
#include "dhcp6-lease-internal.h"
+#include "dhcp6-protocol.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "socket-util.h"
+#include "virt.h"
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
@@ -700,7 +701,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
static int test_client_solicit(sd_event *e) {
sd_dhcp6_client *client;
usec_t time_now = now(clock_boottime_or_monotonic());
- bool val = true;
+ int val = true;
if (verbose)
printf("* %s\n", __FUNCTION__);
diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c
deleted file mode 100644
index 27b0ef4572..0000000000
--- a/src/libsystemd-network/test-icmp6-rs.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/icmp6.h>
-
-#include "socket-util.h"
-
-#include "dhcp6-internal.h"
-#include "sd-icmp6-nd.h"
-
-static struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
-};
-
-static bool verbose = false;
-static sd_event_source *test_hangcheck;
-static int test_fd[2];
-
-typedef int (*send_ra_t)(uint8_t flags);
-static send_ra_t send_ra_function;
-
-static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
- void *userdata) {
- assert_se(false);
-
- return 0;
-}
-
-int dhcp_network_icmp6_bind_router_solicitation(int index) {
- assert_se(index == 42);
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
- return -errno;
-
- return test_fd[0];
-}
-
-static int send_ra_short_prefix(uint8_t flags) {
- uint8_t advertisement[] = {
- 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4,
- 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
- sizeof(advertisement));
-
- return 0;
-}
-
-static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) {
- sd_event *e = userdata;
- struct {
- struct in6_addr addr;
- uint8_t prefixlen;
- bool success;
- } addrs[] = {
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 52, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 64, false },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 60, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 64, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
- 52, true },
- };
- uint8_t prefixlen;
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(addrs); i++) {
- printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
- __FUNCTION__,
- addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
- addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
- addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
- addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
-
- if (addrs[i].success) {
- assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
- &prefixlen) >= 0);
- assert_se(addrs[i].prefixlen == prefixlen);
- printf("/%d onlink\n", prefixlen);
- } else {
- assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
- &prefixlen) == -EADDRNOTAVAIL);
- printf("/128 offlink\n");
- }
- }
-
- sd_event_exit(e, 0);
-}
-
-static int send_ra_prefixes(uint8_t flags) {
- uint8_t advertisement[] = {
- 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4,
- 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58,
- 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84,
- 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84,
- 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
- 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53
- };
-
- assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
- sizeof(advertisement));
-
- return 0;
-}
-
-static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) {
- sd_event *e = userdata;
- struct {
- struct in6_addr addr;
- uint8_t prefixlen;
- bool success;
- } addrs[] = {
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 63, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 64, false },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 60, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
- 64, true },
- { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
- 63, false },
- };
- uint8_t prefixlen;
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(addrs); i++) {
- printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x",
- __FUNCTION__,
- addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1],
- addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3],
- addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5],
- addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]);
-
- if (addrs[i].success) {
- assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
- &prefixlen) >= 0);
- assert_se(addrs[i].prefixlen == prefixlen);
- printf("/%d onlink\n", prefixlen);
- } else {
- assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr,
- &prefixlen) == -EADDRNOTAVAIL);
- printf("/128 offlink\n");
- }
- }
-
- send_ra_function = send_ra_short_prefix;
- assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0);
- assert_se(sd_icmp6_nd_stop(nd) >= 0);
- assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-}
-
-static void test_prefixes(void) {
- sd_event *e;
- sd_icmp6_nd *nd;
-
- if (verbose)
- printf("* %s\n", __FUNCTION__);
-
- send_ra_function = send_ra_prefixes;
-
- assert_se(sd_event_new(&e) >= 0);
-
- assert_se(sd_icmp6_nd_new(&nd) >= 0);
- assert_se(nd);
-
- assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
-
- assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
- assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
- assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0);
-
- assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-
- sd_event_loop(e);
-
- nd = sd_icmp6_nd_unref(nd);
- assert_se(!nd);
-
- close(test_fd[1]);
-
- sd_event_unref(e);
-}
-
-static int send_ra(uint8_t flags) {
- uint8_t advertisement[] = {
- 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
- 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
- 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
- };
-
- advertisement[5] = flags;
-
- assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
- sizeof(advertisement));
-
- if (verbose)
- printf(" sent RA with flag 0x%02x\n", flags);
-
- return 0;
-}
-
-int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
- return send_ra_function(0);
-}
-
-static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
- sd_event *e = userdata;
- static int idx = 0;
- struct {
- uint8_t flag;
- int event;
- } flag_event[] = {
- { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE },
- { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER },
- { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED }
- };
- uint32_t mtu;
-
- assert_se(nd);
-
- assert_se(event == flag_event[idx].event);
- idx++;
-
- if (verbose)
- printf(" got event %d\n", event);
-
- if (idx < 3) {
- send_ra(flag_event[idx].flag);
- return;
- }
-
- assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG);
-
- sd_event_exit(e, 0);
-}
-
-static void test_rs(void) {
- sd_event *e;
- sd_icmp6_nd *nd;
- usec_t time_now = now(clock_boottime_or_monotonic());
-
- if (verbose)
- printf("* %s\n", __FUNCTION__);
-
- send_ra_function = send_ra;
-
- assert_se(sd_event_new(&e) >= 0);
-
- assert_se(sd_icmp6_nd_new(&nd) >= 0);
- assert_se(nd);
-
- assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0);
-
- assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0);
- assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0);
- assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0);
-
- assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
- time_now + 2 *USEC_PER_SEC, 0,
- test_rs_hangcheck, NULL) >= 0);
-
- assert_se(sd_icmp6_nd_stop(nd) >= 0);
- assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
- assert_se(sd_icmp6_nd_stop(nd) >= 0);
-
- assert_se(sd_icmp6_router_solicitation_start(nd) >= 0);
-
- sd_event_loop(e);
-
- test_hangcheck = sd_event_source_unref(test_hangcheck);
-
- nd = sd_icmp6_nd_unref(nd);
- assert_se(!nd);
-
- close(test_fd[1]);
-
- sd_event_unref(e);
-}
-
-int main(int argc, char *argv[]) {
-
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
-
- test_rs();
- test_prefixes();
-
- return 0;
-}
diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c
index dd2e44e7a3..913a929069 100644
--- a/src/libsystemd-network/test-ipv4ll-manual.c
+++ b/src/libsystemd-network/test-ipv4ll-manual.c
@@ -19,21 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
+#include <net/if.h>
+#include <stdlib.h>
#include <unistd.h>
-
#include <linux/veth.h>
-#include <net/if.h>
#include "sd-event.h"
-#include "sd-netlink.h"
#include "sd-ipv4ll.h"
+#include "sd-netlink.h"
-#include "util.h"
+#include "alloc-util.h"
#include "event-util.h"
-#include "netlink-util.h"
#include "in-addr-util.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "util.h"
static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
_cleanup_free_ char *address = NULL;
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index e72204d992..6f416c51e4 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -18,20 +18,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
-#include <sys/types.h>
+#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
-#include "event-util.h"
-
#include "sd-ipv4ll.h"
+
#include "arp-util.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "socket-util.h"
+#include "util.h"
static bool verbose = false;
static bool extended = false;
@@ -100,6 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad
}
static void test_public_api_setters(sd_event *e) {
+ struct in_addr address = {};
unsigned seed = 0;
sd_ipv4ll *ll;
struct ether_addr mac_addr = {
@@ -118,6 +120,16 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(169U << 24 | 254U << 16);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0x00FF);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0xF000);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == 0);
+ address.s_addr |= htobe32(0x0F00);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+
assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL);
assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index 06545aee59..99545d0b8b 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -20,31 +20,41 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <arpa/inet.h>
+#include <net/ethernet.h>
#include <stdio.h>
#include <string.h>
-#include <net/ethernet.h>
-#include <arpa/inet.h>
-#include "macro.h"
-#include "lldp.h"
+#include "sd-event.h"
+#include "sd-lldp.h"
+
+#include "alloc-util.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "lldp-network.h"
#include "lldp-tlv.h"
+#include "lldp.h"
+#include "macro.h"
+#include "string-util.h"
#define TEST_LLDP_PORT "em1"
#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
+static int test_fd[2];
+
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
};
static int lldp_build_tlv_packet(tlv_packet **ret) {
- _cleanup_tlv_packet_free_ tlv_packet *m = NULL;
+ _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
struct ether_header ether = {
.ether_type = htons(ETHERTYPE_LLDP),
};
- /* Append ethernet header */
+ /* Append Ethernet header */
memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
@@ -202,6 +212,15 @@ static int lldp_parse_ttl_tlv(tlv_packet *m) {
return 0;
}
+static int lldp_get_destination_type(tlv_packet *m) {
+ int dest;
+
+ assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
+ assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
+
+ return 0;
+}
+
static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
uint8_t subtype;
@@ -212,20 +231,241 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
assert_se(lldp_parse_ttl_tlv(m) >= 0);
assert_se(lldp_parse_system_desc_tlv(m) >= 0);
+ assert_se(lldp_get_destination_type(m) >= 0);
+
return 0;
}
-int main(int argc, char *argv[]) {
- _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL;
+static void test_parser(void) {
+ _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
/* form a packet */
lldp_build_tlv_packet(&tlv);
-
/* parse the packet */
tlv_packet_parse_pdu(tlv, tlv->length);
-
/* verify */
lldp_parse_tlv_packet(tlv, tlv->length);
+}
+
+int lldp_network_bind_raw_socket(int ifindex) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
+ return -errno;
+
+ return test_fd[0];
+}
+
+static int lldp_handler_calls;
+static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
+ lldp_handler_calls++;
+}
+
+static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
+ int r;
+
+ r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
+ if (r)
+ return r;
+
+ r = sd_lldp_attach_event(*lldp, e, 0);
+ if (r)
+ return r;
+
+ r = sd_lldp_set_callback(*lldp, cb, cb_data);
+ if (r)
+ return r;
+
+ r = sd_lldp_start(*lldp);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int stop_lldp(sd_lldp *lldp) {
+ int r;
+
+ r = sd_lldp_stop(lldp);
+ if (r)
+ return r;
+
+ r = sd_lldp_detach_event(lldp);
+ if (r)
+ return r;
+
+ sd_lldp_free(lldp);
+ safe_close(test_fd[1]);
+
+ return 0;
+}
+
+static void test_receive_basic_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint8_t type, *data;
+ uint16_t length, ttl;
+ int dest_type;
+ char *str;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
+ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
+ /* LLDP optional TLVs */
+ 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
+ 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
+ 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
+ 0x00, 0x00 /* End Of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 1);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+
+ assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
+ assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
+ assert_se(length == ETH_ALEN);
+ assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
+
+ assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
+ assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
+ assert_se(length == 3);
+ assert_se(strneq((char *) data, "1/3", 3));
+
+ assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
+ assert_se(length == 4);
+ assert_se(strneq(str, "Port", 4));
+
+ assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
+ assert_se(length == 3);
+ assert_se(strneq(str, "SYS", 3));
+
+ assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
+ assert_se(length == 4); /* This is the real length in the TLV packet */
+ assert_se(strneq(str, "foo", 3));
+
+ assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
+ assert_se(ttl == 120);
+
+ assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
+ assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
+
+ sd_lldp_packet_unref(packets[0]);
+ free(packets);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+static void test_receive_incomplete_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
+ /* Missing TTL */
+ 0x00, 0x00 /* End Of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 0);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+static void test_receive_oui_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint32_t id32;
+ uint16_t id16, len;
+ uint8_t flags;
+ char *str;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
+ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
+ /* LLDP optional TLVs */
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
+ 0x12, 0x34,
+ 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
+ 0x01, 0x77, 0x88,
+ 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
+ 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
+ 0x6e, 0x35, 0x31,
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
+ 0x01, 0x02,
+ 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
+ 0x01, 0x00, 0x14, 0x00, 0x12,
+ 0x00, 0x00 /* End of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 1);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+
+ assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
+ assert_se(id16 == 0x1234);
+
+ assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
+ assert_se(flags == 1);
+ assert_se(id16 == 0x7788);
+
+ assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
+ assert_se(id16 == 0x1234);
+ assert_se(len == 6);
+ assert_se(strneq(str, "Vlan51", 6));
+
+ assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
+ assert_se(id16 == 0x0102);
+
+ assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
+ assert_se(flags == 1);
+ assert_se(id32 == 0x00140012);
+
+ sd_lldp_packet_unref(packets[0]);
+ free(packets);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+
+ test_parser();
+
+ /* LLDP reception tests */
+ assert_se(sd_event_new(&e) == 0);
+ test_receive_basic_packet(e);
+ test_receive_incomplete_packet(e);
+ test_receive_oui_packet(e);
return 0;
}
diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c
new file mode 100644
index 0000000000..44eab94e8b
--- /dev/null
+++ b/src/libsystemd-network/test-ndisc-rs.c
@@ -0,0 +1,171 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/icmp6.h>
+
+#include "sd-ndisc.h"
+
+#include "icmp6-util.h"
+#include "socket-util.h"
+
+static struct ether_addr mac_addr = {
+ .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
+};
+
+static bool verbose = false;
+static sd_event_source *test_hangcheck;
+static int test_fd[2];
+
+typedef int (*send_ra_t)(uint8_t flags);
+static send_ra_t send_ra_function;
+
+static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
+ void *userdata) {
+ assert_se(false);
+
+ return 0;
+}
+
+int icmp6_bind_router_solicitation(int index) {
+ assert_se(index == 42);
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
+ return -errno;
+
+ return test_fd[0];
+}
+
+static int send_ra(uint8_t flags) {
+ uint8_t advertisement[] = {
+ 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
+ 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
+ };
+
+ advertisement[5] = flags;
+
+ assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
+ sizeof(advertisement));
+
+ if (verbose)
+ printf(" sent RA with flag 0x%02x\n", flags);
+
+ return 0;
+}
+
+int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
+ return send_ra_function(0);
+}
+
+static void test_rs_done(sd_ndisc *nd, int event, void *userdata) {
+ sd_event *e = userdata;
+ static int idx = 0;
+ struct {
+ uint8_t flag;
+ int event;
+ } flag_event[] = {
+ { 0, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE },
+ { ND_RA_FLAG_OTHER, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER },
+ { ND_RA_FLAG_MANAGED, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED }
+ };
+ uint32_t mtu;
+
+ assert_se(nd);
+
+ assert_se(event == flag_event[idx].event);
+ idx++;
+
+ if (verbose)
+ printf(" got event %d\n", event);
+
+ if (idx < 3) {
+ send_ra(flag_event[idx].flag);
+ return;
+ }
+
+ assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG);
+
+ sd_event_exit(e, 0);
+}
+
+static void test_rs(void) {
+ sd_event *e;
+ sd_ndisc *nd;
+ usec_t time_now = now(clock_boottime_or_monotonic());
+
+ if (verbose)
+ printf("* %s\n", __FUNCTION__);
+
+ send_ra_function = send_ra;
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_ndisc_new(&nd) >= 0);
+ assert_se(nd);
+
+ assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
+
+ assert_se(sd_ndisc_set_index(nd, 42) >= 0);
+ assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
+ assert_se(sd_ndisc_set_callback(nd, test_rs_done, e) >= 0);
+
+ assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
+ time_now + 2 *USEC_PER_SEC, 0,
+ test_rs_hangcheck, NULL) >= 0);
+
+ assert_se(sd_ndisc_stop(nd) >= 0);
+ assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+ assert_se(sd_ndisc_stop(nd) >= 0);
+
+ assert_se(sd_ndisc_router_discovery_start(nd) >= 0);
+
+ sd_event_loop(e);
+
+ test_hangcheck = sd_event_source_unref(test_hangcheck);
+
+ nd = sd_ndisc_unref(nd);
+ assert_se(!nd);
+
+ close(test_fd[1]);
+
+ sd_event_unref(e);
+}
+
+int main(int argc, char *argv[]) {
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ test_rs();
+
+ return 0;
+}
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
deleted file mode 100644
index 6d71569a26..0000000000
--- a/src/libsystemd-network/test-pppoe.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <linux/veth.h>
-#include <net/if.h>
-
-#include "util.h"
-#include "sd-event.h"
-#include "event-util.h"
-#include "sd-netlink.h"
-#include "sd-pppoe.h"
-#include "process-util.h"
-
-static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
- static int pppoe_state = -1;
- sd_event *e = userdata;
-
- assert_se(ppp);
- assert_se(e);
-
- switch (event) {
- case SD_PPPOE_EVENT_RUNNING:
- assert_se(pppoe_state == -1);
- log_info("running");
- break;
- case SD_PPPOE_EVENT_STOPPED:
- assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING);
- log_info("stopped");
- assert_se(sd_event_exit(e, 0) >= 0);
- break;
- default:
- assert_not_reached("invalid pppoe event");
- }
-
- pppoe_state = event;
-}
-
-static int client_run(const char *client_name, sd_event *e) {
- sd_pppoe *pppoe;
- int client_ifindex;
-
- client_ifindex = (int) if_nametoindex(client_name);
- assert_se(client_ifindex > 0);
-
- assert_se(sd_pppoe_new(&pppoe) >= 0);
- assert_se(sd_pppoe_attach_event(pppoe, e, 0) >= 0);
-
- assert_se(sd_pppoe_set_ifname(pppoe, "pppoe-client") >= 0);
- assert_se(sd_pppoe_set_ifindex(pppoe, client_ifindex) >= 0);
- assert_se(sd_pppoe_set_callback(pppoe, pppoe_handler, e) >= 0);
-
- log_info("starting PPPoE client, it will exit when the server times out and sends PADT");
-
- assert_se(sd_pppoe_start(pppoe) >= 0);
-
- assert_se(sd_event_loop(e) >= 0);
-
- assert_se(!sd_pppoe_unref(pppoe));
-
- return EXIT_SUCCESS;
-}
-
-static int test_pppoe_server(sd_event *e) {
- sd_netlink *rtnl;
- sd_netlink_message *m;
- pid_t pid;
- int r, client_ifindex, server_ifindex;
-
- r = unshare(CLONE_NEWNET);
- if (r < 0 && errno == EPERM)
- return EXIT_TEST_SKIP;
-
- assert_se(r >= 0);
-
- assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
-
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0);
- assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0);
- assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0);
- assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0);
- assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0);
- assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_message_close_container(m) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- client_ifindex = (int) if_nametoindex("pppoe-client");
- assert_se(client_ifindex > 0);
- server_ifindex = (int) if_nametoindex("pppoe-server");
- assert_se(server_ifindex > 0);
-
- m = sd_netlink_message_unref(m);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0);
- assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- m = sd_netlink_message_unref(m);
- assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0);
- assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0);
- assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0);
-
- pid = fork();
- assert_se(pid >= 0);
- if (pid == 0) {
- /* let the client send some discover messages before the server is started */
- sleep(2);
-
- /* TODO: manage pppoe-server-options */
- execlp("pppoe-server", "pppoe-server", "-F",
- "-I", "pppoe-server",
- "-C", "Test-AC",
- "-S", "Service-Default",
- "-S", "Service-First-Auxiliary",
- "-S", "Service-Second-Auxiliary",
- NULL);
- assert_not_reached("failed to execute pppoe-server. not installed?");
- }
-
- client_run("pppoe-client", e);
-
- assert_se(kill(pid, SIGTERM) >= 0);
- assert_se(wait_for_terminate(pid, NULL) >= 0);
-
- assert_se(!sd_netlink_message_unref(m));
- assert_se(!sd_netlink_unref(rtnl));
-
- return EXIT_SUCCESS;
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_event_unref_ sd_event *e = NULL;
-
- log_set_max_level(LOG_DEBUG);
- log_parse_environment();
- log_open();
-
- assert_se(sd_event_new(&e) >= 0);
-
- if (argc == 1) {
- log_info("running PPPoE client against local server");
-
- return test_pppoe_server(e);
- } else if (argc == 2) {
- log_info("running PPPoE client over '%s'", argv[1]);
-
- return client_run(argv[1], e);
- } else {
- log_error("This program takes one or no arguments.\n"
- "\t %s [<ifname>]", program_invocation_short_name);
- return EXIT_FAILURE;
- }
-}
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 518cbbb7ed..043ff13e6f 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -477,4 +477,7 @@ global:
LIBSYSTEMD_227 {
global:
sd_bus_default_flush_close;
+ sd_bus_path_decode_many;
+ sd_bus_path_encode_many;
+ sd_listen_fds_with_names;
} LIBSYSTEMD_226;
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 5c607f49b1..589a90bbff 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -22,11 +22,12 @@
#include <unistd.h>
#include <fcntl.h>
-#include "util.h"
-#include "process-util.h"
+#include "bus-container.h"
#include "bus-internal.h"
#include "bus-socket.h"
-#include "bus-container.h"
+#include "fd-util.h"
+#include "process-util.h"
+#include "util.h"
int bus_container_connect_socket(sd_bus *b) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
@@ -217,15 +218,8 @@ int bus_container_connect_kernel(sd_bus *b) {
_exit(EXIT_FAILURE);
}
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+ r = send_one_fd(pair[1], fd, 0);
+ if (r < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index aeb48bedd1..d5bc32e757 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -26,14 +26,19 @@
#include <stddef.h>
#include <errno.h>
-#include "strv.h"
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-bloom.h"
+#include "bus-control.h"
#include "bus-internal.h"
#include "bus-message.h"
-#include "bus-control.h"
-#include "bus-bloom.h"
#include "bus-util.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
_public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) {
int r;
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index af5f7da11c..0afafc2942 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -22,8 +22,9 @@
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-signature.h"
-#include "bus-util.h"
#include "bus-type.h"
+#include "bus-util.h"
+#include "string-util.h"
_public_ int sd_bus_emit_signal(
sd_bus *bus,
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index 3e8cb0b7d0..2922da3763 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -19,22 +19,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <linux/capability.h>
+#include <stdlib.h>
-#include "util.h"
-#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "capability.h"
-#include "cgroup-util.h"
-#include "fileio.h"
-#include "audit.h"
+#include "alloc-util.h"
+#include "audit-util.h"
+#include "bus-creds.h"
+#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
+#include "capability-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "bus-creds.h"
-#include "bus-label.h"
+#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
enum {
CAP_OFFSET_INHERITABLE = 0,
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 8833b9c677..43a7e67a6d 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -19,18 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "capability.h"
-#include "strv.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "bus-dump.h"
+#include "bus-internal.h"
+#include "bus-message.h"
+#include "bus-type.h"
#include "cap-list.h"
+#include "capability-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
-
-#include "bus-message.h"
-#include "bus-internal.h"
-#include "bus-type.h"
-#include "bus-dump.h"
+#include "util.h"
static char *indent(unsigned level, unsigned flags) {
char *p;
diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index 64a5a972ae..239d7245e6 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -20,16 +20,18 @@
***/
#include <errno.h>
-#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <string.h>
#include <stdio.h>
-
-#include "util.h"
-#include "errno-list.h"
+#include <stdlib.h>
+#include <string.h>
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "errno-list.h"
+#include "string-util.h"
+#include "util.h"
#include "bus-error.h"
BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = {
@@ -565,7 +567,7 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for
const char *bus_error_message(const sd_bus_error *e, int error) {
if (e) {
- /* Sometimes the D-Bus server is a little bit too verbose with
+ /* Sometimes, the D-Bus server is a little bit too verbose with
* its error messages, so let's override them here */
if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED))
return "Access denied";
diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c
index fea796cd30..d9f9cd1c5e 100644
--- a/src/libsystemd/sd-bus/bus-internal.c
+++ b/src/libsystemd/sd-bus/bus-internal.c
@@ -19,8 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "bus-message.h"
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-message.h"
+#include "hexdecoct.h"
+#include "string-util.h"
bool object_path_is_valid(const char *p) {
const char *q;
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index e399701beb..5fc0926f06 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -21,21 +21,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <pthread.h>
-
-#include "hashmap.h"
-#include "prioq.h"
-#include "list.h"
-#include "util.h"
-#include "refcnt.h"
-#include "socket-util.h"
+#include <sys/socket.h>
#include "sd-bus.h"
+
#include "bus-error.h"
-#include "bus-match.h"
#include "bus-kernel.h"
+#include "bus-match.h"
+#include "hashmap.h"
#include "kdbus.h"
+#include "list.h"
+#include "prioq.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
struct reply_callback {
sd_bus_message_handler_t callback;
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
index 3149a56397..a90536bac9 100644
--- a/src/libsystemd/sd-bus/bus-introspect.c
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "bus-introspect.h"
-#include "bus-signature.h"
#include "bus-internal.h"
+#include "bus-introspect.h"
#include "bus-protocol.h"
+#include "bus-signature.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "string-util.h"
+#include "util.h"
int introspect_begin(struct introspect *i, bool trusted) {
assert(i);
diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c
index 577a8b44c3..6716f6daca 100644
--- a/src/libsystemd/sd-bus/bus-kernel.c
+++ b/src/libsystemd/sd-bus/bus-kernel.c
@@ -34,19 +34,23 @@
#include <libgen.h>
#undef basename
-#include "util.h"
-#include "strv.h"
-#include "memfd-util.h"
-#include "capability.h"
-#include "fileio.h"
-#include "formats-util.h"
-
+#include "alloc-util.h"
+#include "bus-bloom.h"
#include "bus-internal.h"
-#include "bus-message.h"
#include "bus-kernel.h"
-#include "bus-bloom.h"
-#include "bus-util.h"
#include "bus-label.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "capability-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "memfd-util.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
@@ -1433,12 +1437,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
if (!bus || !bus->is_kernel)
return -EOPNOTSUPP;
- assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
if (bus->n_memfd_cache <= 0) {
int r;
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
r = memfd_new(bus->description);
if (r < 0)
@@ -1460,7 +1464,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al
*allocated = c->allocated;
fd = c->fd;
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
return fd;
}
@@ -1484,10 +1488,10 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si
return;
}
- assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
close_and_munmap(fd, address, mapped);
return;
@@ -1507,7 +1511,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si
c->allocated = allocated;
}
- assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
+ assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
}
void bus_kernel_flush_memfd(sd_bus *b) {
diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c
index 7234e7926a..55dc7caa53 100644
--- a/src/libsystemd/sd-bus/bus-match.c
+++ b/src/libsystemd/sd-bus/bus-match.c
@@ -19,10 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-internal.h"
-#include "bus-message.h"
#include "bus-match.h"
+#include "bus-message.h"
#include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hexdecoct.h"
+#include "string-util.h"
#include "strv.h"
/* Example:
diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h
index 53ee0463ca..bc85af3ec0 100644
--- a/src/libsystemd/sd-bus/bus-match.h
+++ b/src/libsystemd/sd-bus/bus-match.h
@@ -21,10 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "hashmap.h"
-
#include "sd-bus.h"
+#include "hashmap.h"
+
enum bus_match_node_type {
BUS_MATCH_ROOT,
BUS_MATCH_VALUE,
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index 72e2b9f785..5c80095bf0 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -23,19 +23,23 @@
#include <fcntl.h>
#include <sys/mman.h>
-#include "util.h"
-#include "utf8.h"
-#include "strv.h"
-#include "time-util.h"
-#include "memfd-util.h"
-
#include "sd-bus.h"
-#include "bus-message.h"
+
+#include "alloc-util.h"
+#include "bus-gvariant.h"
#include "bus-internal.h"
-#include "bus-type.h"
+#include "bus-message.h"
#include "bus-signature.h"
-#include "bus-gvariant.h"
+#include "bus-type.h"
#include "bus-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "memfd-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "time-util.h"
+#include "utf8.h"
+#include "util.h"
static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h
index ff25003461..4c91dbae09 100644
--- a/src/libsystemd/sd-bus/bus-message.h
+++ b/src/libsystemd/sd-bus/bus-message.h
@@ -21,15 +21,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <byteswap.h>
+#include <stdbool.h>
#include <sys/socket.h>
-#include "macro.h"
#include "sd-bus.h"
-#include "time-util.h"
+
#include "bus-creds.h"
#include "bus-protocol.h"
+#include "macro.h"
+#include "time-util.h"
struct bus_container {
char enclosing;
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 1d061cb9cf..8c472626a8 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -19,15 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
-#include "set.h"
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-introspect.h"
#include "bus-message.h"
-#include "bus-type.h"
#include "bus-signature.h"
-#include "bus-introspect.h"
-#include "bus-util.h"
#include "bus-slot.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
#include "bus-objects.h"
static int node_vtable_get_userdata(
@@ -1578,25 +1580,14 @@ _public_ int sd_bus_add_fallback(
return bus_add_object(bus, slot, true, prefix, callback, userdata);
}
-static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void vtable_member_hash_func(const void *a, struct siphash *state) {
const struct vtable_member *m = a;
- uint8_t hash_key2[HASH_KEY_SIZE];
- unsigned long ret;
assert(m);
- ret = string_hash_func(m->path, hash_key);
-
- /* Use a slightly different hash key for the interface */
- memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
- hash_key2[0]++;
- ret ^= string_hash_func(m->interface, hash_key2);
-
- /* And an even different one for the member */
- hash_key2[0]++;
- ret ^= string_hash_func(m->member, hash_key2);
-
- return ret;
+ string_hash_func(m->path, state);
+ string_hash_func(m->interface, state);
+ string_hash_func(m->member, state);
}
static int vtable_member_compare_func(const void *a, const void *b) {
diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c
index b149ea16da..550bad27ba 100644
--- a/src/libsystemd/sd-bus/bus-slot.c
+++ b/src/libsystemd/sd-bus/bus-slot.c
@@ -20,8 +20,11 @@
***/
#include "sd-bus.h"
+
+#include "alloc-util.h"
#include "bus-control.h"
#include "bus-objects.h"
+#include "string-util.h"
#include "bus-slot.h"
sd_bus_slot *bus_slot_allocate(
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index d0b1e3d7dc..a5cb667630 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -20,22 +20,28 @@
***/
#include <endian.h>
+#include <poll.h>
#include <stdlib.h>
#include <unistd.h>
-#include <poll.h>
+#include "sd-bus.h"
#include "sd-daemon.h"
-#include "util.h"
-#include "macro.h"
-#include "missing.h"
-#include "utf8.h"
-#include "formats-util.h"
-#include "signal-util.h"
-#include "sd-bus.h"
-#include "bus-socket.h"
+#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-message.h"
+#include "bus-socket.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "hexdecoct.h"
+#include "macro.h"
+#include "missing.h"
+#include "signal-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "utf8.h"
+#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index e43891be25..fd7e58fcfa 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -20,9 +20,11 @@
***/
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-track.h"
+#include "bus-util.h"
struct sd_bus_track {
unsigned n_ref;
diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h
index 581574ab73..ad89e6c911 100644
--- a/src/libsystemd/sd-bus/bus-type.h
+++ b/src/libsystemd/sd-bus/bus-type.h
@@ -23,9 +23,10 @@
#include <stdbool.h>
-#include "macro.h"
#include "sd-bus.h"
+#include "macro.h"
+
bool bus_type_is_valid(char c) _const_;
bool bus_type_is_valid_in_signature(char c) _const_;
bool bus_type_is_basic(char c) _const_;
diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c
index abe482fc46..71f962b00c 100644
--- a/src/libsystemd/sd-bus/busctl-introspect.c
+++ b/src/libsystemd/sd-bus/busctl-introspect.c
@@ -19,11 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "xml.h"
-#include "sd-bus-vtable.h"
+#include "sd-bus.h"
+#include "alloc-util.h"
#include "busctl-introspect.h"
+#include "string-util.h"
+#include "util.h"
+#include "xml.h"
#define NODE_DEPTH_MAX 16
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 5d07d5809c..452ac7c407 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -21,22 +21,27 @@
#include <getopt.h>
-#include "strv.h"
-#include "util.h"
-#include "log.h"
-#include "build.h"
-#include "pager.h"
-#include "path-util.h"
-#include "set.h"
-
#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-dump.h"
+#include "bus-internal.h"
#include "bus-signature.h"
#include "bus-type.h"
+#include "bus-util.h"
#include "busctl-introspect.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "locale-util.h"
+#include "log.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -629,22 +634,24 @@ typedef struct Member {
uint64_t flags;
} Member;
-static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
+static void member_hash_func(const void *p, struct siphash *state) {
const Member *m = p;
- unsigned long ul;
+ uint64_t arity = 1;
assert(m);
assert(m->type);
- ul = string_hash_func(m->type, hash_key);
+ string_hash_func(m->type, state);
+
+ arity += !!m->name + !!m->interface;
+
+ uint64_hash_func(&arity, state);
if (m->name)
- ul ^= string_hash_func(m->name, hash_key);
+ string_hash_func(m->name, state);
if (m->interface)
- ul ^= string_hash_func(m->interface, hash_key);
-
- return ul;
+ string_hash_func(m->interface, state);
}
static int member_compare_func(const void *a, const void *b) {
@@ -1786,9 +1793,7 @@ static int parse_argv(int argc, char *argv[]) {
return help();
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 53d1c6f61d..a8d79b01b0 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -27,28 +27,33 @@
#include <sys/mman.h>
#include <pthread.h>
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-#include "missing.h"
-#include "def.h"
-#include "cgroup-util.h"
-#include "hostname-util.h"
-#include "bus-label.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-container.h"
+#include "bus-control.h"
#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-type.h"
-#include "bus-socket.h"
#include "bus-kernel.h"
-#include "bus-control.h"
+#include "bus-label.h"
+#include "bus-message.h"
#include "bus-objects.h"
-#include "bus-util.h"
-#include "bus-container.h"
#include "bus-protocol.h"
-#include "bus-track.h"
#include "bus-slot.h"
+#include "bus-socket.h"
+#include "bus-track.h"
+#include "bus-type.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "macro.h"
+#include "missing.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
#define log_debug_bus_message(m) \
do { \
@@ -3454,6 +3459,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext
return 1;
}
+_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) {
+ _cleanup_strv_free_ char **labels = NULL;
+ char *path, *path_pos, **label_pos;
+ const char *sep, *template_pos;
+ size_t path_length;
+ va_list list;
+ int r;
+
+ assert_return(out, -EINVAL);
+ assert_return(path_template, -EINVAL);
+
+ path_length = strlen(path_template);
+
+ va_start(list, path_template);
+ for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) {
+ const char *arg;
+ char *label;
+
+ arg = va_arg(list, const char *);
+ if (!arg) {
+ va_end(list);
+ return -EINVAL;
+ }
+
+ label = bus_label_escape(arg);
+ if (!label) {
+ va_end(list);
+ return -ENOMEM;
+ }
+
+ r = strv_consume(&labels, label);
+ if (r < 0) {
+ va_end(list);
+ return r;
+ }
+
+ /* add label length, but account for the format character */
+ path_length += strlen(label) - 1;
+ }
+ va_end(list);
+
+ path = malloc(path_length + 1);
+ if (!path)
+ return -ENOMEM;
+
+ path_pos = path;
+ label_pos = labels;
+
+ for (template_pos = path_template; *template_pos; ) {
+ sep = strchrnul(template_pos, '%');
+ path_pos = mempcpy(path_pos, template_pos, sep - template_pos);
+ if (!*sep)
+ break;
+
+ path_pos = stpcpy(path_pos, *label_pos++);
+ template_pos = sep + 1;
+ }
+
+ *path_pos = 0;
+ *out = path;
+ return 0;
+}
+
+_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) {
+ _cleanup_strv_free_ char **labels = NULL;
+ const char *template_pos, *path_pos;
+ char **label_pos;
+ va_list list;
+ int r;
+
+ /*
+ * This decodes an object-path based on a template argument. The
+ * template consists of a verbatim path, optionally including special
+ * directives:
+ *
+ * - Each occurrence of '%' in the template matches an arbitrary
+ * substring of a label in the given path. At most one such
+ * directive is allowed per label. For each such directive, the
+ * caller must provide an output parameter (char **) via va_arg. If
+ * NULL is passed, the given label is verified, but not returned.
+ * For each matched label, the *decoded* label is stored in the
+ * passed output argument, and the caller is responsible to free
+ * it. Note that the output arguments are only modified if the
+ * actualy path matched the template. Otherwise, they're left
+ * untouched.
+ *
+ * This function returns <0 on error, 0 if the path does not match the
+ * template, 1 if it matched.
+ */
+
+ assert_return(path, -EINVAL);
+ assert_return(path_template, -EINVAL);
+
+ path_pos = path;
+
+ for (template_pos = path_template; *template_pos; ) {
+ const char *sep;
+ size_t length;
+ char *label;
+
+ /* verify everything until the next '%' matches verbatim */
+ sep = strchrnul(template_pos, '%');
+ length = sep - template_pos;
+ if (strncmp(path_pos, template_pos, length))
+ return 0;
+
+ path_pos += length;
+ template_pos += length;
+
+ if (!*template_pos)
+ break;
+
+ /* We found the next '%' character. Everything up until here
+ * matched. We now skip ahead to the end of this label and make
+ * sure it matches the tail of the label in the path. Then we
+ * decode the string in-between and save it for later use. */
+
+ ++template_pos; /* skip over '%' */
+
+ sep = strchrnul(template_pos, '/');
+ length = sep - template_pos; /* length of suffix to match verbatim */
+
+ /* verify the suffixes match */
+ sep = strchrnul(path_pos, '/');
+ if (sep - path_pos < (ssize_t)length ||
+ strncmp(sep - length, template_pos, length))
+ return 0;
+
+ template_pos += length; /* skip over matched label */
+ length = sep - path_pos - length; /* length of sub-label to decode */
+
+ /* store unescaped label for later use */
+ label = bus_label_unescape_n(path_pos, length);
+ if (!label)
+ return -ENOMEM;
+
+ r = strv_consume(&labels, label);
+ if (r < 0)
+ return r;
+
+ path_pos = sep; /* skip decoded label and suffix */
+ }
+
+ /* end of template must match end of path */
+ if (*path_pos)
+ return 0;
+
+ /* copy the labels over to the caller */
+ va_start(list, path_template);
+ for (label_pos = labels; label_pos && *label_pos; ++label_pos) {
+ char **arg;
+
+ arg = va_arg(list, char **);
+ if (arg)
+ *arg = *label_pos;
+ else
+ free(*label_pos);
+ }
+ va_end(list);
+
+ free(labels);
+ labels = NULL;
+ return 1;
+}
+
_public_ int sd_bus_try_close(sd_bus *bus) {
int r;
diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c
index d14110aa04..96a0929a14 100644
--- a/src/libsystemd/sd-bus/test-bus-benchmark.c
+++ b/src/libsystemd/sd-bus/test-bus-benchmark.c
@@ -21,14 +21,16 @@
#include <sys/wait.h>
-#include "def.h"
-#include "util.h"
-#include "time-util.h"
-
#include "sd-bus.h"
-#include "bus-kernel.h"
+
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-kernel.h"
#include "bus-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "time-util.h"
+#include "util.h"
#define MAX_SIZE (2*1024*1024)
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 20f1b532b7..767aef63ff 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -24,16 +24,18 @@
#include <unistd.h>
#include <fcntl.h>
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "formats-util.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
-#include "bus-match.h"
#include "bus-internal.h"
+#include "bus-match.h"
#include "bus-util.h"
+#include "formats-util.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
+#include "fd-util.h"
static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m)));
diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c
index f586880593..51aa0a9ad0 100644
--- a/src/libsystemd/sd-bus/test-bus-cleanup.c
+++ b/src/libsystemd/sd-bus/test-bus-cleanup.c
@@ -22,9 +22,10 @@
#include <stdio.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-internal.h"
#include "bus-message.h"
+#include "bus-util.h"
#include "refcnt.h"
static void test_bus_new(void) {
diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c
index b078bdc5f6..931c001788 100644
--- a/src/libsystemd/sd-bus/test-bus-gvariant.c
+++ b/src/libsystemd/sd-bus/test-bus-gvariant.c
@@ -23,14 +23,16 @@
#include <glib.h>
#endif
-#include "util.h"
-#include "macro.h"
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
#include "bus-gvariant.h"
-#include "bus-util.h"
#include "bus-internal.h"
#include "bus-message.h"
-#include "bus-dump.h"
+#include "bus-util.h"
+#include "macro.h"
+#include "util.h"
static void test_bus_gvariant_is_fixed_size(void) {
assert_se(bus_gvariant_is_fixed_size("") > 0);
diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
index f3d1099dd2..dbdaa69fbe 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c
@@ -19,12 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "log.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
#include "bus-kernel.h"
#include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "util.h"
static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
int *found = userdata;
diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c
index 6506eaab2e..0080f71d3b 100644
--- a/src/libsystemd/sd-bus/test-bus-kernel.c
+++ b/src/libsystemd/sd-bus/test-bus-kernel.c
@@ -21,13 +21,15 @@
#include <fcntl.h>
-#include "util.h"
-#include "log.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
#include "bus-kernel.h"
#include "bus-util.h"
-#include "bus-dump.h"
+#include "fd-util.h"
+#include "log.h"
+#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_close_ int bus_ref = -1;
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index b203707f27..0747d6a37c 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -30,14 +30,17 @@
#include <dbus/dbus.h>
#endif
-#include "log.h"
-#include "util.h"
-
#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-dump.h"
#include "bus-label.h"
+#include "bus-message.h"
+#include "bus-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "hexdecoct.h"
+#include "util.h"
static void test_bus_path_encode_unique(void) {
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL;
@@ -66,6 +69,36 @@ static void test_bus_path_encode(void) {
assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar"));
}
+static void test_bus_path_encode_many(void) {
+ _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
+
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar"));
+ assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar"));
+ assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar"));
+
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar"));
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0);
+
+ assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix"));
+}
+
static void test_bus_label_escape_one(const char *a, const char *b) {
_cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
@@ -393,6 +426,7 @@ int main(int argc, char *argv[]) {
test_bus_label_escape();
test_bus_path_encode();
test_bus_path_encode_unique();
+ test_bus_path_encode_many();
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index 0a35b750b3..5bc72e2355 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -22,16 +22,17 @@
#include <stdlib.h>
#include <pthread.h>
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "bus-dump.h"
+#include "log.h"
+#include "macro.h"
+#include "strv.h"
+#include "util.h"
struct context {
int fds[2];
diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c
index aef768dc18..428e185769 100644
--- a/src/libsystemd/sd-bus/test-bus-proxy.c
+++ b/src/libsystemd/sd-bus/test-bus-proxy.c
@@ -23,13 +23,14 @@
#include <fcntl.h>
#include <stdlib.h>
-#include "util.h"
-#include "log.h"
-
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-dump.h"
#include "bus-kernel.h"
#include "bus-util.h"
-#include "bus-dump.h"
+#include "log.h"
+#include "util.h"
typedef struct {
const char *sender;
diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c
index 080d8eddb7..5bf2c1ecf8 100644
--- a/src/libsystemd/sd-bus/test-bus-server.c
+++ b/src/libsystemd/sd-bus/test-bus-server.c
@@ -19,16 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <pthread.h>
-
-#include "log.h"
-#include "util.h"
-#include "macro.h"
+#include <stdlib.h>
#include "sd-bus.h"
+
#include "bus-internal.h"
#include "bus-util.h"
+#include "log.h"
+#include "macro.h"
+#include "util.h"
struct context {
int fds[2];
diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c
index 17c6188ca0..92a810a7d8 100644
--- a/src/libsystemd/sd-bus/test-bus-signature.c
+++ b/src/libsystemd/sd-bus/test-bus-signature.c
@@ -19,7 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
+#include "string-util.h"
#include "log.h"
#include "bus-signature.h"
#include "bus-internal.h"
diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c
index 2d062fc9b5..ff8df61a9e 100644
--- a/src/libsystemd/sd-bus/test-bus-zero-copy.c
+++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c
@@ -21,14 +21,17 @@
#include <sys/mman.h>
-#include "util.h"
-#include "log.h"
-#include "memfd-util.h"
-
#include "sd-bus.h"
-#include "bus-message.h"
-#include "bus-kernel.h"
+
+#include "alloc-util.h"
#include "bus-dump.h"
+#include "bus-kernel.h"
+#include "bus-message.h"
+#include "log.h"
+#include "memfd-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "fd-util.h"
#define FIRST_ARRAY 17
#define SECOND_ARRAY 33
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 9ec73406c6..f1e9b7ed1b 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -19,29 +19,46 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <stdlib.h>
#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stddef.h>
#include <limits.h>
#include <mqueue.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
-#include "util.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "socket-util.h"
-#include "sd-daemon.h"
+#include "strv.h"
+#include "util.h"
+
+#define SNDBUF_SIZE (8*1024*1024)
+
+static void unsetenv_all(bool unset_environment) {
+
+ if (!unset_environment)
+ return;
+
+ unsetenv("LISTEN_PID");
+ unsetenv("LISTEN_FDS");
+ unsetenv("LISTEN_FDNAMES");
+}
_public_ int sd_listen_fds(int unset_environment) {
const char *e;
- unsigned n;
- int r, fd;
+ int n, r, fd;
pid_t pid;
e = getenv("LISTEN_PID");
@@ -66,25 +83,68 @@ _public_ int sd_listen_fds(int unset_environment) {
goto finish;
}
- r = safe_atou(e, &n);
+ r = safe_atoi(e, &n);
if (r < 0)
goto finish;
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) {
+ assert_cc(SD_LISTEN_FDS_START < INT_MAX);
+ if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) {
+ r = -EINVAL;
+ goto finish;
+ }
+
+ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
r = fd_cloexec(fd, true);
if (r < 0)
goto finish;
}
- r = (int) n;
+ r = n;
finish:
- if (unset_environment) {
- unsetenv("LISTEN_PID");
- unsetenv("LISTEN_FDS");
+ unsetenv_all(unset_environment);
+ return r;
+}
+
+_public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
+ _cleanup_strv_free_ char **l = NULL;
+ bool have_names;
+ int n_names = 0, n_fds;
+ const char *e;
+ int r;
+
+ if (!names)
+ return sd_listen_fds(unset_environment);
+
+ e = getenv("LISTEN_FDNAMES");
+ if (e) {
+ n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (n_names < 0) {
+ unsetenv_all(unset_environment);
+ return n_names;
+ }
+
+ have_names = true;
+ } else
+ have_names = false;
+
+ n_fds = sd_listen_fds(unset_environment);
+ if (n_fds <= 0)
+ return n_fds;
+
+ if (have_names) {
+ if (n_names != n_fds)
+ return -EINVAL;
+ } else {
+ r = strv_extend_n(&l, "unknown", n_fds);
+ if (r < 0)
+ return r;
}
- return r;
+ *names = l;
+ l = NULL;
+
+ return n_fds;
}
_public_ int sd_is_fifo(int fd, const char *path) {
@@ -310,10 +370,15 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path
_public_ int sd_is_mq(int fd, const char *path) {
struct mq_attr attr;
- assert_return(fd >= 0, -EBADF);
+ /* Check that the fd is valid */
+ assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
- if (mq_getattr(fd, &attr) < 0)
+ if (mq_getattr(fd, &attr) < 0) {
+ if (errno == EBADF)
+ /* A non-mq fd (or an invalid one, but we ruled that out above) */
+ return 0;
return -errno;
+ }
if (path) {
char fpath[PATH_MAX];
@@ -376,12 +441,19 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
goto finish;
}
+ if (strlen(e) > sizeof(sockaddr.un.sun_path)) {
+ r = -EINVAL;
+ goto finish;
+ }
+
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
if (fd < 0) {
r = -errno;
goto finish;
}
+ fd_inc_sndbuf(fd, SNDBUF_SIZE);
+
iovec.iov_len = strlen(state);
strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
@@ -396,9 +468,11 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (n_fds > 0 || have_pid) {
/* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
- msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
- CMSG_SPACE(sizeof(struct ucred)) * have_pid;
- msghdr.msg_control = alloca(msghdr.msg_controllen);
+ msghdr.msg_controllen =
+ (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
+ (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
+
+ msghdr.msg_control = alloca0(msghdr.msg_controllen);
cmsg = CMSG_FIRSTHDR(&msghdr);
if (n_fds > 0) {
@@ -498,16 +572,11 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
}
_public_ int sd_booted(void) {
- struct stat st;
-
/* We test whether the runtime unit file directory has been
* created. This takes place in mount-setup.c, so is
* guaranteed to happen very early during boot. */
- if (lstat("/run/systemd/system/", &st) < 0)
- return 0;
-
- return !!S_ISDIR(st.st_mode);
+ return laccess("/run/systemd/system/", F_OK) >= 0;
}
_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
@@ -522,7 +591,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
r = safe_atou64(s, &u);
if (r < 0)
goto finish;
- if (u <= 0) {
+ if (u <= 0 || u >= USEC_INFINITY) {
r = -EINVAL;
goto finish;
}
diff --git a/src/machine-id-commit/Makefile b/src/libsystemd/sd-device/Makefile
index d0b0e8e008..d0b0e8e008 120000
--- a/src/machine-id-commit/Makefile
+++ b/src/libsystemd/sd-device/Makefile
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
index 5eb37e16cb..ae3157ee5e 100644
--- a/src/libsystemd/sd-device/device-enumerator.c
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -18,15 +18,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "prioq.h"
-#include "strv.h"
-#include "set.h"
-
#include "sd-device.h"
-#include "device-util.h"
+#include "alloc-util.h"
#include "device-enumerator-private.h"
+#include "device-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "prioq.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
#define DEVICE_ENUMERATE_MAX_DEPTH 256
@@ -812,10 +815,8 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
if (access("/sys/subsystem", F_OK) >= 0) {
/* we have /subsystem/, forget all the old stuff */
r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
- if (r < 0) {
- log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m");
} else {
int k;
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 0ec9667744..a13477e753 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -19,25 +19,31 @@
***/
#include <ctype.h>
-#include <sys/types.h>
#include <net/if.h>
-
-#include "util.h"
-#include "macro.h"
-#include "refcnt.h"
-#include "path-util.h"
-#include "strxcpyx.h"
-#include "fileio.h"
-#include "hashmap.h"
-#include "set.h"
-#include "strv.h"
-#include "mkdir.h"
+#include <sys/types.h>
#include "sd-device.h"
-#include "device-util.h"
+#include "alloc-util.h"
#include "device-internal.h"
#include "device-private.h"
+#include "device-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "refcnt.h"
+#include "set.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+#include "user-util.h"
+#include "util.h"
int device_add_property(sd_device *device, const char *key, const char *value) {
int r;
@@ -200,10 +206,8 @@ static int device_read_db(sd_device *device) {
if (r < 0) {
if (r == -ENOENT)
return 0;
- else {
- log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
- return r;
- }
+ else
+ return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
}
/* devices with a database entry are initialized */
@@ -247,7 +251,7 @@ static int device_read_db(sd_device *device) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
- log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
state = PRE_KEY;
}
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
index 49a7b66a2b..d1f34efc2d 100644
--- a/src/libsystemd/sd-device/device-private.h
+++ b/src/libsystemd/sd-device/device-private.h
@@ -21,6 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "sd-device.h"
+
int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
int device_new_from_strv(sd_device **ret, char **strv);
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 7cea5a0746..0e49262087 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -19,23 +19,28 @@
***/
#include <ctype.h>
-#include <sys/types.h>
#include <net/if.h>
+#include <sys/types.h>
-#include "util.h"
-#include "macro.h"
-#include "path-util.h"
-#include "strxcpyx.h"
+#include "sd-device.h"
+
+#include "alloc-util.h"
+#include "device-internal.h"
+#include "device-private.h"
+#include "device-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "hashmap.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "set.h"
+#include "stat-util.h"
+#include "string-util.h"
#include "strv.h"
-
-#include "sd-device.h"
-
-#include "device-util.h"
-#include "device-private.h"
-#include "device-internal.h"
+#include "strxcpyx.h"
+#include "util.h"
int device_new_aux(sd_device **ret) {
_cleanup_device_unref_ sd_device *device = NULL;
@@ -169,11 +174,10 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* the device does not exist (any more?) */
return -ENODEV;
- log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
- return -errno;
+ return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
}
} else if (r < 0) {
- log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
+ log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
return r;
}
@@ -296,15 +300,27 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s
} else
return -EINVAL;
} else {
- syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
+ char *name;
+ size_t len = 0;
+
+ /* translate sysname back to sysfs filename */
+ name = strdupa(sysname);
+ while (name[len] != '\0') {
+ if (name[len] == '/')
+ name[len] = '!';
+
+ len ++;
+ }
+
+ syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
- syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
+ syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
- syspath = strjoina("/sys/class/", subsystem, "/", sysname);
+ syspath = strjoina("/sys/class/", subsystem, "/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
}
@@ -340,13 +356,10 @@ int device_set_ifindex(sd_device *device, const char *_ifindex) {
assert(device);
assert(_ifindex);
- r = safe_atoi(_ifindex, &ifindex);
+ r = parse_ifindex(_ifindex, &ifindex);
if (r < 0)
return r;
- if (ifindex <= 0)
- return -EINVAL;
-
r = device_add_property_internal(device, "IFINDEX", _ifindex);
if (r < 0)
return r;
@@ -516,7 +529,7 @@ int device_read_uevent_file(sd_device *device) {
/* some devices may not have uevent files, see set_syspath() */
return 0;
else if (r < 0) {
- log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
return r;
}
@@ -555,7 +568,7 @@ int device_read_uevent_file(sd_device *device) {
r = handle_uevent_line(device, key, value, &major, &minor);
if (r < 0)
- log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
state = PRE_KEY;
}
@@ -569,7 +582,7 @@ int device_read_uevent_file(sd_device *device) {
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
- log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
+ log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
}
return 0;
@@ -616,11 +629,9 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
struct ifreq ifr = {};
int ifindex;
- r = safe_atoi(&id[1], &ifr.ifr_ifindex);
+ r = parse_ifindex(&id[1], &ifr.ifr_ifindex);
if (r < 0)
return r;
- else if (ifr.ifr_ifindex <= 0)
- return -EINVAL;
sk = socket(PF_INET, SOCK_DGRAM, 0);
if (sk < 0)
@@ -1271,10 +1282,8 @@ int device_read_db_aux(sd_device *device, bool force) {
if (r < 0) {
if (r == -ENOENT)
return 0;
- else {
- log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
- return r;
- }
+ else
+ return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
}
/* devices with a database entry are initialized */
@@ -1318,7 +1327,7 @@ int device_read_db_aux(sd_device *device, bool force) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
- log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
state = PRE_KEY;
}
diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h
index e7cad9be46..ae020340a5 100644
--- a/src/libsystemd/sd-event/event-util.h
+++ b/src/libsystemd/sd-event/event-util.h
@@ -21,9 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "sd-event.h"
+#include "util.h"
+
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index 48a5219275..ee4886700e 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -23,19 +23,22 @@
#include <sys/timerfd.h>
#include <sys/wait.h>
-#include "sd-id128.h"
#include "sd-daemon.h"
-#include "macro.h"
-#include "prioq.h"
+#include "sd-event.h"
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
#include "hashmap.h"
-#include "util.h"
-#include "time-util.h"
+#include "list.h"
+#include "macro.h"
#include "missing.h"
+#include "prioq.h"
#include "set.h"
-#include "list.h"
#include "signal-util.h"
-
-#include "sd-event.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "util.h"
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
@@ -242,12 +245,6 @@ static int pending_prioq_compare(const void *a, const void *b) {
if (x->pending_iteration > y->pending_iteration)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -277,12 +274,6 @@ static int prepare_prioq_compare(const void *a, const void *b) {
if (x->priority > y->priority)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -310,12 +301,6 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
if (x->time.next > y->time.next)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -343,12 +328,6 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -370,12 +349,6 @@ static int exit_prioq_compare(const void *a, const void *b) {
if (x->priority > y->priority)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -1153,8 +1126,8 @@ _public_ int sd_event_add_signal(
callback = signal_exit_callback;
r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
- if (r < 0)
- return -errno;
+ if (r != 0)
+ return -r;
if (!sigismember(&ss, sig))
return -EBUSY;
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index c092e56b7a..c1a3b49483 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -20,10 +20,12 @@
***/
#include "sd-event.h"
+
+#include "fd-util.h"
#include "log.h"
-#include "util.h"
#include "macro.h"
#include "signal-util.h"
+#include "util.h"
static int prepare_handler(sd_event_source *s, void *userdata) {
log_info("preparing %c", PTR_TO_INT(userdata));
diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h
index fedccdec72..13fddfc8ad 100644
--- a/src/libsystemd/sd-hwdb/hwdb-internal.h
+++ b/src/libsystemd/sd-hwdb/hwdb-internal.h
@@ -19,6 +19,7 @@
#pragma once
#include "sparse-endian.h"
+#include "util.h"
#define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }
diff --git a/src/libsystemd/sd-hwdb/hwdb-util.h b/src/libsystemd/sd-hwdb/hwdb-util.h
index ee020a2942..d366c6fa41 100644
--- a/src/libsystemd/sd-hwdb/hwdb-util.h
+++ b/src/libsystemd/sd-hwdb/hwdb-util.h
@@ -21,10 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-
#include "sd-hwdb.h"
+#include "util.h"
+
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref);
#define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp)
diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c
index f0316be659..0e034863d6 100644
--- a/src/libsystemd/sd-hwdb/sd-hwdb.c
+++ b/src/libsystemd/sd-hwdb/sd-hwdb.c
@@ -19,21 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
+#include <fnmatch.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <fnmatch.h>
+#include <string.h>
#include <sys/mman.h>
#include "sd-hwdb.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "hashmap.h"
-#include "refcnt.h"
-
-#include "hwdb-util.h"
#include "hwdb-internal.h"
+#include "hwdb-util.h"
+#include "refcnt.h"
+#include "string-util.h"
struct sd_hwdb {
RefCount n_ref;
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index eb539ad318..1e17ea6a06 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -23,10 +23,14 @@
#include <fcntl.h>
#include <unistd.h>
-#include "util.h"
-#include "macro.h"
#include "sd-id128.h"
+
+#include "fd-util.h"
+#include "io-util.h"
+#include "macro.h"
+#include "hexdecoct.h"
#include "random-util.h"
+#include "util.h"
_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
unsigned n;
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 265c7c7db2..3f2e459825 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -19,21 +19,33 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <sys/inotify.h>
#include <poll.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <unistd.h>
-#include "util.h"
+#include "sd-login.h"
+
+#include "alloc-util.h"
#include "cgroup-util.h"
-#include "macro.h"
-#include "strv.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "login-util.h"
#include "formats-util.h"
+#include "fs-util.h"
#include "hostname-util.h"
-#include "sd-login.h"
+#include "io-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
/* Error codes:
*
@@ -920,9 +932,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
*(char*) (mempcpy(buf, word, l)) = 0;
- if (safe_atoi(buf, &ifi) < 0)
- continue;
- if (ifi <= 0)
+ if (parse_ifindex(buf, &ifi) < 0)
continue;
if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index f734ce9eee..b0f94c9522 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -22,11 +22,14 @@
#include <poll.h>
#include <string.h>
-#include "systemd/sd-login.h"
+#include "sd-login.h"
-#include "util.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
static void test_login(void) {
_cleanup_close_pair_ int pair[2] = { -1, -1 };
diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c
index e2f637f7f9..a00865b56b 100644
--- a/src/libsystemd/sd-netlink/local-addresses.c
+++ b/src/libsystemd/sd-netlink/local-addresses.c
@@ -21,6 +21,8 @@
***/
#include "sd-netlink.h"
+
+#include "alloc-util.h"
#include "netlink-util.h"
#include "macro.h"
#include "local-addresses.h"
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index 4026e2c341..8519a4d523 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -23,13 +23,12 @@
#include <linux/netlink.h>
-#include "refcnt.h"
-#include "prioq.h"
-#include "list.h"
-
#include "sd-netlink.h"
+#include "list.h"
#include "netlink-types.h"
+#include "prioq.h"
+#include "refcnt.h"
#define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
@@ -64,6 +63,9 @@ struct sd_netlink {
struct sockaddr_nl nl;
} sockaddr;
+ Hashmap *broadcast_group_refs;
+ bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
+
sd_netlink_message **rqueue;
unsigned rqueue_size;
size_t rqueue_allocated;
@@ -124,7 +126,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
int socket_open(int family);
int socket_bind(sd_netlink *nl);
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
int socket_read_message(sd_netlink *nl);
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 0d8e37b856..03971b3596 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -23,16 +23,17 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
@@ -149,6 +150,15 @@ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
return 0;
}
+int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
+ assert_return(m, -EINVAL);
+ assert_return(flags, -EINVAL);
+
+ m->hdr->nlmsg_flags = flags;
+
+ return 0;
+}
+
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
assert_return(m, -EINVAL);
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index 84ff7c38c9..13945202e4 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -23,16 +23,17 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
+#include "alloc-util.h"
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
int socket_open(int family) {
int fd;
@@ -44,6 +45,65 @@ int socket_open(int family) {
return fd;
}
+static int broadcast_groups_get(sd_netlink *nl) {
+ _cleanup_free_ uint32_t *groups = NULL;
+ socklen_t len = 0, old_len;
+ unsigned i, j;
+ int r;
+
+ assert(nl);
+ assert(nl->fd > 0);
+
+ r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
+ if (r < 0) {
+ if (errno == ENOPROTOOPT) {
+ nl->broadcast_group_dont_leave = true;
+ return 0;
+ } else
+ return -errno;
+ }
+
+ if (len == 0)
+ return 0;
+
+ groups = new0(uint32_t, len);
+ if (!groups)
+ return -ENOMEM;
+
+ old_len = len;
+
+ r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
+ if (r < 0)
+ return -errno;
+
+ if (old_len != len)
+ return -EIO;
+
+ r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < len; i++) {
+ for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
+ uint32_t offset;
+ unsigned group;
+
+ offset = 1U << j;
+
+ if (!(groups[i] & offset))
+ continue;
+
+ group = i * sizeof(uint32_t) * 8 + j + 1;
+
+ r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
int socket_bind(sd_netlink *nl) {
socklen_t addrlen;
int r, one = 1;
@@ -63,11 +123,32 @@ int socket_bind(sd_netlink *nl) {
if (r < 0)
return -errno;
+ r = broadcast_groups_get(nl);
+ if (r < 0)
+ return r;
+
return 0;
}
+static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
+ assert(nl);
+
+ return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
+}
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
+static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
+ int r;
+
+ assert(nl);
+
+ r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int broadcast_group_join(sd_netlink *nl, unsigned group) {
int r;
assert(nl);
@@ -81,6 +162,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
return 0;
}
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
+ unsigned n_ref;
+ int r;
+
+ assert(nl);
+
+ n_ref = broadcast_group_get_ref(nl, group);
+
+ n_ref ++;
+
+ r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+ if (r < 0)
+ return r;
+
+ r = broadcast_group_set_ref(nl, group, n_ref);
+ if (r < 0)
+ return r;
+
+ if (n_ref > 1)
+ /* not yet in the group */
+ return 0;
+
+ r = broadcast_group_join(nl, group);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
+ int r;
+
+ assert(nl);
+ assert(nl->fd >= 0);
+ assert(group > 0);
+
+ if (nl->broadcast_group_dont_leave)
+ return 0;
+
+ r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
+ unsigned n_ref;
+ int r;
+
+ assert(nl);
+
+ n_ref = broadcast_group_get_ref(nl, group);
+
+ assert(n_ref > 0);
+
+ n_ref --;
+
+ r = broadcast_group_set_ref(nl, group, n_ref);
+ if (r < 0)
+ return r;
+
+ if (n_ref > 0)
+ /* still refs left */
+ return 0;
+
+ r = broadcast_group_leave(nl, group);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
/* returns the number of bytes sent, or a negative error code */
int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
union {
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 2128329191..cf0a6248d6 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -28,16 +28,15 @@
#include <linux/if_bridge.h>
#include <linux/if_addr.h>
#include <linux/if.h>
-
#include <linux/ip.h>
#include <linux/if_link.h>
#include <linux/if_tunnel.h>
#include "macro.h"
-#include "util.h"
-
-#include "netlink-types.h"
#include "missing.h"
+#include "netlink-types.h"
+#include "string-table.h"
+#include "util.h"
/* Maximum ARP IP target defined in kernel */
#define BOND_MAX_ARP_TARGETS 16
@@ -97,7 +96,7 @@ static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
[IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
};
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
+static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = {
[IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 },
/*
@@ -106,6 +105,15 @@ static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
*/
};
+static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = {
+ [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+};
+
static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
[IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
/*
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 482ff6b1c2..6f9fd2993b 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include "sd-netlink.h"
#include "netlink-util.h"
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 9df0aa28bf..acc6c15ff3 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-netlink.h"
#include "util.h"
-#include "sd-netlink.h"
int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret);
uint32_t rtnl_message_get_serial(sd_netlink_message *m);
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 2f31f4ee69..7cccb9b1d5 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -23,16 +23,16 @@
#include <stdbool.h>
#include <unistd.h>
-#include "util.h"
-#include "socket-util.h"
+#include "sd-netlink.h"
+
#include "formats-util.h"
-#include "refcnt.h"
#include "missing.h"
-
-#include "sd-netlink.h"
-#include "netlink-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
+#include "netlink-util.h"
+#include "refcnt.h"
+#include "socket-util.h"
+#include "util.h"
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct rtmsg *rtm;
@@ -99,6 +99,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(protocol, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *protocol = rtm->rtm_protocol;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(scope, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *scope = rtm->rtm_scope;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(tos, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *tos = rtm->rtm_tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(table, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *table = rtm->rtm_table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
struct rtmsg *rtm;
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index d248869c8d..7c24e053cf 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -19,17 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <poll.h>
-
-#include "missing.h"
-#include "macro.h"
-#include "util.h"
-#include "hashmap.h"
+#include <sys/socket.h>
#include "sd-netlink.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hashmap.h"
+#include "macro.h"
+#include "missing.h"
#include "netlink-internal.h"
#include "netlink-util.h"
+#include "socket-util.h"
+#include "util.h"
static int sd_netlink_new(sd_netlink **ret) {
_cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
@@ -183,10 +186,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
sd_event_unref(rtnl->event);
while ((f = rtnl->match_callbacks)) {
- LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
- free(f);
+ sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
}
+ hashmap_free(rtnl->broadcast_group_refs);
+
safe_close(rtnl->fd);
free(rtnl);
}
@@ -856,26 +860,33 @@ int sd_netlink_add_match(sd_netlink *rtnl,
switch (type) {
case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
case RTM_DELLINK:
- r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
if (r < 0)
return r;
break;
case RTM_NEWADDR:
- case RTM_GETADDR:
case RTM_DELADDR:
- r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
if (r < 0)
return r;
- r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
if (r < 0)
return r;
break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -892,23 +903,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl,
sd_netlink_message_handler_t callback,
void *userdata) {
struct match_callback *c;
+ int r;
assert_return(rtnl, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
- /* we should unsubscribe from the broadcast groups at this point, but it is not so
- trivial for a few reasons: the refcounting is a bit of a mess and not obvious
- how it will look like after we add genetlink support, and it is also not possible
- to query what broadcast groups were subscribed to when we inherit the socket to get
- the initial refcount. The latter could indeed be done for the first 32 broadcast
- groups (which incidentally is all we currently support in .socket units anyway),
- but we better not rely on only ever using 32 groups. */
LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
if (c->callback == callback && c->type == type && c->userdata == userdata) {
LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
free(c);
+ switch (type) {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
+ if (r < 0)
+ return r;
+
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
+ if (r < 0)
+ return r;
+
+ break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
+ if (r < 0)
+ return r;
+
+ r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
return 1;
}
diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c
index 9867eec065..7180175970 100644
--- a/src/libsystemd/sd-netlink/test-local-addresses.c
+++ b/src/libsystemd/sd-netlink/test-local-addresses.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "in-addr-util.h"
#include "local-addresses.h"
#include "af-list.h"
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index c9cb415ca0..58b774e0e1 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -19,16 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/ether.h>
#include <net/if.h>
+#include <netinet/ether.h>
-#include "util.h"
-#include "macro.h"
#include "sd-netlink.h"
-#include "socket-util.h"
-#include "netlink-util.h"
+
+#include "ether-addr-util.h"
#include "event-util.h"
+#include "macro.h"
#include "missing.h"
+#include "netlink-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_message_link_bridge(sd_netlink *rtnl) {
_cleanup_netlink_message_unref_ sd_netlink_message *message = NULL;
diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c
index 48958e8a9f..a2d6c59314 100644
--- a/src/libsystemd/sd-network/network-util.c
+++ b/src/libsystemd/sd-network/network-util.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "network-util.h"
+#include "strv.h"
bool network_is_online(void) {
_cleanup_free_ char *state = NULL;
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index 87d87359b8..efbceba83d 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -20,16 +20,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
-#include <sys/inotify.h>
#include <poll.h>
+#include <string.h>
+#include <sys/inotify.h>
-#include "util.h"
+#include "sd-network.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "macro.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "fileio.h"
-#include "sd-network.h"
+#include "util.h"
_public_ int sd_network_get_operational_state(char **state) {
_cleanup_free_ char *s = NULL;
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
index 7363be2794..480f1ad065 100644
--- a/src/libsystemd/sd-path/sd-path.c
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -17,12 +17,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "sd-path.h"
+
+#include "alloc-util.h"
#include "architecture.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "missing.h"
#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "sd-path.h"
-#include "missing.h"
+#include "user-util.h"
+#include "util.h"
static int from_environment(const char *envname, const char *fallback, const char **ret) {
assert(ret);
diff --git a/src/libsystemd/sd-resolve/resolve-util.h b/src/libsystemd/sd-resolve/resolve-util.h
index 019cdaffe1..51a8a8af83 100644
--- a/src/libsystemd/sd-resolve/resolve-util.h
+++ b/src/libsystemd/sd-resolve/resolve-util.h
@@ -21,9 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "sd-resolve.h"
+#include "util.h"
+
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve_query*, sd_resolve_query_unref);
diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c
index 888b372c99..34a0b03f92 100644
--- a/src/libsystemd/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/sd-resolve/sd-resolve.c
@@ -19,24 +19,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <signal.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
#include <errno.h>
+#include <poll.h>
+#include <pthread.h>
#include <resolv.h>
+#include <signal.h>
#include <stdint.h>
-#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/prctl.h>
-#include <poll.h>
+#include <unistd.h>
-#include "util.h"
+#include "sd-resolve.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "list.h"
-#include "socket-util.h"
#include "missing.h"
#include "resolve-util.h"
-#include "sd-resolve.h"
+#include "socket-util.h"
+#include "util.h"
#define WORKERS_MIN 1U
#define WORKERS_MAX 16U
@@ -580,12 +584,8 @@ static void resolve_free(sd_resolve *resolve) {
}
/* Now terminate them and wait until they are gone. */
- for (i = 0; i < resolve->n_valid_workers; i++) {
- for (;;) {
- if (pthread_join(resolve->workers[i], NULL) != EINTR)
- break;
- }
- }
+ for (i = 0; i < resolve->n_valid_workers; i++)
+ pthread_join(resolve->workers[i], NULL);
/* Close all communication channels */
for (i = 0; i < _FD_MAX; i++)
diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c
index e8056529f5..05544a584c 100644
--- a/src/libsystemd/sd-resolve/test-resolve.c
+++ b/src/libsystemd/sd-resolve/test-resolve.c
@@ -20,18 +20,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <sys/socket.h>
#include <arpa/inet.h>
-#include <stdio.h>
+#include <errno.h>
#include <netinet/in.h>
#include <resolv.h>
-#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
-#include "socket-util.h"
#include "sd-resolve.h"
-#include "resolve-util.h"
+
+#include "alloc-util.h"
#include "macro.h"
+#include "resolve-util.h"
+#include "socket-util.h"
+#include "string-util.h"
static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
const struct addrinfo *i;
diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c
index 6f2aa6064c..381397cc52 100644
--- a/src/libsystemd/sd-utf8/sd-utf8.c
+++ b/src/libsystemd/sd-utf8/sd-utf8.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-utf8.h"
+
#include "util.h"
#include "utf8.h"
-#include "sd-utf8.h"
_public_ const char *sd_utf8_is_valid(const char *s) {
assert_return(s, NULL);
diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h
index aa36b8cb12..40d59201cf 100644
--- a/src/libudev/libudev-device-internal.h
+++ b/src/libudev/libudev-device-internal.h
@@ -21,9 +21,10 @@
#pragma once
#include "libudev.h"
-#include "libudev-private.h"
#include "sd-device.h"
+#include "libudev-private.h"
+
/**
* udev_device:
*
diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c
index 4b9c053b54..2d3e62410c 100644
--- a/src/libudev/libudev-device-private.c
+++ b/src/libudev/libudev-device-private.c
@@ -19,10 +19,10 @@
***/
#include "libudev.h"
-#include "libudev-private.h"
-#include "libudev-device-internal.h"
#include "device-private.h"
+#include "libudev-device-internal.h"
+#include "libudev-private.h"
int udev_device_tag_index(struct udev_device *udev_device, struct udev_device *udev_device_old, bool add) {
sd_device *device_old = NULL;
diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c
index 9a8d682107..814e016800 100644
--- a/src/libudev/libudev-device.c
+++ b/src/libudev/libudev-device.c
@@ -18,29 +18,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
+#include <ctype.h>
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
-#include <ctype.h>
+#include <linux/sockios.h>
#include <net/if.h>
-#include <sys/stat.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
-#include <linux/sockios.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "libudev.h"
#include "sd-device.h"
-#include "device-util.h"
-#include "device-private.h"
-#include "libudev.h"
-#include "libudev-private.h"
+#include "alloc-util.h"
+#include "device-private.h"
+#include "device-util.h"
#include "libudev-device-internal.h"
+#include "libudev-private.h"
+#include "parse-util.h"
/**
* SECTION:libudev-device
diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c
index df088946df..442f9615f2 100644
--- a/src/libudev/libudev-enumerate.c
+++ b/src/libudev/libudev-enumerate.c
@@ -18,22 +18,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <errno.h>
-#include <string.h>
#include <dirent.h>
+#include <errno.h>
#include <fnmatch.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
#include "libudev.h"
-#include "libudev-device-internal.h"
#include "sd-device.h"
-#include "device-util.h"
-#include "device-enumerator-private.h"
+#include "alloc-util.h"
+#include "device-enumerator-private.h"
+#include "device-util.h"
+#include "libudev-device-internal.h"
/**
* SECTION:libudev-enumerate
diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c
index 98951fb85b..eba698d163 100644
--- a/src/libudev/libudev-hwdb.c
+++ b/src/libudev/libudev-hwdb.c
@@ -17,9 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "libudev-private.h"
#include "sd-hwdb.h"
+
+#include "alloc-util.h"
#include "hwdb-util.h"
+#include "libudev-private.h"
/**
* SECTION:libudev-hwdb
diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c
index 19e9130be0..da496ed456 100644
--- a/src/libudev/libudev-list.c
+++ b/src/libudev/libudev-list.c
@@ -17,11 +17,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stddef.h>
#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
+#include "alloc-util.h"
#include "libudev-private.h"
/**
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 282aa2b0d9..f870eba9eb 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -17,22 +17,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
+#include <linux/filter.h>
+#include <linux/netlink.h>
+#include <poll.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
#include <string.h>
-#include <poll.h>
#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/filter.h>
+#include <unistd.h>
#include "libudev.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
#include "libudev-private.h"
-#include "socket-util.h"
#include "missing.h"
-#include "formats-util.h"
+#include "mount-util.h"
+#include "socket-util.h"
+#include "string-util.h"
/**
* SECTION:libudev-monitor
@@ -408,10 +414,8 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
if (err >= 0)
monitor_set_nl_address(udev_monitor);
- else {
- log_debug_errno(errno, "bind failed: %m");
- return -errno;
- }
+ else
+ return log_debug_errno(errno, "bind failed: %m");
/* enable receiving of sender credentials */
err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h
index 1240ea79cc..5f50496291 100644
--- a/src/libudev/libudev-private.h
+++ b/src/libudev/libudev-private.h
@@ -25,10 +25,11 @@
#include <stdbool.h>
#include "libudev.h"
+
#include "macro.h"
-#include "util.h"
#include "mkdir.h"
#include "strxcpyx.h"
+#include "util.h"
#define READ_END 0
#define WRITE_END 1
@@ -135,8 +136,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor
#define UTIL_NAME_SIZE 512
#define UTIL_LINE_SIZE 16384
#define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
-ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size);
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
int util_log_priority(const char *priority);
size_t util_path_encode(const char *src, char *dest, size_t size);
void util_remove_trailing_chars(char *path, char c);
diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c
index 11e15d13e6..58410b1b8f 100644
--- a/src/libudev/libudev-queue.c
+++ b/src/libudev/libudev-queue.c
@@ -24,6 +24,9 @@
#include <errno.h>
#include <sys/inotify.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "libudev-private.h"
/**
diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c
index f4656277c6..574cfeac85 100644
--- a/src/libudev/libudev-util.c
+++ b/src/libudev/libudev-util.c
@@ -17,18 +17,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
+#include <ctype.h>
#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
+#include <unistd.h>
-#include "device-nodes.h"
#include "libudev.h"
+
+#include "MurmurHash2.h"
+#include "device-nodes.h"
#include "libudev-private.h"
+#include "syslog-util.h"
#include "utf8.h"
-#include "MurmurHash2.h"
/**
* SECTION:libudev-util
@@ -100,52 +102,6 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string,
return 0;
}
-ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
-{
- char path[UTIL_PATH_SIZE];
- char target[UTIL_PATH_SIZE];
- ssize_t len;
- const char *pos;
-
- strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
- len = readlink(path, target, sizeof(target));
- if (len <= 0 || len == (ssize_t)sizeof(target))
- return -1;
- target[len] = '\0';
- pos = strrchr(target, '/');
- if (pos == NULL)
- return -1;
- pos = &pos[1];
- return strscpy(value, size, pos);
-}
-
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
-{
- char link_target[UTIL_PATH_SIZE];
-
- ssize_t len;
- int i;
- int back;
- char *base = NULL;
-
- len = readlink(syspath, link_target, sizeof(link_target));
- if (len <= 0 || len == (ssize_t)sizeof(link_target))
- return -1;
- link_target[len] = '\0';
-
- for (back = 0; startswith(&link_target[back * 3], "../"); back++)
- ;
- for (i = 0; i <= back; i++) {
- base = strrchr(syspath, '/');
- if (base == NULL)
- return -EINVAL;
- base[0] = '\0';
- }
-
- strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
- return 0;
-}
-
int util_log_priority(const char *priority)
{
char *endptr;
diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c
index ec15d2576b..63fb05547d 100644
--- a/src/libudev/libudev.c
+++ b/src/libudev/libudev.c
@@ -17,16 +17,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <ctype.h>
+#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
#include <string.h>
-#include <ctype.h>
#include "libudev.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
#include "libudev-private.h"
#include "missing.h"
+#include "string-util.h"
/**
* SECTION:libudev
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 4a91c7420a..4a339dcfd4 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -20,26 +20,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <ftw.h>
+#include <getopt.h>
#include <locale.h>
-#include <stdlib.h>
#include <stdbool.h>
-#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ftw.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "util.h"
-#include "spawn-polkit-agent.h"
-#include "build.h"
-#include "strv.h"
-#include "pager.h"
-#include "set.h"
+#include "bus-util.h"
#include "def.h"
-#include "virt.h"
+#include "fd-util.h"
#include "fileio.h"
#include "locale-util.h"
+#include "pager.h"
+#include "set.h"
+#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "util.h"
+#include "virt.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -546,9 +547,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_CONVERT:
arg_convert = false;
@@ -678,7 +677,7 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
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 e3eef4a610..720cbbaaba 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -24,25 +24,29 @@
#include <string.h>
#include <unistd.h>
+#ifdef HAVE_XKBCOMMON
+#include <xkbcommon/xkbcommon.h>
+#endif
+
#include "sd-bus.h"
-#include "util.h"
-#include "mkdir.h"
-#include "strv.h"
-#include "def.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "fileio-label.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-error.h"
#include "bus-message.h"
+#include "bus-util.h"
+#include "def.h"
+#include "env-util.h"
#include "event-util.h"
+#include "fd-util.h"
+#include "fileio-label.h"
+#include "fileio.h"
#include "locale-util.h"
+#include "mkdir.h"
+#include "path-util.h"
#include "selinux-util.h"
-
-#ifdef HAVE_XKBCOMMON
-#include <xkbcommon/xkbcommon.h>
-#endif
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
enum {
/* We don't list LC_ALL here on purpose. People should be
diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index c53ea8add7..70fef332f7 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -19,21 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
#include <getopt.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
-#include "util.h"
-#include "build.h"
-#include "strv.h"
+#include "bus-util.h"
+#include "fd-util.h"
#include "formats-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
static const char* arg_what = "idle:sleep:shutdown";
static const char* arg_who = NULL;
@@ -179,9 +182,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_WHAT:
arg_what = optarg;
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index be52518161..aff68a49fe 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -19,31 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
#include <locale.h>
+#include <string.h>
+#include <unistd.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-util.h"
+#include "cgroup-show.h"
+#include "cgroup-util.h"
#include "log.h"
-#include "util.h"
+#include "logs-show.h"
#include "macro.h"
#include "pager.h"
-#include "build.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "spawn-polkit-agent.h"
#include "strv.h"
-#include "unit-name.h"
#include "sysfs-show.h"
-#include "logs-show.h"
-#include "cgroup-show.h"
-#include "cgroup-util.h"
-#include "spawn-polkit-agent.h"
-#include "verbs.h"
-#include "process-util.h"
#include "terminal-util.h"
-#include "signal-util.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
+#include "verbs.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -1416,9 +1419,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'p': {
r = strv_extend(&arg_property, optarg);
@@ -1544,7 +1545,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c
index 466225d69c..d0dd569a03 100644
--- a/src/login/logind-acl.c
+++ b/src/login/logind-acl.c
@@ -22,12 +22,17 @@
#include <errno.h>
#include <string.h>
-#include "util.h"
-#include "formats-util.h"
#include "acl-util.h"
-#include "set.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "logind-acl.h"
+#include "set.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "util.h"
static int flush_acl(acl_t acl) {
acl_entry_t i;
diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h
index ec09843a78..93e9ed02eb 100644
--- a/src/login/logind-acl.h
+++ b/src/login/logind-acl.h
@@ -23,7 +23,8 @@
#include <sys/types.h>
#include <stdbool.h>
-#include <libudev.h>
+
+#include "libudev.h"
#ifdef HAVE_ACL
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index f635fb1b63..185108f8f1 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -21,15 +21,18 @@
#include <unistd.h>
-#include "conf-parser.h"
-#include "special.h"
-#include "sleep-config.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-error.h"
-#include "logind-action.h"
+#include "bus-util.h"
+#include "conf-parser.h"
#include "formats-util.h"
+#include "logind-action.h"
#include "process-util.h"
+#include "sleep-config.h"
+#include "special.h"
+#include "string-table.h"
#include "terminal-util.h"
+#include "user-util.h"
int manager_handle_action(
Manager *m,
@@ -147,7 +150,6 @@ int manager_handle_action(
offending->uid, strna(u),
offending->pid, strna(comm));
- warn_melody();
return -EPERM;
}
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index ff98065371..e9b424b5f6 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -36,6 +36,7 @@ typedef enum HandleAction {
} HandleAction;
#include "logind.h"
+#include "logind-inhibit.h"
int manager_handle_action(
Manager *m,
diff --git a/src/login/logind-button.c b/src/login/logind-button.c
index f40e35a8cb..b08b69dbfc 100644
--- a/src/login/logind-button.c
+++ b/src/login/logind-button.c
@@ -19,16 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <linux/input.h>
#include "sd-messages.h"
-#include "util.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
#include "logind-button.h"
+#include "string-util.h"
+#include "util.h"
Button* button_new(Manager *m, const char *name) {
Button *b;
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 6c05c11dbd..b3f30c8dc9 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -25,13 +25,16 @@
#include <pwd.h>
#include <linux/vt.h>
-#include "strv.h"
-#include "cgroup-util.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-error.h"
-#include "udev-util.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
#include "logind.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "udev-util.h"
+#include "user-util.h"
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
Device *d;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 22e37a1638..7890d68aa0 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -20,29 +20,36 @@
***/
#include <errno.h>
+#include <pwd.h>
#include <string.h>
#include <unistd.h>
-#include <pwd.h>
#include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "special.h"
-#include "sleep-config.h"
-#include "fileio-label.h"
-#include "unit-name.h"
-#include "audit.h"
-#include "bus-util.h"
-#include "bus-error.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
#include "bus-common-errors.h"
-#include "udev-util.h"
-#include "selinux-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "dirent-util.h"
#include "efivars.h"
-#include "logind.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio-label.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "logind.h"
+#include "mkdir.h"
+#include "path-util.h"
#include "process-util.h"
+#include "selinux-util.h"
+#include "sleep-config.h"
+#include "special.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "udev-util.h"
+#include "unit-name.h"
+#include "user-util.h"
#include "utmp-wtmp.h"
int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) {
@@ -1352,24 +1359,26 @@ static int bus_manager_log_shutdown(
return 0;
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
- p = "MESSAGE=System is powering down.";
+ p = "MESSAGE=System is powering down";
q = "SHUTDOWN=power-off";
} else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
- p = "MESSAGE=System is halting.";
+ p = "MESSAGE=System is halting";
q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
- p = "MESSAGE=System is rebooting.";
+ p = "MESSAGE=System is rebooting";
q = "SHUTDOWN=reboot";
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
- p = "MESSAGE=System is rebooting with kexec.";
+ p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec";
} else {
- p = "MESSAGE=System is shutting down.";
+ p = "MESSAGE=System is shutting down";
q = NULL;
}
- if (!isempty(m->wall_message))
- p = strjoina(p, " (", m->wall_message, ")");
+ if (isempty(m->wall_message))
+ p = strjoina(p, ".");
+ else
+ p = strjoina(p, " (", m->wall_message, ").");
return log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
@@ -2022,7 +2031,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
}
utmp_wall("The system shutdown has been cancelled",
- lookup_uid(uid), tty, logind_wall_tty_filter, m);
+ uid_to_name(uid), tty, logind_wall_tty_filter, m);
}
return sd_bus_reply_method_return(message, "b", cancelled);
@@ -2586,7 +2595,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
if (m->action_job && streq(m->action_job, path)) {
- log_info("Operation finished.");
+ log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
/* Tell people that they now may take a lock again */
send_prepare_for(m, m->action_what, false);
diff --git a/src/login/logind-device.c b/src/login/logind-device.c
index ee4c45fb8d..ffb9162e56 100644
--- a/src/login/logind-device.c
+++ b/src/login/logind-device.c
@@ -21,8 +21,9 @@
#include <string.h>
-#include "util.h"
+#include "alloc-util.h"
#include "logind-device.h"
+#include "util.h"
Device* device_new(Manager *m, const char *sysfs, bool master) {
Device *d;
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index 0c9c1e5e97..33fbdde557 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -24,11 +24,18 @@
#include <string.h>
#include <unistd.h>
-#include "util.h"
-#include "mkdir.h"
-#include "logind-inhibit.h"
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
+#include "logind-inhibit.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
Inhibitor* inhibitor_new(Manager *m, const char* id) {
Inhibitor *i;
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 346e1d2cec..43b578f364 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -22,13 +22,15 @@
#include <errno.h>
#include <string.h>
-#include "util.h"
-#include "bus-util.h"
-#include "strv.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-label.h"
-#include "logind.h"
+#include "bus-util.h"
#include "logind-seat.h"
+#include "logind.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
static int property_get_active_session(
sd_bus *bus,
diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c
index 8d13a63688..1f4936cebe 100644
--- a/src/login/logind-seat.c
+++ b/src/login/logind-seat.c
@@ -20,17 +20,23 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <unistd.h>
#include "sd-messages.h"
-#include "logind-seat.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
#include "logind-acl.h"
-#include "util.h"
+#include "logind-seat.h"
#include "mkdir.h"
-#include "formats-util.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
Seat *seat_new(Manager *m, const char *id) {
Seat *s;
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index e6b4ccd7c6..7810199a54 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -22,15 +22,16 @@
#include <errno.h>
#include <string.h>
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-label.h"
-
-#include "logind.h"
-#include "logind-session.h"
+#include "bus-util.h"
+#include "fd-util.h"
#include "logind-session-device.h"
+#include "logind-session.h"
+#include "logind.h"
+#include "strv.h"
+#include "util.h"
static int property_get_user(
sd_bus *bus,
diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c
index 656f268dba..9bf3ca0995 100644
--- a/src/login/logind-session-device.c
+++ b/src/login/logind-session-device.c
@@ -20,16 +20,19 @@
***/
#include <fcntl.h>
-#include <libudev.h>
#include <linux/input.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
-#include "util.h"
-#include "missing.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
#include "bus-util.h"
+#include "fd-util.h"
#include "logind-session-device.h"
+#include "missing.h"
+#include "util.h"
enum SessionDeviceNotifications {
SESSION_DEVICE_RESUME,
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index f5fe030b07..1d561a6f8a 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -21,24 +21,33 @@
#include <errno.h>
#include <fcntl.h>
-#include <linux/vt.h>
#include <linux/kd.h>
+#include <linux/vt.h>
#include <signal.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "sd-messages.h"
-#include "util.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "fileio.h"
-#include "audit.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
#include "bus-error.h"
-#include "logind-session.h"
+#include "bus-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "io-util.h"
+#include "logind-session.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-table.h"
#include "terminal-util.h"
+#include "user-util.h"
+#include "util.h"
#define RELEASE_USEC (20*USEC_PER_SEC)
@@ -987,7 +996,7 @@ static int session_open_vt(Session *s) {
sprintf(path, "/dev/tty%u", s->vtnr);
s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY);
if (s->vtfd < 0)
- return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id);
+ return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id);
return s->vtfd;
}
@@ -1049,9 +1058,13 @@ error:
}
void session_restore_vt(Session *s) {
+
+ static const struct vt_mode mode = {
+ .mode = VT_AUTO,
+ };
+
_cleanup_free_ char *utf8 = NULL;
- int vt, kb = K_XLATE;
- struct vt_mode mode = { 0 };
+ int vt, kb, old_fd;
/* We need to get a fresh handle to the virtual terminal,
* since the old file-descriptor is potentially in a hung-up
@@ -1059,7 +1072,7 @@ void session_restore_vt(Session *s) {
* little dance to avoid having the terminal be available
* for reuse before we've cleaned it up.
*/
- int old_fd = s->vtfd;
+ old_fd = s->vtfd;
s->vtfd = -1;
vt = session_open_vt(s);
@@ -1072,13 +1085,13 @@ void session_restore_vt(Session *s) {
if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
kb = K_UNICODE;
+ else
+ kb = K_XLATE;
(void) ioctl(vt, KDSKBMODE, kb);
- mode.mode = VT_AUTO;
(void) ioctl(vt, VT_SETMODE, &mode);
-
- fchown(vt, 0, -1);
+ (void) fchown(vt, 0, (gid_t) -1);
s->vtfd = safe_close(s->vtfd);
}
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index 20ea2fbdc4..df901f6558 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -22,11 +22,13 @@
#include <errno.h>
#include <string.h>
-#include "strv.h"
+#include "alloc-util.h"
#include "bus-util.h"
-#include "logind.h"
-#include "logind-user.h"
#include "formats-util.h"
+#include "logind-user.h"
+#include "logind.h"
+#include "strv.h"
+#include "user-util.h"
static int property_get_display(
sd_bus *bus,
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 47669afdef..56bc5a010c 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -19,27 +19,35 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mount.h>
+#include <errno.h>
#include <string.h>
+#include <sys/mount.h>
#include <unistd.h>
-#include <errno.h>
-#include "util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "hashmap.h"
-#include "fileio.h"
-#include "path-util.h"
-#include "special.h"
-#include "unit-name.h"
-#include "bus-util.h"
+#include "alloc-util.h"
#include "bus-error.h"
-#include "conf-parser.h"
+#include "bus-util.h"
#include "clean-ipc.h"
-#include "smack-util.h"
+#include "conf-parser.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "hashmap.h"
#include "label.h"
#include "logind-user.h"
+#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "smack-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "util.h"
User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
User *u;
@@ -868,12 +876,12 @@ int config_parse_tmpfs_size(
errno = 0;
ul = strtoul(rvalue, &f, 10);
if (errno != 0 || f != e) {
- log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue);
return 0;
}
if (ul <= 0 || ul >= 100) {
- log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue);
return 0;
}
@@ -883,7 +891,7 @@ int config_parse_tmpfs_size(
r = parse_size(rvalue, 1024, &k);
if (r < 0 || (uint64_t) (size_t) k != k) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 1e13ff01de..3e7a935a34 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -25,15 +25,18 @@
#include <pwd.h>
#include "sd-messages.h"
-#include "strv.h"
-#include "special.h"
-#include "unit-name.h"
-#include "audit.h"
-#include "bus-util.h"
-#include "bus-error.h"
+
+#include "alloc-util.h"
+#include "audit-util.h"
#include "bus-common-errors.h"
-#include "logind.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "formats-util.h"
+#include "logind.h"
+#include "special.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "user-util.h"
#include "utmp-wtmp.h"
_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
@@ -94,7 +97,7 @@ static int warn_wall(Manager *m, usec_t n) {
return 0;
}
- utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid),
+ utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid),
m->scheduled_shutdown_tty, logind_wall_tty_filter, m);
return 1;
diff --git a/src/login/logind.c b/src/login/logind.c
index 8ac2aceb9b..83896ea627 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -20,20 +20,25 @@
***/
#include <errno.h>
-#include <libudev.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#include "libudev.h"
#include "sd-daemon.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
-#include "udev-util.h"
+#include "bus-util.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "formats-util.h"
-#include "signal-util.h"
#include "logind.h"
+#include "signal-util.h"
+#include "strv.h"
+#include "udev-util.h"
static void manager_free(Manager *m);
@@ -292,8 +297,7 @@ static int manager_enumerate_seats(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/seats: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -329,8 +333,7 @@ static int manager_enumerate_linger_users(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -365,8 +368,7 @@ static int manager_enumerate_users(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /run/systemd/users: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/users: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -406,8 +408,7 @@ static int manager_enumerate_sessions(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -453,8 +454,7 @@ static int manager_enumerate_inhibitors(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
@@ -744,8 +744,7 @@ static int manager_connect_console(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m");
}
r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m);
diff --git a/src/login/logind.h b/src/login/logind.h
index 7990da5a93..44e05d8b01 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -22,20 +22,21 @@
***/
#include <stdbool.h>
-#include <libudev.h>
-#include "sd-event.h"
+#include "libudev.h"
#include "sd-bus.h"
-#include "list.h"
+#include "sd-event.h"
+
#include "hashmap.h"
+#include "list.h"
#include "set.h"
typedef struct Manager Manager;
+#include "logind-action.h"
+#include "logind-button.h"
#include "logind-device.h"
#include "logind-inhibit.h"
-#include "logind-button.h"
-#include "logind-action.h"
struct Manager {
sd_event *event;
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index f66f1ce842..0d61f528db 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -19,31 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <endian.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/file.h>
#include <pwd.h>
-#include <endian.h>
-
-#include <security/pam_modules.h>
#include <security/_pam_macros.h>
-#include <security/pam_modutil.h>
#include <security/pam_ext.h>
#include <security/pam_misc.h>
+#include <security/pam_modules.h>
+#include <security/pam_modutil.h>
+#include <sys/file.h>
+#include "alloc-util.h"
+#include "audit-util.h"
#include "bus-common-errors.h"
-#include "util.h"
-#include "audit.h"
-#include "macro.h"
-#include "strv.h"
+#include "bus-error.h"
#include "bus-util.h"
#include "def.h"
-#include "socket-util.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "bus-error.h"
#include "formats-util.h"
-#include "terminal-util.h"
#include "hostname-util.h"
+#include "login-util.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
static int parse_argv(
pam_handle_t *handle,
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index 9a9fb7622d..e9ca4bb03d 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -21,13 +21,17 @@
#include <errno.h>
#include <string.h>
-#include <libudev.h>
-#include "util.h"
-#include "sysfs-show.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
+#include "locale-util.h"
#include "path-util.h"
-#include "udev-util.h"
+#include "string-util.h"
+#include "sysfs-show.h"
#include "terminal-util.h"
+#include "udev-util.h"
+#include "util.h"
static int show_sysfs_one(
struct udev *udev,
@@ -114,7 +118,7 @@ static int show_sysfs_one(
"%s%s:%s%s%s%s",
is_master ? "[MASTER] " : "",
subsystem, sysname,
- name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0)
+ name ? " \"" : "", strempty(name), name ? "\"" : "") < 0)
return -ENOMEM;
free(k);
diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c
index 03516de916..d0727ff7c7 100644
--- a/src/login/test-inhibit.c
+++ b/src/login/test-inhibit.c
@@ -21,10 +21,12 @@
#include <unistd.h>
-#include "macro.h"
-#include "util.h"
#include "sd-bus.h"
+
#include "bus-util.h"
+#include "fd-util.h"
+#include "macro.h"
+#include "util.h"
static int inhibit(sd_bus *bus, const char *what) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c
deleted file mode 100644
index 0f7748e453..0000000000
--- a/src/machine-id-commit/machine-id-commit.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-*- 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 <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 = NULL;
-
-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)
- goto finish;
-
- r = machine_id_commit(arg_root);
-
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 20cb60b804..f1165ea09c 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -19,24 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
-#include "machine-id-setup.h"
#include "log.h"
-#include "build.h"
+#include "machine-id-setup.h"
+#include "util.h"
+#include "path-util.h"
-static const char *arg_root = "";
+static char *arg_root = NULL;
+static bool arg_commit = false;
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Initialize /etc/machine-id from a random source.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --root=ROOT Filesystem root\n",
- program_invocation_short_name);
+ " --root=ROOT Filesystem root\n"
+ " --commit Commit transient ID\n"
+ , program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
@@ -44,16 +47,18 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_ROOT,
+ ARG_COMMIT,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
+ { "commit", no_argument, NULL, ARG_COMMIT },
{}
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -67,12 +72,16 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
- arg_root = optarg;
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
+ break;
+
+ case ARG_COMMIT:
+ arg_commit = true;
break;
case '?':
@@ -98,7 +107,14 @@ int main(int argc, char *argv[]) {
r = parse_argv(argc, argv);
if (r <= 0)
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ goto finish;
+
+ if (arg_commit)
+ r = machine_id_commit(arg_root);
+ else
+ r = machine_id_setup(arg_root);
- return machine_id_setup(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+finish:
+ free(arg_root);
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
index 2453a9ff04..4ec1766033 100644
--- a/src/machine/image-dbus.c
+++ b/src/machine/image-dbus.c
@@ -19,11 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-label.h"
-#include "strv.h"
#include "bus-util.h"
-#include "machine-image.h"
#include "image-dbus.h"
+#include "machine-image.h"
+#include "strv.h"
+#include "user-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index b010c90989..452130a29c 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -29,23 +29,27 @@
#include <libgen.h>
#undef basename
-#include "bus-util.h"
-#include "bus-label.h"
-#include "strv.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
+#include "bus-internal.h"
+#include "bus-label.h"
+#include "bus-util.h"
#include "copy.h"
+#include "env-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "formats-util.h"
+#include "fs-util.h"
#include "in-addr-util.h"
#include "local-addresses.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "bus-internal.h"
-#include "machine.h"
#include "machine-dbus.h"
-#include "formats-util.h"
+#include "machine.h"
+#include "mkdir.h"
+#include "path-util.h"
#include "process-util.h"
-#include "env-util.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "user-util.h"
static int property_get_id(
sd_bus *bus,
@@ -639,7 +643,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
_cleanup_free_ char *pty_name = NULL;
_cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
sd_bus *container_bus = NULL;
- _cleanup_close_ int master = -1;
+ _cleanup_close_ int master = -1, slave = -1;
_cleanup_strv_free_ char **env = NULL, **args = NULL;
Machine *m = userdata;
const char *p, *unit, *user, *path, *description, *utmp_id;
@@ -700,8 +704,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
p = path_startswith(pty_name, "/dev/pts/");
- if (!p)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
+ assert(p);
+
+ slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (slave < 0)
+ return slave;
utmp_id = path_startswith(pty_name, "/dev/");
assert(utmp_id);
@@ -735,20 +742,19 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
description = strjoina("Shell for User ", isempty(user) ? "root" : user);
r = sd_bus_message_append(tm,
- "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
+ "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"Description", "s", description,
- "StandardInput", "s", "tty",
- "StandardOutput", "s", "tty",
- "StandardError", "s", "tty",
- "TTYPath", "s", pty_name,
+ "StandardInputFileDescriptor", "h", slave,
+ "StandardOutputFileDescriptor", "h", slave,
+ "StandardErrorFileDescriptor", "h", slave,
"SendSIGHUP", "b", true,
"IgnoreSIGPIPE", "b", false,
"KillMode", "s", "mixed",
- "TTYVHangup", "b", true,
"TTYReset", "b", true,
"UtmpIdentifier", "s", utmp_id,
"UtmpMode", "s", "user",
- "PAMName", "s", "login");
+ "PAMName", "s", "login",
+ "WorkingDirectory", "s", "-~");
if (r < 0)
return r;
@@ -844,6 +850,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
+ slave = safe_close(slave);
+
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h
index 38b46ad936..194e680e05 100644
--- a/src/machine/machine-dbus.h
+++ b/src/machine/machine-dbus.h
@@ -23,6 +23,8 @@
#include "sd-bus.h"
+#include "machine.h"
+
extern const sd_bus_vtable machine_vtable[];
char *machine_bus_path(Machine *s);
diff --git a/src/machine/machine.c b/src/machine/machine.c
index b52ecd015c..196bc4b8f4 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -19,23 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
#include "sd-messages.h"
-#include "util.h"
-#include "mkdir.h"
-#include "hashmap.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "formats-util.h"
+#include "hashmap.h"
+#include "machine-dbus.h"
+#include "machine.h"
+#include "mkdir.h"
+#include "parse-util.h"
#include "special.h"
+#include "string-table.h"
+#include "terminal-util.h"
#include "unit-name.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "machine.h"
-#include "machine-dbus.h"
-#include "formats-util.h"
+#include "util.h"
+#include "extract-word.h"
Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
Machine *m;
@@ -306,19 +313,26 @@ int machine_load(Machine *m) {
}
if (netif) {
- size_t l, allocated = 0, nr = 0;
- const char *word, *state;
+ size_t allocated = 0, nr = 0;
+ const char *p;
int *ni = NULL;
- FOREACH_WORD(word, l, netif, state) {
- char buf[l+1];
+ p = netif;
+ for(;;) {
+ _cleanup_free_ char *word = NULL;
int ifi;
- *(char*) (mempcpy(buf, word, l)) = 0;
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse NETIF: %s", netif);
+ break;
+ }
- if (safe_atoi(buf, &ifi) < 0)
- continue;
- if (ifi <= 0)
+ if (parse_ifindex(word, &ifi) < 0)
continue;
if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
@@ -538,7 +552,7 @@ int machine_kill(Machine *m, KillWho who, int signo) {
return 0;
}
- /* Otherwise make PID 1 do it for us, for the entire cgroup */
+ /* Otherwise, make PID 1 do it for us, for the entire cgroup */
return manager_kill_unit(m->manager, m->unit, signo, NULL);
}
@@ -571,6 +585,25 @@ int machine_openpt(Machine *m, int flags) {
}
}
+int machine_open_terminal(Machine *m, const char *path, int mode) {
+ assert(m);
+
+ switch (m->class) {
+
+ case MACHINE_HOST:
+ return open_terminal(path, mode);
+
+ case MACHINE_CONTAINER:
+ if (m->leader <= 0)
+ return -EINVAL;
+
+ return open_terminal_in_namespace(m->leader, path, mode);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
MachineOperation *machine_operation_unref(MachineOperation *o) {
if (!o)
return NULL;
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 5f978289f2..ad7f2a162f 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
int machine_openpt(Machine *m, int flags);
+int machine_open_terminal(Machine *m, const char *path, int mode);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index d276fbe956..7e17c7a41c 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -19,44 +19,48 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <unistd.h>
+#include <arpa/inet.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
#include <getopt.h>
#include <locale.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <net/if.h>
+#include <netinet/in.h>
+#include <string.h>
#include <sys/mount.h>
+#include <sys/socket.h>
+#include <unistd.h>
#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "pager.h"
-#include "spawn-polkit-agent.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
-#include "build.h"
-#include "strv.h"
-#include "unit-name.h"
+#include "bus-util.h"
#include "cgroup-show.h"
-#include "logs-show.h"
#include "cgroup-util.h"
-#include "ptyfwd.h"
-#include "event-util.h"
-#include "path-util.h"
-#include "mkdir.h"
#include "copy.h"
-#include "verbs.h"
+#include "env-util.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "hostname-util.h"
#include "import-util.h"
+#include "log.h"
+#include "logs-show.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
+#include "ptyfwd.h"
#include "signal-util.h"
-#include "env-util.h"
-#include "hostname-util.h"
+#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "verbs.h"
+#include "web-util.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -1092,9 +1096,10 @@ static int copy_files(int argc, char *argv[], void *userdata) {
container_path = copy_from ? argv[2] : dest;
if (!path_is_absolute(host_path)) {
- abs_host_path = path_make_absolute_cwd(host_path);
- if (!abs_host_path)
- return log_oom();
+ r = path_make_absolute_cwd(host_path, &abs_host_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make path absolute: %m");
+
host_path = abs_host_path;
}
@@ -1110,10 +1115,8 @@ static int copy_files(int argc, char *argv[], void *userdata) {
argv[1],
copy_from ? container_path : host_path,
copy_from ? host_path : container_path);
- if (r < 0) {
- log_error("Failed to copy: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
return 0;
}
@@ -1173,7 +1176,7 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r
return 0;
}
-static int process_forward(sd_event *event, PTYForward **forward, int master, bool ignore_vhangup, const char *name) {
+static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
char last_char = 0;
bool machine_died;
int ret = 0, r;
@@ -1192,7 +1195,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
- r = pty_forward_new(event, master, ignore_vhangup, false, forward);
+ r = pty_forward_new(event, master, flags, forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -1203,7 +1206,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo
pty_forward_get_last_char(*forward, &last_char);
machine_died =
- ignore_vhangup &&
+ (flags & PTY_FORWARD_IGNORE_VHANGUP) &&
pty_forward_get_ignore_vhangup(*forward) == 0;
*forward = pty_forward_free(*forward);
@@ -1286,7 +1289,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- return process_forward(event, &forward, master, true, machine);
+ return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
}
static int shell_machine(int argc, char *argv[], void *userdata) {
@@ -1390,7 +1393,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- return process_forward(event, &forward, master, false, machine);
+ return process_forward(event, &forward, master, 0, machine);
}
static int remove_image(int argc, char *argv[], void *userdata) {
@@ -2382,7 +2385,7 @@ static int set_limit(int argc, char *argv[], void *userdata) {
uint64_t limit;
int r;
- if (streq(argv[argc-1], "-"))
+ if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
limit = (uint64_t) -1;
else {
r = parse_size(argv[argc-1], 1024, &limit);
@@ -2554,9 +2557,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'p':
r = strv_extend(&arg_property, optarg);
@@ -2747,7 +2748,7 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
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 41bb106d28..7827f063c1 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -24,21 +24,26 @@
#include <unistd.h>
#include "sd-id128.h"
-#include "strv.h"
-#include "path-util.h"
-#include "unit-name.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
+#include "btrfs-util.h"
#include "bus-common-errors.h"
+#include "bus-util.h"
#include "cgroup-util.h"
-#include "btrfs-util.h"
+#include "fd-util.h"
#include "formats-util.h"
-#include "process-util.h"
#include "hostname-util.h"
+#include "image-dbus.h"
+#include "machine-dbus.h"
#include "machine-image.h"
#include "machine-pool.h"
-#include "image-dbus.h"
#include "machined.h"
-#include "machine-dbus.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "user-util.h"
static int property_get_pool_path(
sd_bus *bus,
@@ -79,7 +84,7 @@ static int property_get_pool_usage(
if (fd >= 0) {
BtrfsQuotaInfo q;
- if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+ if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
usage = q.referenced;
}
@@ -115,7 +120,7 @@ static int property_get_pool_limit(
if (fd >= 0) {
BtrfsQuotaInfo q;
- if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
+ if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
size = q.referenced_max;
}
@@ -831,7 +836,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
- r = btrfs_quota_limit("/var/lib/machines", limit);
+ (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
+
+ r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
if (r == -ENOTTY)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
if (r < 0)
diff --git a/src/machine/machined.c b/src/machine/machined.c
index df3cc9972a..a099de9f36 100644
--- a/src/machine/machined.c
+++ b/src/machine/machined.c
@@ -24,15 +24,19 @@
#include <unistd.h>
#include "sd-daemon.h"
-#include "cgroup-util.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-error.h"
-#include "label.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "formats-util.h"
-#include "signal-util.h"
#include "hostname-util.h"
+#include "label.h"
#include "machine-image.h"
#include "machined.h"
+#include "signal-util.h"
Manager *manager_new(void) {
Manager *m;
@@ -146,8 +150,7 @@ int manager_enumerate_machines(Manager *m) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
}
FOREACH_DIRENT(de, d, return -errno) {
diff --git a/src/machine/machined.h b/src/machine/machined.h
index b3e59bf998..dac7a29ed1 100644
--- a/src/machine/machined.h
+++ b/src/machine/machined.h
@@ -23,10 +23,11 @@
#include <stdbool.h>
-#include "list.h"
-#include "hashmap.h"
-#include "sd-event.h"
#include "sd-bus.h"
+#include "sd-event.h"
+
+#include "hashmap.h"
+#include "list.h"
typedef struct Manager Manager;
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 5bbe314ba0..13784763f1 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -20,17 +20,21 @@
***/
#include <errno.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <limits.h>
#include <getopt.h>
#include <libkmod.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "log.h"
-#include "util.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
#include "strv.h"
-#include "conf-files.h"
-#include "build.h"
+#include "util.h"
static char **arg_proc_cmdline_modules = NULL;
@@ -51,7 +55,7 @@ static int add_modules(const char *p) {
if (!k)
return log_oom();
- if (strv_extend_strv(&arg_proc_cmdline_modules, k) < 0)
+ if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0)
return log_oom();
return 0;
@@ -147,8 +151,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
if (feof(f))
break;
- log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
}
l = strstrip(line);
@@ -199,9 +202,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 75572b6388..ba7e3ba74a 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -19,29 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <getopt.h>
#include <net/if.h>
+#include <stdbool.h>
-#include "sd-network.h"
-#include "sd-netlink.h"
-#include "sd-hwdb.h"
#include "sd-device.h"
+#include "sd-hwdb.h"
+#include "sd-netlink.h"
+#include "sd-network.h"
-#include "strv.h"
-#include "build.h"
-#include "util.h"
-#include "pager.h"
-#include "lldp.h"
-#include "netlink-util.h"
+#include "alloc-util.h"
+#include "arphrd-list.h"
#include "device-util.h"
+#include "ether-addr-util.h"
#include "hwdb-util.h"
-#include "arphrd-list.h"
+#include "lldp.h"
#include "local-addresses.h"
+#include "locale-util.h"
+#include "locale-util.h"
+#include "netlink-util.h"
+#include "pager.h"
+#include "parse-util.h"
#include "socket-util.h"
-#include "ether-addr-util.h"
-#include "verbs.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "util.h"
+#include "verbs.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -516,7 +521,7 @@ static int link_status_one(
assert(rtnl);
assert(name);
- if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
+ if (parse_ifindex(name, &ifindex) >= 0)
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
else {
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
@@ -1063,9 +1068,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index d609daafde..889fe1e30d 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -19,8 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "networkd.h"
+#include "alloc-util.h"
#include "networkd-address-pool.h"
+#include "networkd.h"
+#include "set.h"
+#include "string-util.h"
int address_pool_new(
Manager *m,
@@ -96,9 +99,10 @@ static bool address_pool_prefix_is_taken(
HASHMAP_FOREACH(l, p->manager->links, i) {
Address *a;
+ Iterator j;
/* Don't clash with assigned addresses */
- LIST_FOREACH(addresses, a, l->addresses) {
+ SET_FOREACH(a, l->addresses, j) {
if (a->family != p->family)
continue;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index b0d296941e..8b6acf2e1d 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -21,26 +21,39 @@
#include <net/if.h>
-#include "utf8.h"
-#include "util.h"
+#include "alloc-util.h"
#include "conf-parser.h"
#include "firewall-util.h"
#include "netlink-util.h"
-
-#include "networkd.h"
#include "networkd-address.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "utf8.h"
+#include "util.h"
-static void address_init(Address *address) {
- assert(address);
+int address_new(Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
+
+ address = new0(Address, 1);
+ if (!address)
+ return -ENOMEM;
address->family = AF_UNSPEC;
address->scope = RT_SCOPE_UNIVERSE;
address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
+
+ *ret = address;
+ address = NULL;
+
+ return 0;
}
int address_new_static(Network *network, unsigned section, Address **ret) {
_cleanup_address_free_ Address *address = NULL;
+ int r;
if (section) {
address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
@@ -52,11 +65,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
}
}
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
+ r = address_new(&address);
+ if (r < 0)
+ return r;
address->network = network;
@@ -74,21 +85,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
return 0;
}
-int address_new_dynamic(Address **ret) {
- _cleanup_address_free_ Address *address = NULL;
-
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
-
- *ret = address;
- address = NULL;
-
- return 0;
-}
-
void address_free(Address *address) {
if (!address)
return;
@@ -101,10 +97,112 @@ void address_free(Address *address) {
UINT_TO_PTR(address->section));
}
+ if (address->link) {
+ set_remove(address->link->addresses, address);
+ set_remove(address->link->addresses_foreign, address);
+ }
+
free(address);
}
-int address_establish(Address *address, Link *link) {
+static void address_hash_func(const void *b, struct siphash *state) {
+ const Address *a = b;
+
+ assert(a);
+
+ siphash24_compress(&a->family, sizeof(a->family), state);
+
+ switch (a->family) {
+ case AF_INET:
+ siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
+
+ /* peer prefix */
+ if (a->prefixlen != 0) {
+ uint32_t prefix;
+
+ if (a->in_addr_peer.in.s_addr != 0)
+ prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
+ else
+ prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
+
+ siphash24_compress(&prefix, sizeof(prefix), state);
+ }
+
+ /* fallthrough */
+ case AF_INET6:
+ /* local address */
+ siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int address_compare_func(const void *c1, const void *c2) {
+ const Address *a1 = c1, *a2 = c2;
+
+ if (a1->family < a2->family)
+ return -1;
+ if (a1->family > a2->family)
+ return 1;
+
+ switch (a1->family) {
+ /* use the same notion of equality as the kernel does */
+ case AF_INET:
+ if (a1->prefixlen < a2->prefixlen)
+ return -1;
+ if (a1->prefixlen > a2->prefixlen)
+ return 1;
+
+ /* compare the peer prefixes */
+ if (a1->prefixlen != 0) {
+ /* make sure we don't try to shift by 32.
+ * See ISO/IEC 9899:TC3 § 6.5.7.3. */
+ uint32_t b1, b2;
+
+ if (a1->in_addr_peer.in.s_addr != 0)
+ b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (a2->in_addr_peer.in.s_addr != 0)
+ b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (b1 < b2)
+ return -1;
+ if (b1 > b2)
+ return 1;
+ }
+
+ /* fall-through */
+ case AF_INET6:
+ return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+static const struct hash_ops address_hash_ops = {
+ .hash = address_hash_func,
+ .compare = address_compare_func
+};
+
+bool address_equal(Address *a1, Address *a2) {
+ if (a1 == a2)
+ return true;
+
+ if (!a1 || !a2)
+ return false;
+
+ return address_compare_func(a1, a2) == 0;
+}
+
+static int address_establish(Address *address, Link *link) {
bool masq;
int r;
@@ -112,9 +210,9 @@ int address_establish(Address *address, Link *link) {
assert(link);
masq = link->network &&
- link->network->ip_masquerade &&
- address->family == AF_INET &&
- address->scope < RT_SCOPE_LINK;
+ link->network->ip_masquerade &&
+ address->family == AF_INET &&
+ address->scope < RT_SCOPE_LINK;
/* Add firewall entry if this is requested */
if (address->ip_masquerade_done != masq) {
@@ -131,11 +229,86 @@ int address_establish(Address *address, Link *link) {
return 0;
}
-int address_release(Address *address, Link *link) {
+static int address_add_internal(Link *link, Set **addresses,
+ int family,
+ const union in_addr_union *in_addr,
+ unsigned char prefixlen,
+ Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
int r;
- assert(address);
assert(link);
+ assert(addresses);
+ assert(in_addr);
+
+ r = address_new(&address);
+ if (r < 0)
+ return r;
+
+ address->family = family;
+ address->in_addr = *in_addr;
+ address->prefixlen = prefixlen;
+
+ r = set_ensure_allocated(addresses, &address_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(*addresses, address);
+ if (r < 0)
+ return r;
+
+ address->link = link;
+
+ if (ret)
+ *ret = address;
+
+ address = NULL;
+
+ return 0;
+}
+
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
+}
+
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ Address *address;
+ int r;
+
+ r = address_get(link, family, in_addr, prefixlen, &address);
+ if (r == -ENOENT) {
+ /* Address does not exist, create a new one */
+ r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
+ if (r < 0)
+ return r;
+ } else if (r == 0) {
+ /* Take over a foreign address */
+ r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->addresses, address);
+ if (r < 0)
+ return r;
+
+ set_remove(link->addresses_foreign, address);
+ } else if (r == 1) {
+ /* Already exists, do nothing */
+ ;
+ } else
+ return r;
+
+ if (ret)
+ *ret = address;
+
+ return 0;
+}
+
+static int address_release(Address *address) {
+ int r;
+
+ assert(address);
+ assert(address->link);
/* Remove masquerading firewall entry if it was added */
if (address->ip_masquerade_done) {
@@ -144,7 +317,7 @@ int address_release(Address *address, Link *link) {
r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
if (r < 0)
- log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m");
+ log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
address->ip_masquerade_done = false;
}
@@ -152,81 +325,97 @@ int address_release(Address *address, Link *link) {
return 0;
}
-int address_drop(Address *address, Link *link,
- sd_netlink_message_handler_t callback) {
- _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
- int r;
+int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
+ bool ready;
assert(address);
- assert(address->family == AF_INET || address->family == AF_INET6);
- assert(link);
- assert(link->ifindex > 0);
- assert(link->manager);
- assert(link->manager->rtnl);
+ assert(cinfo);
- address_release(address, link);
+ ready = address_is_ready(address);
- r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
- link->ifindex, address->family);
- if (r < 0)
- return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
+ address->added = true;
+ address->flags = flags;
+ address->scope = scope;
+ address->cinfo = *cinfo;
- r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
- if (r < 0)
- return log_error_errno(r, "Could not set prefixlen: %m");
+ if (address->link) {
+ link_update_operstate(address->link);
- if (address->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
- else if (address->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
- if (r < 0)
- return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
+ if (!ready && address_is_ready(address))
+ link_check_ready(address->link);
+ }
- r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
- if (r < 0)
- return log_error_errno(r, "Could not send rtnetlink message: %m");
+ return 0;
+}
- link_ref(link);
+int address_drop(Address *address) {
+ Link *link;
+ bool ready;
+
+ assert(address);
+
+ ready = address_is_ready(address);
+ link = address->link;
+
+ address_release(address);
+ address_free(address);
+
+ link_update_operstate(link);
+
+ if (link && !ready)
+ link_check_ready(link);
return 0;
}
-int address_update(Address *address, Link *link,
- sd_netlink_message_handler_t callback) {
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ Address address = {}, *existing;
+
+ assert(link);
+ assert(in_addr);
+ assert(ret);
+
+ address.family = family;
+ address.in_addr = *in_addr;
+ address.prefixlen = prefixlen;
+
+ existing = set_get(link->addresses, &address);
+ if (existing) {
+ *ret = existing;
+
+ return 1;
+ } else {
+ existing = set_get(link->addresses_foreign, &address);
+ if (!existing)
+ return -ENOENT;
+ }
+
+ *ret = existing;
+
+ return 0;
+}
+
+int address_remove(Address *address, Link *link,
+ sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
assert(address);
assert(address->family == AF_INET || address->family == AF_INET6);
+ assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
- r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
+ r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
link->ifindex, address->family);
if (r < 0)
- return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
+ return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
if (r < 0)
return log_error_errno(r, "Could not set prefixlen: %m");
- address->flags |= IFA_F_PERMANENT;
-
- r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff);
- if (r < 0)
- return log_error_errno(r, "Could not set flags: %m");
-
- if (address->flags & ~0xff && link->rtnl_extended_attrs) {
- r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
- if (r < 0)
- return log_error_errno(r, "Could not set extended flags: %m");
- }
-
- r = sd_rtnl_message_addr_set_scope(req, address->scope);
- if (r < 0)
- return log_error_errno(r, "Could not set scope: %m");
-
if (address->family == AF_INET)
r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
else if (address->family == AF_INET6)
@@ -234,22 +423,6 @@ int address_update(Address *address, Link *link,
if (r < 0)
return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
- if (address->family == AF_INET) {
- r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
- if (r < 0)
- return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
- }
-
- if (address->label) {
- r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
- if (r < 0)
- return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
- }
-
- r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
- if (r < 0)
- return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
-
r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
if (r < 0)
return log_error_errno(r, "Could not send rtnetlink message: %m");
@@ -292,7 +465,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
} else if (original->family == AF_INET6)
in_addr.in6.s6_addr[15] |= 1;
- r = address_new_dynamic(&na);
+ r = address_new(&na);
if (r < 0)
return r;
@@ -318,8 +491,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
return 0;
}
-int address_configure(Address *address, Link *link,
- sd_netlink_message_handler_t callback) {
+int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -334,8 +506,12 @@ int address_configure(Address *address, Link *link,
if (r < 0)
return r;
- r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
- link->ifindex, address->family);
+ if (update)
+ r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
+ link->ifindex, address->family);
+ else
+ r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
+ link->ifindex, address->family);
if (r < 0)
return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
@@ -392,13 +568,23 @@ int address_configure(Address *address, Link *link,
if (r < 0)
return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
- r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+ r = address_establish(address, link);
if (r < 0)
+ return r;
+
+ r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
+ if (r < 0) {
+ address_release(address);
return log_error_errno(r, "Could not send rtnetlink message: %m");
+ }
link_ref(link);
- address_establish(address, link);
+ r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+ if (r < 0) {
+ address_release(address);
+ return log_error_errno(r, "Could not add address: %m");
+ }
return 0;
}
@@ -430,15 +616,13 @@ int config_parse_broadcast(
return r;
if (n->family == AF_INET6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
return 0;
}
r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Broadcast is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@@ -487,10 +671,10 @@ int config_parse_address(const char *unit,
e = strchr(rvalue, '/');
if (e) {
unsigned i;
+
r = safe_atou(e + 1, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Prefix length is invalid, ignoring assignment: %s", e + 1);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
@@ -502,23 +686,20 @@ int config_parse_address(const char *unit,
r = in_addr_from_string_auto(address, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Address is invalid, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
return 0;
}
if (!e && f == AF_INET) {
r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
return 0;
}
}
if (n->family != AF_UNSPEC && f != n->family) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Address is incompatible, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
return 0;
}
@@ -567,9 +748,7 @@ int config_parse_label(const char *unit,
return log_oom();
if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface label is not ASCII clean or is too"
- " long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
free(label);
return 0;
}
@@ -587,49 +766,8 @@ int config_parse_label(const char *unit,
return 0;
}
-bool address_equal(Address *a1, Address *a2) {
- /* same object */
- if (a1 == a2)
- return true;
-
- /* one, but not both, is NULL */
- if (!a1 || !a2)
- return false;
-
- if (a1->family != a2->family)
- return false;
-
- switch (a1->family) {
- /* use the same notion of equality as the kernel does */
- case AF_UNSPEC:
- return true;
+bool address_is_ready(const Address *a) {
+ assert(a);
- case AF_INET:
- if (a1->prefixlen != a2->prefixlen)
- return false;
- else if (a1->prefixlen == 0)
- /* make sure we don't try to shift by 32.
- * See ISO/IEC 9899:TC3 § 6.5.7.3. */
- return true;
- else {
- uint32_t b1, b2;
-
- b1 = be32toh(a1->in_addr.in.s_addr);
- b2 = be32toh(a2->in_addr.in.s_addr);
-
- return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
- }
-
- case AF_INET6: {
- uint64_t *b1, *b2;
-
- b1 = (uint64_t*)&a1->in_addr.in6;
- b2 = (uint64_t*)&a2->in_addr.in6;
-
- return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
- }
-
- default:
- assert_not_reached("Invalid address family");
- }
+ return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 39789a2382..0b1f3b688b 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -38,6 +38,8 @@ struct Address {
Network *network;
unsigned section;
+ Link *link;
+
int family;
unsigned char prefixlen;
unsigned char scope;
@@ -50,20 +52,24 @@ struct Address {
union in_addr_union in_addr;
union in_addr_union in_addr_peer;
- bool ip_masquerade_done;
+ bool added:1;
+ bool ip_masquerade_done:1;
LIST_FIELDS(Address, addresses);
};
int address_new_static(Network *network, unsigned section, Address **ret);
-int address_new_dynamic(Address **ret);
+int address_new(Address **ret);
void address_free(Address *address);
-int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_establish(Address *address, Link *link);
-int address_release(Address *address, Link *link);
+int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
+int address_drop(Address *address);
+int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update);
+int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2);
+bool address_is_ready(const Address *a);
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
#define _cleanup_address_free_ _cleanup_(address_freep)
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 04f04df117..b58fc5808c 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -22,10 +22,11 @@
#include <netinet/ether.h>
#include <linux/if.h>
+#include "alloc-util.h"
+#include "dhcp-lease-internal.h"
#include "hostname-util.h"
-#include "networkd-link.h"
#include "network-internal.h"
-#include "dhcp-lease-internal.h"
+#include "networkd-link.h"
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
@@ -45,7 +46,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
if (!link->dhcp4_messages) {
link->dhcp4_configured = true;
- link_client_handler(link);
+ link_check_ready(link);
}
return 1;
@@ -72,11 +73,13 @@ static int link_set_dhcp_routes(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
- r = route_new_dynamic(&route_gw, RTPROT_DHCP);
+ route->protocol = RTPROT_DHCP;
+
+ r = route_new(&route_gw);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
@@ -84,11 +87,12 @@ static int link_set_dhcp_routes(Link *link) {
* route for the gw host so that we can route no matter the
* netmask or existing kernel route tables. */
route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
+ route_gw->dst.in = gateway;
route_gw->dst_prefixlen = 32;
- route_gw->prefsrc_addr.in = address;
+ route_gw->prefsrc.in = address;
route_gw->scope = RT_SCOPE_LINK;
- route_gw->metrics = link->network->dhcp_route_metric;
+ route_gw->protocol = RTPROT_DHCP;
+ route_gw->priority = link->network->dhcp_route_metric;
r = route_configure(route_gw, link, &dhcp4_route_handler);
if (r < 0)
@@ -97,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) {
link->dhcp4_messages ++;
route->family = AF_INET;
- route->in_addr.in = gateway;
- route->prefsrc_addr.in = address;
- route->metrics = link->network->dhcp_route_metric;
+ route->gw.in = gateway;
+ route->prefsrc.in = address;
+ route->priority = link->network->dhcp_route_metric;
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0) {
@@ -120,15 +124,16 @@ static int link_set_dhcp_routes(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
route->family = AF_INET;
- route->in_addr.in = static_routes[i].gw_addr;
- route->dst_addr.in = static_routes[i].dst_addr;
+ route->protocol = RTPROT_DHCP;
+ route->gw.in = static_routes[i].gw_addr;
+ route->dst.in = static_routes[i].dst_addr;
route->dst_prefixlen = static_routes[i].dst_prefixlen;
- route->metrics = link->network->dhcp_route_metric;
+ route->priority = link->network->dhcp_route_metric;
r = route_configure(route, link, &dhcp4_route_handler);
if (r < 0)
@@ -162,45 +167,45 @@ static int dhcp_lease_lost(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->in_addr.in = routes[i].gw_addr;
- route->dst_addr.in = routes[i].dst_addr;
+ route->gw.in = routes[i].gw_addr;
+ route->dst.in = routes[i].dst_addr;
route->dst_prefixlen = routes[i].dst_prefixlen;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
}
}
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r >= 0) {
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r >= 0) {
_cleanup_route_free_ Route *route_gw = NULL;
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
+ r = route_new(&route_gw);
if (r >= 0) {
route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
+ route_gw->dst.in = gateway;
route_gw->dst_prefixlen = 32;
route_gw->scope = RT_SCOPE_LINK;
- route_drop(route_gw, link,
- &link_route_drop_handler);
+ route_remove(route_gw, link,
+ &link_route_remove_handler);
}
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route);
if (r >= 0) {
route->family = AF_INET;
- route->in_addr.in = gateway;
+ route->gw.in = gateway;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
@@ -214,7 +219,7 @@ static int dhcp_lease_lost(Link *link) {
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
}
}
@@ -267,7 +272,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link_set_dhcp_routes(link);
@@ -288,7 +293,7 @@ static int dhcp4_update_address(Link *link,
prefixlen = in_addr_netmask_to_prefixlen(netmask);
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
@@ -299,9 +304,9 @@ static int dhcp4_update_address(Link *link,
addr->prefixlen = prefixlen;
addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
- /* use update rather than configure so that we will update the
- * lifetime of an existing address if it has already been configured */
- r = address_update(addr, link, &dhcp4_address_handler);
+ /* allow reusing an existing address and simply update its lifetime
+ * in case it already exists */
+ r = address_configure(addr, link, &dhcp4_address_handler, true);
if (r < 0)
return r;
@@ -528,9 +533,11 @@ int dhcp4_configure(Link *link) {
assert(link->network);
assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
- r = sd_dhcp_client_new(&link->dhcp_client);
- if (r < 0)
- return r;
+ if (!link->dhcp_client) {
+ r = sd_dhcp_client_new(&link->dhcp_client);
+ if (r < 0)
+ return r;
+ }
r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
if (r < 0)
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 13105c7865..c3332bb1ac 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -22,12 +22,11 @@
#include <netinet/ether.h>
#include <linux/if.h>
-#include "networkd-link.h"
-#include "network-internal.h"
-
-#include "sd-icmp6-nd.h"
#include "sd-dhcp6-client.h"
+#include "network-internal.h"
+#include "networkd-link.h"
+
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
@@ -53,24 +52,22 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
- log_link_error(link, "Could not set DHCPv6 address: %s",
- strerror(-r));
+ log_link_error_errno(link, r, "Could not set DHCPv6 address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
-static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
- uint8_t prefixlen, uint32_t lifetime_preferred,
- uint32_t lifetime_valid) {
+static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr,
+ uint32_t lifetime_preferred, uint32_t lifetime_valid) {
int r;
_cleanup_address_free_ Address *addr = NULL;
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
@@ -78,17 +75,17 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
addr->flags = IFA_F_NOPREFIXROUTE;
- addr->prefixlen = prefixlen;
+ addr->prefixlen = 128;
addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid;
log_link_info(link,
- "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
+ "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
+ SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
addr->prefixlen, lifetime_preferred, lifetime_valid);
- r = address_update(addr, link, dhcp6_address_handler);
+ r = address_configure(addr, link, dhcp6_address_handler, true);
if (r < 0)
log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m");
@@ -100,7 +97,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
sd_dhcp6_lease *lease;
struct in6_addr ip6_addr;
uint32_t lifetime_preferred, lifetime_valid;
- uint8_t prefixlen;
r = sd_dhcp6_client_get_lease(client, &lease);
if (r < 0)
@@ -112,19 +108,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
&lifetime_preferred,
&lifetime_valid) >= 0) {
- r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
- &ip6_addr, &prefixlen);
- if (r < 0 && r != -EADDRNOTAVAIL) {
- log_link_warning(link, "Could not get prefix information: %s",
- strerror(-r));
- return r;
- }
-
- if (r == -EADDRNOTAVAIL)
- prefixlen = 128;
-
- r = dhcp6_address_update(link, &ip6_addr, prefixlen,
- lifetime_preferred, lifetime_valid);
+ r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
if (r < 0)
return r;
}
@@ -172,50 +156,39 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
default:
if (event < 0)
- log_link_warning(link, "DHCPv6 error: %s",
- strerror(-event));
+ log_link_warning_errno(link, event, "DHCPv6 error: %m");
else
- log_link_warning(link, "DHCPv6 unknown event: %d",
- event);
+ log_link_warning(link, "DHCPv6 unknown event: %d", event);
return;
}
- link_client_handler(link);
+ link_check_ready(link);
}
-static int dhcp6_configure(Link *link, int event) {
- int r;
- bool information_request;
+int dhcp6_configure(Link *link, bool inf_req) {
+ int r, information_request;
assert_return(link, -EINVAL);
- assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);
link->dhcp6_configured = false;
if (link->dhcp6_client) {
- r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
- &information_request);
+ 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: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
goto error;
}
- if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
+ if (information_request && !inf_req) {
r = sd_dhcp6_client_stop(link->dhcp6_client);
if (r < 0) {
- log_link_warning(link, "Could not stop DHCPv6 while setting Managed mode %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
goto error;
}
- r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
- false);
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false);
if (r < 0) {
- log_link_warning(link, "Could not unset DHCPv6 Information request: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
goto error;
}
@@ -223,8 +196,7 @@ static int dhcp6_configure(Link *link, int event) {
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0 && r != -EALREADY) {
- log_link_warning(link, "Could not restart DHCPv6: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
goto error;
}
@@ -257,9 +229,8 @@ static int dhcp6_configure(Link *link, int event) {
if (r < 0)
goto error;
- if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
- r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
- true);
+ if (inf_req) {
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client, true);
if (r < 0)
goto error;
}
@@ -274,109 +245,3 @@ static int dhcp6_configure(Link *link, int event) {
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
-
-static int dhcp6_prefix_expired(Link *link) {
- int r;
- sd_dhcp6_lease *lease;
- struct in6_addr *expired_prefix, ip6_addr;
- uint8_t expired_prefixlen;
- uint32_t lifetime_preferred, lifetime_valid;
-
- r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
- &expired_prefix, &expired_prefixlen);
- if (r < 0)
- return r;
-
- r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
- if (r < 0)
- return r;
-
- log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired",
- SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix),
- expired_prefixlen);
-
- sd_dhcp6_lease_reset_address_iter(lease);
-
- while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
- &lifetime_preferred,
- &lifetime_valid) >= 0) {
-
- r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
- &ip6_addr);
- if (r < 0)
- continue;
-
- log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128);
-
- dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
- }
-
- return 0;
-}
-
-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 SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
- return;
-
- case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
- case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
- case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
- dhcp6_configure(link, event);
-
- break;
-
- case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
- if (!link->rtnl_extended_attrs)
- dhcp6_prefix_expired(link);
-
- break;
-
- default:
- if (event < 0)
- log_link_warning(link, "ICMPv6 error: %s",
- strerror(-event));
- else
- log_link_warning(link, "ICMPv6 unknown event: %d",
- event);
-
- break;
- }
-
-}
-
-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-fdb.c b/src/network/networkd-fdb.c
index 22efadb843..c9222b8cb8 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -22,12 +22,12 @@
#include <net/if.h>
#include <net/ethernet.h>
+#include "alloc-util.h"
#include "conf-parser.h"
-#include "util.h"
#include "netlink-util.h"
-
-#include "networkd.h"
#include "networkd-fdb.h"
+#include "networkd.h"
+#include "util.h"
/* create a new FDB entry or get an existing one. */
int fdb_entry_new_static(Network *const network,
@@ -197,7 +197,7 @@ int config_parse_fdb_hwaddr(
&fdb_entry->mac_addr->ether_addr_octet[5]);
if (ETHER_ADDR_LEN != r) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index af3e3884e6..ed0d861e7a 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -42,9 +42,9 @@ static int ipv4ll_address_lost(Link *link) {
log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r < 0) {
- log_link_error(link, "Could not allocate address: %s", strerror(-r));
+ log_link_error_errno(link, r, "Could not allocate address: %m");
return r;
}
@@ -53,22 +53,21 @@ static int ipv4ll_address_lost(Link *link) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route);
if (r < 0) {
- log_link_error(link, "Could not allocate route: %s",
- strerror(-r));
+ log_link_error_errno(link, r, "Could not allocate route: %m");
return r;
}
route->family = AF_INET;
route->scope = RT_SCOPE_LINK;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
- route_drop(route, link, &link_route_drop_handler);
+ route_remove(route, link, &link_route_remove_handler);
- link_client_handler(link);
+ link_check_ready(link);
return 0;
}
@@ -82,14 +81,14 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error(link, "could not set ipv4ll route: %s", strerror(-r));
+ log_link_error_errno(link, r, "could not set ipv4ll route: %m");
link_enter_failed(link);
}
link->ipv4ll_route = true;
if (link->ipv4ll_address == true)
- link_client_handler(link);
+ link_check_ready(link);
return 1;
}
@@ -103,15 +102,15 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error(link, "could not set ipv4ll address: %s", strerror(-r));
+ log_link_error_errno(link, r, "could not set ipv4ll address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link->ipv4ll_address = true;
if (link->ipv4ll_route == true)
- link_client_handler(link);
+ link_check_ready(link);
return 1;
}
@@ -134,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
ADDRESS_FMT_VAL(address));
- r = address_new_dynamic(&ll_addr);
+ r = address_new(&ll_addr);
if (r < 0)
return r;
@@ -144,19 +143,20 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
ll_addr->scope = RT_SCOPE_LINK;
- r = address_configure(ll_addr, link, ipv4ll_address_handler);
+ r = address_configure(ll_addr, link, ipv4ll_address_handler, false);
if (r < 0)
return r;
link->ipv4ll_address = false;
- r = route_new_dynamic(&route, RTPROT_STATIC);
+ r = route_new(&route);
if (r < 0)
return r;
route->family = AF_INET;
route->scope = RT_SCOPE_LINK;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->protocol = RTPROT_STATIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
r = route_configure(route, link, ipv4ll_route_handler);
if (r < 0)
@@ -208,9 +208,11 @@ int ipv4ll_configure(Link *link) {
assert(link->network);
assert(link->network->link_local & ADDRESS_FAMILY_IPV4);
- r = sd_ipv4ll_new(&link->ipv4ll);
- if (r < 0)
- return r;
+ if (!link->ipv4ll) {
+ r = sd_ipv4ll_new(&link->ipv4ll);
+ if (r < 0)
+ return r;
+ }
if (link->udev_device) {
r = net_get_unique_predictable_data(link->udev_device, seed);
diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c
index 1a1524dfb4..11b35d6cf8 100644
--- a/src/network/networkd-link-bus.c
+++ b/src/network/networkd-link-bus.c
@@ -22,8 +22,10 @@
#include "bus-util.h"
#include "strv.h"
-#include "networkd.h"
+#include "alloc-util.h"
#include "networkd-link.h"
+#include "networkd.h"
+#include "parse-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
@@ -101,7 +103,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
if (r < 0)
return 0;
- r = safe_atoi(identifier, &ifindex);
+ r = parse_ifindex(identifier, &ifindex);
if (r < 0)
return 0;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 5dd14b1104..46979ffa12 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -23,18 +23,23 @@
#include <linux/if.h>
#include <unistd.h>
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "socket-util.h"
+#include "alloc-util.h"
#include "bus-util.h"
-#include "udev-util.h"
-#include "netlink-util.h"
#include "dhcp-lease-internal.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "netlink-util.h"
#include "network-internal.h"
-
#include "networkd-link.h"
#include "networkd-netdev.h"
+#include "set.h"
+#include "socket-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "udev-util.h"
+#include "util.h"
+#include "virt.h"
bool link_dhcp6_enabled(Link *link) {
if (link->flags & IFF_LOOPBACK)
@@ -129,6 +134,57 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
return link->network->ipv6_privacy_extensions;
}
+void link_update_operstate(Link *link) {
+ LinkOperationalState operstate;
+ assert(link);
+
+ if (link->kernel_operstate == IF_OPER_DORMANT)
+ operstate = LINK_OPERSTATE_DORMANT;
+ else if (link_has_carrier(link)) {
+ Address *address;
+ uint8_t scope = RT_SCOPE_NOWHERE;
+ Iterator i;
+
+ /* if we have carrier, check what addresses we have */
+ SET_FOREACH(address, link->addresses, i) {
+ if (!address_is_ready(address))
+ continue;
+
+ if (address->scope < scope)
+ scope = address->scope;
+ }
+
+ /* for operstate we also take foreign addresses into account */
+ SET_FOREACH(address, link->addresses_foreign, i) {
+ if (!address_is_ready(address))
+ continue;
+
+ if (address->scope < scope)
+ scope = address->scope;
+ }
+
+ if (scope < RT_SCOPE_SITE)
+ /* universally accessible addresses found */
+ operstate = LINK_OPERSTATE_ROUTABLE;
+ else if (scope < RT_SCOPE_HOST)
+ /* only link or site local addresses found */
+ operstate = LINK_OPERSTATE_DEGRADED;
+ else
+ /* no useful addresses found */
+ operstate = LINK_OPERSTATE_CARRIER;
+ } else if (link->flags & IFF_UP)
+ operstate = LINK_OPERSTATE_NO_CARRIER;
+ else
+ operstate = LINK_OPERSTATE_OFF;
+
+ if (link->operstate != operstate) {
+ link->operstate = operstate;
+ link_send_changed(link, "OperationalState", NULL);
+ link_dirty(link);
+ manager_dirty(link->manager);
+ }
+}
+
#define FLAG_STRING(string, flag, old, new) \
(((old ^ new) & flag) \
? ((old & flag) ? (" -" string) : (" +" string)) \
@@ -201,7 +257,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
link->flags = flags;
link->kernel_operstate = operstate;
- link_save(link);
+ link_update_operstate(link);
return 0;
}
@@ -291,10 +347,15 @@ static void link_free(Link *link) {
if (!link)
return;
- while ((address = link->addresses)) {
- LIST_REMOVE(addresses, link->addresses, address);
- address_free(address);
- }
+ while (!set_isempty(link->addresses))
+ address_free(set_first(link->addresses));
+
+ while (!set_isempty(link->addresses_foreign))
+ address_free(set_first(link->addresses_foreign));
+
+ link->addresses = set_free(link->addresses);
+
+ link->addresses_foreign = set_free(link->addresses_foreign);
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
@@ -313,13 +374,14 @@ static void link_free(Link *link) {
sd_ipv4ll_unref(link->ipv4ll);
sd_dhcp6_client_unref(link->dhcp6_client);
- sd_icmp6_nd_unref(link->icmp6_router_discovery);
+ sd_ndisc_unref(link->ndisc_router_discovery);
if (link->manager)
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
free(link->ifname);
+ (void)unlink(link->state_file);
free(link->state_file);
udev_device_unref(link->udev_device);
@@ -336,15 +398,28 @@ static void link_free(Link *link) {
}
Link *link_unref(Link *link) {
- if (link && (-- link->n_ref <= 0))
- link_free(link);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref --;
+
+ if (link->n_ref > 0)
+ return NULL;
+
+ link_free(link);
return NULL;
}
Link *link_ref(Link *link) {
- if (link)
- assert_se(++ link->n_ref >= 2);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref ++;
return link;
}
@@ -385,7 +460,7 @@ static void link_enter_unmanaged(Link *link) {
link_set_state(link, LINK_STATE_UNMANAGED);
- link_save(link);
+ link_dirty(link);
}
static int link_stop_clients(Link *link) {
@@ -410,16 +485,16 @@ static int link_stop_clients(Link *link) {
r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
}
- if(link->icmp6_router_discovery) {
+ if(link->ndisc_router_discovery) {
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
}
- k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
+ k = sd_ndisc_stop(link->ndisc_router_discovery);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m");
+ r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
}
if (link->lldp) {
@@ -443,7 +518,7 @@ void link_enter_failed(Link *link) {
link_stop_clients(link);
- link_save(link);
+ link_dirty(link);
}
static Address* link_find_dhcp_server_address(Link *link) {
@@ -484,14 +559,19 @@ static int link_enter_configured(Link *link) {
link_set_state(link, LINK_STATE_CONFIGURED);
- link_save(link);
+ link_dirty(link);
return 0;
}
-void link_client_handler(Link *link) {
+void link_check_ready(Link *link) {
+ Address *a;
+ Iterator i;
+
assert(link);
- assert(link->network);
+
+ if (!link->network)
+ return;
if (!link->static_configured)
return;
@@ -501,12 +581,18 @@ void link_client_handler(Link *link) {
!link->ipv4ll_route)
return;
- if (link_dhcp4_enabled(link) && !link->dhcp4_configured)
- return;
-
- if (link_dhcp6_enabled(link) && !link->dhcp6_configured)
+ if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured) ||
+ (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+ !link->dhcp6_configured) ||
+ (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured && !link->dhcp6_configured))
return;
+ SET_FOREACH(a, link->addresses, i)
+ if (!address_is_ready(a))
+ return;
+
if (link->state != LINK_STATE_CONFIGURED)
link_enter_configured(link);
@@ -529,12 +615,12 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set route: %m");
if (link->link_messages == 0) {
log_link_debug(link, "Routes set");
link->static_configured = true;
- link_client_handler(link);
+ link_check_ready(link);
}
return 1;
@@ -563,14 +649,14 @@ static int link_enter_set_routes(Link *link) {
if (link->link_messages == 0) {
link->static_configured = true;
- link_client_handler(link);
+ link_check_ready(link);
} else
log_link_debug(link, "Setting routes");
return 0;
}
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -583,7 +669,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
- log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop route: %m");
return 1;
}
@@ -607,9 +693,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "could not set address: %m");
else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
if (link->link_messages == 0) {
log_link_debug(link, "Addresses set");
@@ -720,7 +806,7 @@ static int link_enter_set_addresses(Link *link) {
link_set_state(link, LINK_STATE_SETTING_ADDRESSES);
LIST_FOREACH(addresses, ad, link->network->static_addresses) {
- r = address_configure(ad, link, &address_handler);
+ r = address_configure(ad, link, &address_handler, false);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set addresses: %m");
link_enter_failed(link);
@@ -852,7 +938,7 @@ static int link_enter_set_addresses(Link *link) {
return 0;
}
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -865,7 +951,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop address: %m");
return 1;
}
@@ -1017,7 +1103,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set MTU: %m");
return 1;
}
@@ -1156,13 +1242,13 @@ static int link_acquire_conf(Link *link) {
}
if (link_dhcp6_enabled(link)) {
- assert(link->icmp6_router_discovery);
+ assert(link->ndisc_router_discovery);
log_link_debug(link, "Discovering IPv6 routers");
- r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
+ r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery);
if (r < 0)
- return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m");
+ return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m");
}
if (link_lldp_enabled(link)) {
@@ -1205,7 +1291,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
if (r < 0)
/* we warn but don't fail the link, as it may be
brought up later */
- log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring up interface: %m");
return 1;
}
@@ -1292,7 +1378,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring down interface: %m");
return 1;
}
@@ -1430,14 +1516,14 @@ static int link_new_bound_by_list(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
if (r < 0)
return r;
- link_save(carrier);
+ link_dirty(carrier);
}
return 0;
@@ -1472,14 +1558,14 @@ static int link_new_bound_to_list(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
HASHMAP_FOREACH (carrier, link->bound_to_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_by_links);
if (r < 0)
return r;
- link_save(carrier);
+ link_dirty(carrier);
}
return 0;
@@ -1515,7 +1601,7 @@ static void link_free_bound_to_list(Link *link) {
hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex));
if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex)))
- link_save(bound_to);
+ link_dirty(bound_to);
}
return;
@@ -1529,7 +1615,7 @@ static void link_free_bound_by_list(Link *link) {
hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex));
if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) {
- link_save(bound_by);
+ link_dirty(bound_by);
link_handle_bound_to_list(bound_by);
}
}
@@ -1553,7 +1639,7 @@ static void link_free_carrier_maps(Link *link) {
}
if (list_updated)
- link_save(link);
+ link_dirty(link);
return;
}
@@ -1568,6 +1654,7 @@ void link_drop(Link *link) {
log_link_debug(link, "Link removed");
+ (void)unlink(link->state_file);
link_unref(link);
return;
@@ -1614,7 +1701,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
+ log_link_error_errno(link, r, "Could not join netdev: %m");
link_enter_failed(link);
return 1;
} else
@@ -1637,7 +1724,7 @@ static int link_enter_join_netdev(Link *link) {
link_set_state(link, LINK_STATE_ENSLAVING);
- link_save(link);
+ link_dirty(link);
if (!link->network->bridge &&
!link->network->bond &&
@@ -1810,16 +1897,16 @@ static int link_set_ipv6_accept_ra(Link *link) {
* disabled if local forwarding is enabled).
* If set, ignore or enforce RA independent of local forwarding state.
*/
- if (link->network->ipv6_accept_ra < 0) {
+ if (link->network->ipv6_accept_ra < 0)
/* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
v = "1";
- } else if (link->network->ipv6_accept_ra > 0) {
+ else if (link->network->ipv6_accept_ra > 0)
/* "2" means accept RA even if ip_forward is enabled */
v = "2";
- } else {
+ else
/* "0" means ignore RA */
v = "0";
- }
+
p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
r = write_string_file(p, v, 0);
@@ -1834,6 +1921,37 @@ static int link_set_ipv6_accept_ra(Link *link) {
return 0;
}
+static int link_set_ipv6_dad_transmits(Link *link) {
+ char buf[DECIMAL_STR_MAX(unsigned) + 1];
+ const char *p = NULL;
+ int r;
+
+ /* Make this a NOP if IPv6 is not available */
+ if (!socket_ipv6_is_supported())
+ return 0;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ if (link->network->ipv6_dad_transmits < 0)
+ return 0;
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
+
+ xsprintf(buf, "%u", link->network->ipv6_dad_transmits);
+
+ r = write_string_file(p, buf, 0);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, buf) > 0)
+ return 0;
+
+ log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
+ }
+
+ return 0;
+}
+
static int link_configure(Link *link) {
int r;
@@ -1861,6 +1979,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_ipv6_dad_transmits(link);
+ if (r < 0)
+ return r;
+
if (link_ipv4ll_enabled(link)) {
r = ipv4ll_configure(link);
if (r < 0)
@@ -1884,7 +2006,7 @@ static int link_configure(Link *link) {
}
if (link_dhcp6_enabled(link)) {
- r = icmp6_configure(link);
+ r = ndisc_configure(link);
if (r < 0)
return r;
}
@@ -1936,28 +2058,30 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
if (r < 0)
return r;
- r = network_get(link->manager, link->udev_device, link->ifname,
- &link->mac, &network);
- if (r == -ENOENT) {
- link_enter_unmanaged(link);
- return 1;
- } else if (r < 0)
- return r;
+ if (!link->network) {
+ r = network_get(link->manager, link->udev_device, link->ifname,
+ &link->mac, &network);
+ if (r == -ENOENT) {
+ link_enter_unmanaged(link);
+ return 1;
+ } else if (r < 0)
+ return r;
- if (link->flags & IFF_LOOPBACK) {
- if (network->link_local != ADDRESS_FAMILY_NO)
- log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
+ if (link->flags & IFF_LOOPBACK) {
+ if (network->link_local != ADDRESS_FAMILY_NO)
+ log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
- if (network->dhcp != ADDRESS_FAMILY_NO)
- log_link_debug(link, "Ignoring DHCP clients for loopback link");
+ if (network->dhcp != ADDRESS_FAMILY_NO)
+ log_link_debug(link, "Ignoring DHCP clients for loopback link");
- if (network->dhcp_server)
- log_link_debug(link, "Ignoring DHCP server for loopback link");
- }
+ if (network->dhcp_server)
+ log_link_debug(link, "Ignoring DHCP server for loopback link");
+ }
- r = network_apply(link->manager, network, link);
- if (r < 0)
- return r;
+ r = network_apply(link->manager, network, link);
+ if (r < 0)
+ return r;
+ }
r = link_new_bound_to_list(link);
if (r < 0)
@@ -2009,177 +2133,191 @@ int link_initialized(Link *link, struct udev_device *device) {
return 0;
}
-static Address* link_get_equal_address(Link *link, Address *needle) {
- Address *i;
+static int link_load(Link *link) {
+ _cleanup_free_ char *network_file = NULL,
+ *addresses = NULL,
+ *routes = NULL,
+ *dhcp4_address = NULL,
+ *ipv4ll_address = NULL;
+ union in_addr_union address;
+ union in_addr_union route_dst;
+ const char *p;
+ int r;
assert(link);
- assert(needle);
- LIST_FOREACH(addresses, i, link->addresses)
- if (address_equal(i, needle))
- return i;
-
- return NULL;
-}
-
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
- Manager *m = userdata;
- Link *link = NULL;
- uint16_t type;
- _cleanup_address_free_ Address *address = NULL;
- unsigned char flags;
- Address *existing;
- char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL;
- int r, ifindex;
+ r = parse_env_file(link->state_file, NEWLINE,
+ "NETWORK_FILE", &network_file,
+ "ADDRESSES", &addresses,
+ "ROUTES", &routes,
+ "DHCP4_ADDRESS", &dhcp4_address,
+ "IPV4LL_ADDRESS", &ipv4ll_address,
+ NULL);
+ if (r < 0 && r != -ENOENT)
+ return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file);
+
+ if (network_file) {
+ Network *network;
+ char *suffix;
+
+ /* drop suffix */
+ suffix = strrchr(network_file, '.');
+ if (!suffix) {
+ log_link_debug(link, "Failed to get network name from %s", network_file);
+ goto network_file_fail;
+ }
+ *suffix = '\0';
- assert(rtnl);
- assert(message);
- assert(m);
+ r = network_get_by_name(link->manager, basename(network_file), &network);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file));
+ goto network_file_fail;
+ }
- if (sd_netlink_message_is_error(message)) {
- r = sd_netlink_message_get_errno(message);
+ r = network_apply(link->manager, network, link);
if (r < 0)
- log_warning_errno(r, "rtnl: failed to receive address: %m");
-
- return 0;
+ return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file));
}
- r = sd_netlink_message_get_type(message, &type);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get message type: %m");
- return 0;
- } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
- log_warning("rtnl: received unexpected message type when processing address");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
- return 0;
- } else if (ifindex <= 0) {
- log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
- return 0;
- } else {
- r = link_get(m, ifindex, &link);
- if (r < 0 || !link) {
- /* when enumerating we might be out of sync, but we will
- * get the address again, so just ignore it */
- if (!m->enumerating)
- log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
- return 0;
- }
- }
+network_file_fail:
- r = address_new_dynamic(&address);
- if (r < 0)
- return r;
+ if (addresses) {
+ p = addresses;
- r = sd_rtnl_message_addr_get_family(message, &address->family);
- if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
- log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
- return 0;
- }
+ for (;;) {
+ _cleanup_free_ char *address_str = NULL;
+ char *prefixlen_str;
+ int family;
+ unsigned char prefixlen;
- r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
- return 0;
- }
+ r = extract_first_word(&p, &address_str, NULL, 0);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to extract next address string: %m");
+ continue;
+ } if (r == 0)
+ break;
- r = sd_rtnl_message_addr_get_scope(message, &address->scope);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
- return 0;
- }
+ prefixlen_str = strchr(address_str, '/');
+ if (!prefixlen_str) {
+ log_link_debug(link, "Failed to parse address and prefix length %s", address_str);
+ continue;
+ }
- r = sd_rtnl_message_addr_get_flags(message, &flags);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
- return 0;
- }
- address->flags = flags;
+ *prefixlen_str ++ = '\0';
- switch (address->family) {
- case AF_INET:
- r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
- }
+ r = sscanf(prefixlen_str, "%hhu", &prefixlen);
+ if (r != 1) {
+ log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str);
+ continue;
+ }
- break;
+ r = in_addr_from_string_auto(address_str, &family, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str);
+ continue;
+ }
- case AF_INET6:
- r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
+ r = address_add(link, family, &address, prefixlen, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to add address: %m");
}
-
- break;
-
- default:
- assert_not_reached("invalid address family");
}
- if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
- log_link_warning(link, "Could not print address");
- return 0;
- }
+ if (routes) {
+ for (;;) {
+ Route *route;
+ _cleanup_free_ char *route_str = NULL;
+ _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+ usec_t lifetime;
+ char *prefixlen_str;
+ int family;
+ unsigned char prefixlen, tos, table;
+ uint32_t priority;
- r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
- if (r >= 0) {
- if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = "ever";
- else
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
- }
+ r = extract_first_word(&p, &route_str, NULL, 0);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to extract next route string: %m");
+ continue;
+ } if (r == 0)
+ break;
- existing = link_get_equal_address(link, address);
+ prefixlen_str = strchr(route_str, '/');
+ if (!prefixlen_str) {
+ log_link_debug(link, "Failed to parse route %s", route_str);
+ continue;
+ }
- switch (type) {
- case RTM_NEWADDR:
- if (existing) {
- log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+ *prefixlen_str ++ = '\0';
+ r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
+ if (r != 5) {
+ log_link_debug(link,
+ "Failed to parse destination prefix length, tos, priority, table or expiration %s",
+ prefixlen_str);
+ continue;
+ }
- existing->scope = address->scope;
- existing->flags = address->flags;
- existing->cinfo = address->cinfo;
+ r = in_addr_from_string_auto(route_str, &family, &route_dst);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
+ continue;
+ }
- } else {
- log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+ r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to add route: %m");
- LIST_PREPEND(addresses, link->addresses, address);
- address_establish(address, link);
+ if (lifetime != USEC_INFINITY) {
+ r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime,
+ 0, route_expire_handler, route);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not arm route expiration handler: %m");
+ }
- address = NULL;
+ route->lifetime = lifetime;
+ sd_event_source_unref(route->expire);
+ route->expire = expire;
+ expire = NULL;
+ }
+ }
- link_save(link);
+ if (dhcp4_address) {
+ r = in_addr_from_string(AF_INET, dhcp4_address, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address);
+ goto dhcp4_address_fail;
}
- break;
+ r = sd_dhcp_client_new(&link->dhcp_client);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m");
+
+ r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address);
+ }
- case RTM_DELADDR:
+dhcp4_address_fail:
- if (existing) {
- log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
- address_release(existing, link);
- LIST_REMOVE(addresses, link->addresses, existing);
- address_free(existing);
- } else
- log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
+ if (ipv4ll_address) {
+ r = in_addr_from_string(AF_INET, ipv4ll_address, &address);
+ if (r < 0) {
+ log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address);
+ goto ipv4ll_address_fail;
+ }
- break;
- default:
- assert_not_reached("Received invalid RTNL message type");
+ r = sd_ipv4ll_new(&link->ipv4ll);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m");
+
+ r = sd_ipv4ll_set_address(link->ipv4ll, &address.in);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address);
}
- return 1;
+ipv4ll_address_fail:
+
+ return 0;
}
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
@@ -2201,12 +2339,18 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
log_link_debug(link, "Link %d added", link->ifindex);
+ r = link_load(link);
+ if (r < 0)
+ return r;
+
if (detect_container() <= 0) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
device = udev_device_new_from_device_id(m->udev, ifindex_str);
- if (!device)
- return log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ if (!device) {
+ r = log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ goto failed;
+ }
if (udev_device_get_is_initialized(device) <= 0) {
/* not yet ready */
@@ -2216,17 +2360,20 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
r = link_initialized(link, device);
if (r < 0)
- return r;
+ goto failed;
} else {
/* we are calling a callback directly, so must take a ref */
link_ref(link);
r = link_initialized_and_synced(m->rtnl, NULL, link);
if (r < 0)
- return r;
+ goto failed;
}
return 0;
+failed:
+ link_enter_failed(link);
+ return r;
}
static int link_carrier_gained(Link *link) {
@@ -2414,49 +2561,13 @@ int link_update(Link *link, sd_netlink_message *m) {
return 0;
}
-static void link_update_operstate(Link *link) {
- LinkOperationalState operstate;
- assert(link);
-
- if (link->kernel_operstate == IF_OPER_DORMANT)
- operstate = LINK_OPERSTATE_DORMANT;
- else if (link_has_carrier(link)) {
- Address *address;
- uint8_t scope = RT_SCOPE_NOWHERE;
-
- /* if we have carrier, check what addresses we have */
- LIST_FOREACH(addresses, address, link->addresses) {
- if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
- continue;
-
- if (address->scope < scope)
- scope = address->scope;
- }
-
- if (scope < RT_SCOPE_SITE)
- /* universally accessible addresses found */
- operstate = LINK_OPERSTATE_ROUTABLE;
- else if (scope < RT_SCOPE_HOST)
- /* only link or site local addresses found */
- operstate = LINK_OPERSTATE_DEGRADED;
- else
- /* no useful addresses found */
- operstate = LINK_OPERSTATE_CARRIER;
- } else if (link->flags & IFF_UP)
- operstate = LINK_OPERSTATE_NO_CARRIER;
- else
- operstate = LINK_OPERSTATE_OFF;
-
- if (link->operstate != operstate) {
- link->operstate = operstate;
- link_send_changed(link, "OperationalState", NULL);
- }
-}
-
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *admin_state, *oper_state;
+ Address *a;
+ Route *route;
+ Iterator i;
int r;
assert(link);
@@ -2464,12 +2575,6 @@ int link_save(Link *link) {
assert(link->lease_file);
assert(link->manager);
- link_update_operstate(link);
-
- r = manager_save(link->manager);
- if (r < 0)
- return r;
-
if (link->state == LINK_STATE_LINGER) {
unlink(link->state_file);
return 0;
@@ -2537,13 +2642,12 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
serialize_in6_addrs(f, in6_addrs, r);
- space = true;
}
}
- fputs("\n", f);
+ fputc('\n', f);
- fprintf(f, "NTP=");
+ fputs("NTP=", f);
space = false;
STRV_FOREACH(address, link->network->ntp) {
if (space)
@@ -2590,9 +2694,9 @@ int link_save(Link *link) {
}
}
- fputs("\n", f);
+ fputc('\n', f);
- fprintf(f, "DOMAINS=");
+ fputs("DOMAINS=", f);
space = false;
STRV_FOREACH(domain, link->network->domains) {
if (space)
@@ -2628,18 +2732,48 @@ int link_save(Link *link) {
}
}
- fputs("\n", f);
+ fputc('\n', f);
fprintf(f, "WILDCARD_DOMAIN=%s\n",
yes_no(link->network->wildcard_domain));
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->network->llmnr));
+
+ fputs("ADDRESSES=", f);
+ space = false;
+ SET_FOREACH(a, link->addresses, i) {
+ _cleanup_free_ char *address_str = NULL;
+
+ r = in_addr_to_string(a->family, &a->in_addr, &address_str);
+ if (r < 0)
+ goto fail;
+
+ fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen);
+ space = true;
+ }
+
+ fputc('\n', f);
+
+ fputs("ROUTES=", f);
+ space = false;
+ SET_FOREACH(route, link->routes, i) {
+ _cleanup_free_ char *route_str = NULL;
+
+ r = in_addr_to_string(route->family, &route->dst, &route_str);
+ if (r < 0)
+ goto fail;
+
+ fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str,
+ route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
+ space = true;
+ }
+
+ fputc('\n', f);
}
if (!hashmap_isempty(link->bound_to_links)) {
Link *carrier;
- Iterator i;
bool space = false;
fputs("CARRIER_BOUND_TO=", f);
@@ -2650,12 +2784,11 @@ int link_save(Link *link) {
space = true;
}
- fputs("\n", f);
+ fputc('\n', f);
}
if (!hashmap_isempty(link->bound_by_links)) {
Link *carrier;
- Iterator i;
bool space = false;
fputs("CARRIER_BOUND_BY=", f);
@@ -2666,19 +2799,25 @@ int link_save(Link *link) {
space = true;
}
- fputs("\n", f);
+ fputc('\n', f);
}
if (link->dhcp_lease) {
+ struct in_addr address;
const char *tz = NULL;
+ assert(link->network);
+
r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
if (r >= 0)
fprintf(f, "TIMEZONE=%s\n", tz);
- }
- if (link->dhcp_lease) {
- assert(link->network);
+ r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
+ if (r >= 0) {
+ fputs("DHCP4_ADDRESS=", f);
+ serialize_in_addrs(f, &address, 1);
+ fputc('\n', f);
+ }
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
@@ -2690,6 +2829,17 @@ int link_save(Link *link) {
} else
unlink(link->lease_file);
+ if (link->ipv4ll) {
+ struct in_addr address;
+
+ r = sd_ipv4ll_get_address(link->ipv4ll, &address);
+ if (r >= 0) {
+ fputs("IPV4LL_ADDRESS=", f);
+ serialize_in_addrs(f, &address, 1);
+ fputc('\n', f);
+ }
+ }
+
if (link->lldp) {
assert(link->network);
@@ -2722,6 +2872,34 @@ fail:
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file);
}
+/* The serialized state in /run is no longer up-to-date. */
+void link_dirty(Link *link) {
+ int r;
+
+ assert(link);
+
+ r = set_ensure_allocated(&link->manager->dirty_links, NULL);
+ if (r < 0)
+ /* allocation errors are ignored */
+ return;
+
+ r = set_put(link->manager->dirty_links, link);
+ if (r < 0)
+ /* allocation errors are ignored */
+ return;
+
+ link_ref(link);
+}
+
+/* The serialized state in /run is up-to-date */
+void link_clean(Link *link) {
+ assert(link);
+ assert(link->manager);
+
+ set_remove(link->manager->dirty_links, link);
+ link_unref(link);
+}
+
static const char* const link_state_table[_LINK_STATE_MAX] = {
[LINK_STATE_PENDING] = "pending",
[LINK_STATE_ENSLAVING] = "configuring",
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 7b219c6854..a22041870e 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -25,10 +25,10 @@
#include "sd-dhcp-client.h"
#include "sd-dhcp-server.h"
-#include "sd-ipv4ll.h"
-#include "sd-icmp6-nd.h"
#include "sd-dhcp6-client.h"
+#include "sd-ipv4ll.h"
#include "sd-lldp.h"
+#include "sd-ndisc.h"
typedef struct Link Link;
@@ -83,7 +83,10 @@ struct Link {
unsigned link_messages;
unsigned enslaving;
- LIST_HEAD(Address, addresses);
+ Set *addresses;
+ Set *addresses_foreign;
+ Set *routes;
+ Set *routes_foreign;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
@@ -103,7 +106,7 @@ struct Link {
sd_dhcp_server *dhcp_server;
- sd_icmp6_nd *icmp6_router_discovery;
+ sd_ndisc *ndisc_router_discovery;
sd_dhcp6_client *dhcp6_client;
bool rtnl_extended_attrs;
@@ -120,17 +123,19 @@ int link_get(Manager *m, int ifindex, Link **ret);
int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
void link_drop(Link *link);
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
void link_enter_failed(Link *link);
int link_initialized(Link *link, struct udev_device *device);
-void link_client_handler(Link *link);
+void link_check_ready(Link *link);
+void link_update_operstate(Link *link);
int link_update(Link *link, sd_netlink_message *message);
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata);
+void link_dirty(Link *link);
+void link_clean(Link *link);
int link_save(Link *link);
int link_carrier_reset(Link *link);
@@ -142,7 +147,8 @@ int link_set_timezone(Link *link, const char *timezone);
int ipv4ll_configure(Link *link);
int dhcp4_configure(Link *link);
-int icmp6_configure(Link *link);
+int dhcp6_configure(Link *link, bool information_request);
+int ndisc_configure(Link *link);
bool link_lldp_enabled(Link *link);
bool link_ipv4ll_enabled(Link *link);
diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c
index b281f4fdb6..dafaf2daea 100644
--- a/src/network/networkd-manager-bus.c
+++ b/src/network/networkd-manager-bus.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-util.h"
-
#include "networkd.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index b4259cafef..a5701001c1 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -22,21 +22,23 @@
#include <sys/socket.h>
#include <linux/if.h>
-#include "sd-netlink.h"
#include "sd-daemon.h"
+#include "sd-netlink.h"
-#include "conf-parser.h"
-#include "path-util.h"
-#include "libudev-private.h"
-#include "udev-util.h"
-#include "netlink-util.h"
+#include "alloc-util.h"
#include "bus-util.h"
+#include "conf-parser.h"
#include "def.h"
-#include "virt.h"
-#include "set.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "libudev-private.h"
#include "local-addresses.h"
-
+#include "netlink-util.h"
#include "networkd.h"
+#include "path-util.h"
+#include "set.h"
+#include "udev-util.h"
+#include "virt.h"
/* use 8 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (8*1024*1024)
@@ -277,6 +279,348 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
+int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ Manager *m = userdata;
+ Link *link = NULL;
+ uint16_t type;
+ uint32_t ifindex, priority = 0;
+ unsigned char protocol, scope, tos, table;
+ int family;
+ unsigned char dst_prefixlen, src_prefixlen;
+ union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {};
+ Route *route = NULL;
+ int r;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive route: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+ log_warning("rtnl: received unexpected message type when processing route");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
+ if (r == -ENODATA) {
+ log_debug("rtnl: received route without ifindex, ignoring");
+ return 0;
+ } else if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex);
+ return 0;
+ } else {
+ r = link_get(m, ifindex, &link);
+ if (r < 0 || !link) {
+ /* when enumerating we might be out of sync, but we will
+ * get the route again, so just ignore it */
+ if (!m->enumerating)
+ log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex);
+ return 0;
+ }
+ }
+
+ r = sd_rtnl_message_route_get_family(message, &family);
+ if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_protocol(message, &protocol);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get route protocol: %m");
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ default:
+ log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_scope(message, &scope);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_tos(message, &tos);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_route_get_table(message, &table);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority);
+ if (r < 0 && r != -ENODATA) {
+ log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m");
+ return 0;
+ }
+
+ route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+
+ switch (type) {
+ case RTM_NEWROUTE:
+ if (!route) {
+ /* A route appeared that we did not request */
+ r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return 0;
+ }
+
+ route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol);
+
+ break;
+
+ case RTM_DELROUTE:
+
+ if (route)
+ route_drop(route);
+
+ break;
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
+int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ Manager *m = userdata;
+ Link *link = NULL;
+ uint16_t type;
+ unsigned char flags;
+ int family;
+ unsigned char prefixlen;
+ unsigned char scope;
+ union in_addr_union in_addr;
+ struct ifa_cacheinfo cinfo;
+ Address *address = NULL;
+ char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
+ const char *valid_str = NULL;
+ int r, ifindex;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive address: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+ log_warning("rtnl: received unexpected message type when processing address");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
+ return 0;
+ } else {
+ r = link_get(m, ifindex, &link);
+ if (r < 0 || !link) {
+ /* when enumerating we might be out of sync, but we will
+ * get the address again, so just ignore it */
+ if (!m->enumerating)
+ log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
+ return 0;
+ }
+ }
+
+ r = sd_rtnl_message_addr_get_family(message, &family);
+ if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_scope(message, &scope);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_flags(message, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ default:
+ log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family);
+ }
+
+ if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
+ log_link_warning(link, "Could not print address");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
+ if (r >= 0) {
+ if (cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
+ valid_str = "ever";
+ else
+ valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+ cinfo.ifa_valid * USEC_PER_SEC,
+ USEC_PER_SEC);
+ }
+
+ address_get(link, family, &in_addr, prefixlen, &address);
+
+ switch (type) {
+ case RTM_NEWADDR:
+ if (address)
+ log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ else {
+ /* An address appeared that we did not request */
+ r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
+ return 0;
+ } else
+ log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ }
+
+ address_update(address, flags, scope, &cinfo);
+
+ break;
+
+ case RTM_DELADDR:
+
+ if (address) {
+ log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ address_drop(address);
+ } else
+ log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ break;
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
@@ -410,17 +754,232 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m);
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m);
if (r < 0)
return r;
return 0;
}
+static int set_put_in_addr(Set *s, const struct in_addr *address) {
+ char *p;
+ int r;
+
+ assert(s);
+
+ r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
+ if (r < 0)
+ return r;
+
+ r = set_consume(s, p);
+ if (r == -EEXIST)
+ return 0;
+
+ return r;
+}
+
+static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
+ int r, i, c = 0;
+
+ assert(s);
+ assert(n <= 0 || addresses);
+
+ for (i = 0; i < n; i++) {
+ r = set_put_in_addr(s, addresses+i);
+ if (r < 0)
+ return r;
+
+ c += r;
+ }
+
+ return c;
+}
+
+static void print_string_set(FILE *f, const char *field, Set *s) {
+ bool space = false;
+ Iterator i;
+ char *p;
+
+ if (set_isempty(s))
+ return;
+
+ fputs(field, f);
+
+ SET_FOREACH(p, s, i) {
+ if (space)
+ fputc(' ', f);
+ fputs(p, f);
+ space = true;
+ }
+ fputc('\n', f);
+}
+
+static int manager_save(Manager *m) {
+ _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
+ Link *link;
+ Iterator i;
+ _cleanup_free_ char *temp_path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ LinkOperationalState operstate = LINK_OPERSTATE_OFF;
+ const char *operstate_str;
+ int r;
+
+ assert(m);
+ assert(m->state_file);
+
+ /* We add all NTP and DNS server to a set, to filter out duplicates */
+ dns = set_new(&string_hash_ops);
+ if (!dns)
+ return -ENOMEM;
+
+ ntp = set_new(&string_hash_ops);
+ if (!ntp)
+ return -ENOMEM;
+
+ domains = set_new(&string_hash_ops);
+ if (!domains)
+ return -ENOMEM;
+
+ HASHMAP_FOREACH(link, m->links, i) {
+ if (link->flags & IFF_LOOPBACK)
+ continue;
+
+ if (link->operstate > operstate)
+ operstate = link->operstate;
+
+ if (!link->network)
+ continue;
+
+ /* First add the static configured entries */
+ r = set_put_strdupv(dns, link->network->dns);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdupv(ntp, link->network->ntp);
+ if (r < 0)
+ return r;
+
+ r = set_put_strdupv(domains, link->network->domains);
+ if (r < 0)
+ return r;
+
+ if (!link->dhcp_lease)
+ continue;
+
+ /* Secondly, add the entries acquired via DHCP */
+ if (link->network->dhcp_dns) {
+ const struct in_addr *addresses;
+
+ r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
+ if (r > 0) {
+ r = set_put_in_addrv(dns, addresses, r);
+ if (r < 0)
+ return r;
+ } else if (r < 0 && r != -ENODATA)
+ return r;
+ }
+
+ if (link->network->dhcp_ntp) {
+ const struct in_addr *addresses;
+
+ r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
+ if (r > 0) {
+ r = set_put_in_addrv(ntp, addresses, r);
+ if (r < 0)
+ return r;
+ } else if (r < 0 && r != -ENODATA)
+ return r;
+ }
+
+ if (link->network->dhcp_domains) {
+ const char *domainname;
+
+ r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
+ if (r >= 0) {
+ r = set_put_strdup(domains, domainname);
+ if (r < 0)
+ return r;
+ } else if (r != -ENODATA)
+ return r;
+ }
+ }
+
+ operstate_str = link_operstate_to_string(operstate);
+ assert(operstate_str);
+
+ r = fopen_temporary(m->state_file, &f, &temp_path);
+ if (r < 0)
+ return r;
+
+ fchmod(fileno(f), 0644);
+
+ fprintf(f,
+ "# This is private data. Do not parse.\n"
+ "OPER_STATE=%s\n", operstate_str);
+
+ print_string_set(f, "DNS=", dns);
+ print_string_set(f, "NTP=", ntp);
+ print_string_set(f, "DOMAINS=", domains);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ goto fail;
+
+ if (rename(temp_path, m->state_file) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (m->operational_state != operstate) {
+ m->operational_state = operstate;
+ r = manager_send_changed(m, "OperationalState", NULL);
+ if (r < 0)
+ log_error_errno(r, "Could not emit changed OperationalState: %m");
+ }
+
+ m->dirty = false;
+
+ return 0;
+
+fail:
+ (void) unlink(m->state_file);
+ (void) unlink(temp_path);
+
+ return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
+}
+
+static int manager_dirty_handler(sd_event_source *s, void *userdata) {
+ Manager *m = userdata;
+ Link *link;
+ Iterator i;
+ int r;
+
+ assert(m);
+
+ if (m->dirty)
+ manager_save(m);
+
+ SET_FOREACH(link, m->dirty_links, i) {
+ r = link_save(link);
+ if (r >= 0)
+ link_clean(link);
+ }
+
+ return 1;
+}
+
int manager_new(Manager **ret) {
_cleanup_manager_free_ Manager *m = NULL;
int r;
@@ -442,6 +1001,10 @@ int manager_new(Manager **ret) {
sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+ r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m);
+ if (r < 0)
+ return r;
+
r = manager_connect_rtnl(m);
if (r < 0)
return r;
@@ -477,14 +1040,6 @@ void manager_free(Manager *m) {
free(m->state_file);
- sd_event_source_unref(m->udev_event_source);
- udev_monitor_unref(m->udev_monitor);
- udev_unref(m->udev);
-
- sd_bus_unref(m->bus);
- sd_bus_slot_unref(m->prepare_for_sleep_slot);
- sd_event_source_unref(m->bus_retry_event_source);
-
while ((link = hashmap_first(m->links)))
link_unref(link);
hashmap_free(m->links);
@@ -504,6 +1059,14 @@ void manager_free(Manager *m) {
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
+ sd_event_source_unref(m->udev_event_source);
+ udev_monitor_unref(m->udev_monitor);
+ udev_unref(m->udev);
+
+ sd_bus_unref(m->bus);
+ sd_bus_slot_unref(m->prepare_for_sleep_slot);
+ sd_event_source_unref(m->bus_retry_event_source);
+
free(m);
}
@@ -536,8 +1099,19 @@ static bool manager_check_idle(void *userdata) {
}
int manager_run(Manager *m) {
+ Link *link;
+ Iterator i;
+
assert(m);
+ /* The dirty handler will deal with future serialization, but the first one
+ must be done explicitly. */
+
+ manager_save(m);
+
+ HASHMAP_FOREACH(link, m->links, i)
+ link_save(link);
+
if (m->bus)
return bus_event_loop_with_idle(
m->event,
@@ -633,7 +1207,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
m->enumerating = true;
- k = link_rtnl_process_address(m->rtnl, addr, m);
+ k = manager_rtnl_process_address(m->rtnl, addr, m);
if (k < 0)
r = k;
@@ -643,189 +1217,39 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
return r;
}
-static int set_put_in_addr(Set *s, const struct in_addr *address) {
- char *p;
+int manager_rtnl_enumerate_routes(Manager *m) {
+ _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
+ sd_netlink_message *route;
int r;
- assert(s);
+ assert(m);
+ assert(m->rtnl);
- r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
+ r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
if (r < 0)
return r;
- r = set_consume(s, p);
- if (r == -EEXIST)
- return 0;
-
- return r;
-}
-
-static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
- int r, i, c = 0;
-
- assert(s);
- assert(n <= 0 || addresses);
-
- for (i = 0; i < n; i++) {
- r = set_put_in_addr(s, addresses+i);
- if (r < 0)
- return r;
-
- c += r;
- }
-
- return c;
-}
-
-static void print_string_set(FILE *f, const char *field, Set *s) {
- bool space = false;
- Iterator i;
- char *p;
-
- if (set_isempty(s))
- return;
-
- fputs(field, f);
-
- SET_FOREACH(p, s, i) {
- if (space)
- fputc(' ', f);
- fputs(p, f);
- space = true;
- }
- fputc('\n', f);
-}
-
-int manager_save(Manager *m) {
- _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
- Link *link;
- Iterator i;
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- LinkOperationalState operstate = LINK_OPERSTATE_OFF;
- const char *operstate_str;
- int r;
-
- assert(m);
- assert(m->state_file);
-
- /* We add all NTP and DNS server to a set, to filter out duplicates */
- dns = set_new(&string_hash_ops);
- if (!dns)
- return -ENOMEM;
-
- ntp = set_new(&string_hash_ops);
- if (!ntp)
- return -ENOMEM;
-
- domains = set_new(&string_hash_ops);
- if (!domains)
- return -ENOMEM;
-
- HASHMAP_FOREACH(link, m->links, i) {
- if (link->flags & IFF_LOOPBACK)
- continue;
-
- if (link->operstate > operstate)
- operstate = link->operstate;
-
- if (!link->network)
- continue;
-
- /* First add the static configured entries */
- r = set_put_strdupv(dns, link->network->dns);
- if (r < 0)
- return r;
-
- r = set_put_strdupv(ntp, link->network->ntp);
- if (r < 0)
- return r;
-
- r = set_put_strdupv(domains, link->network->domains);
- if (r < 0)
- return r;
-
- if (!link->dhcp_lease)
- continue;
-
- /* Secondly, add the entries acquired via DHCP */
- if (link->network->dhcp_dns) {
- const struct in_addr *addresses;
-
- r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
- if (r > 0) {
- r = set_put_in_addrv(dns, addresses, r);
- if (r < 0)
- return r;
- } else if (r < 0 && r != -ENODATA)
- return r;
- }
-
- if (link->network->dhcp_ntp) {
- const struct in_addr *addresses;
-
- r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
- if (r > 0) {
- r = set_put_in_addrv(ntp, addresses, r);
- if (r < 0)
- return r;
- } else if (r < 0 && r != -ENODATA)
- return r;
- }
-
- if (link->network->dhcp_domains) {
- const char *domainname;
-
- r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
- if (r >= 0) {
- r = set_put_strdup(domains, domainname);
- if (r < 0)
- return r;
- } else if (r != -ENODATA)
- return r;
- }
- }
-
- operstate_str = link_operstate_to_string(operstate);
- assert(operstate_str);
-
- r = fopen_temporary(m->state_file, &f, &temp_path);
+ r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
- fchmod(fileno(f), 0644);
-
- fprintf(f,
- "# This is private data. Do not parse.\n"
- "OPER_STATE=%s\n", operstate_str);
-
- print_string_set(f, "DNS=", dns);
- print_string_set(f, "NTP=", ntp);
- print_string_set(f, "DOMAINS=", domains);
-
- r = fflush_and_check(f);
+ r = sd_netlink_call(m->rtnl, req, 0, &reply);
if (r < 0)
- goto fail;
+ return r;
- if (rename(temp_path, m->state_file) < 0) {
- r = -errno;
- goto fail;
- }
+ for (route = reply; route; route = sd_netlink_message_next(route)) {
+ int k;
- if (m->operational_state != operstate) {
- m->operational_state = operstate;
- r = manager_send_changed(m, "OperationalState", NULL);
- if (r < 0)
- log_error_errno(r, "Could not emit changed OperationalState: %m");
- }
+ m->enumerating = true;
- return 0;
+ k = manager_rtnl_process_route(m->rtnl, route, m);
+ if (k < 0)
+ r = k;
-fail:
- (void) unlink(m->state_file);
- (void) unlink(temp_path);
+ m->enumerating = false;
+ }
- return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
+ return r;
}
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
@@ -884,3 +1308,10 @@ Link* manager_find_uplink(Manager *m, Link *exclude) {
return NULL;
}
+
+void manager_dirty(Manager *manager) {
+ assert(manager);
+
+ /* the serialized state in /run is no longer up-to-date */
+ manager->dirty = true;
+}
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
new file mode 100644
index 0000000000..33e692f97f
--- /dev/null
+++ b/src/network/networkd-ndisc.c
@@ -0,0 +1,88 @@
+/*-*- 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 "sd-ndisc.h"
+
+#include "networkd-link.h"
+
+static void ndisc_router_handler(sd_ndisc *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 SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE:
+ return;
+
+ case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER:
+ dhcp6_configure(link, true);
+
+ break;
+ case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
+ case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED:
+ dhcp6_configure(link, false);
+
+ break;
+
+ default:
+ if (event < 0)
+ log_link_warning_errno(link, event, "IPv6 Neighbor Discover error: %m");
+ else
+ log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
+
+ break;
+ }
+}
+
+int ndisc_configure(Link *link) {
+ int r;
+
+ assert_return(link, -EINVAL);
+
+ r = sd_ndisc_new(&link->ndisc_router_discovery);
+ if (r < 0)
+ return r;
+
+ r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac);
+ if (r < 0)
+ return r;
+
+ r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_ndisc_set_callback(link->ndisc_router_discovery,
+ ndisc_router_handler, link);
+
+ return r;
+}
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 12e2321674..70105b8aa0 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -23,10 +23,14 @@
#include <netinet/ether.h>
#include <linux/if_bonding.h>
-#include "conf-parser.h"
#include "sd-netlink.h"
-#include "networkd-netdev-bond.h"
+
+#include "alloc-util.h"
+#include "conf-parser.h"
#include "missing.h"
+#include "networkd-netdev-bond.h"
+#include "string-util.h"
+#include "string-table.h"
/*
* Number of seconds between instances where the bonding
@@ -178,15 +182,18 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
}
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
- Bond *b = BOND(netdev);
+ Bond *b;
ArpIpTarget *target = NULL;
int r, i = 0;
assert(netdev);
assert(!link);
- assert(b);
assert(m);
+ b = BOND(netdev);
+
+ assert(b);
+
if (b->mode != _NETDEV_BOND_MODE_INVALID) {
r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
bond_mode_to_kernel(b->mode));
@@ -357,12 +364,12 @@ int config_parse_arp_ip_target_address(const char *unit,
r = in_addr_from_string_auto(n, &f, &buffer->ip);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
return 0;
}
if (f != AF_INET) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
return 0;
}
@@ -373,16 +380,19 @@ int config_parse_arp_ip_target_address(const char *unit,
}
if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
return 0;
}
static void bond_done(NetDev *netdev) {
ArpIpTarget *t = NULL, *n = NULL;
- Bond *b = BOND(netdev);
+ Bond *b;
assert(netdev);
+
+ b = BOND(netdev);
+
assert(b);
LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
@@ -392,9 +402,12 @@ static void bond_done(NetDev *netdev) {
}
static void bond_init(NetDev *netdev) {
- Bond *b = BOND(netdev);
+ Bond *b;
assert(netdev);
+
+ b = BOND(netdev);
+
assert(b);
b->mode = _NETDEV_BOND_MODE_INVALID;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index fd6af7e99b..57c58d83b4 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -20,12 +20,97 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <net/if.h>
#include "networkd-netdev-bridge.h"
#include "missing.h"
+#include "netlink-util.h"
+
+/* callback for brige netdev's parameter set */
+static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_netdev_unref_ NetDev *netdev = userdata;
+ int r;
+
+ assert(netdev);
+ assert(m);
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0) {
+ log_netdev_warning_errno(netdev, r, "Bridge parameters could not be set: %m");
+ return 1;
+ }
+
+ log_netdev_debug(netdev, "Bridge parametres set success");
+
+ return 1;
+}
+
+static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+ Bridge *b;
+ int r;
+
+ assert(netdev);
+
+ b = BRIDGE(netdev);
+
+ assert(b);
+
+ r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, netdev->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set netlink flags: %m");
+
+ r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m");
+
+ r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ /* convert to jiffes */
+ if (b->forward_delay > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
+ }
+
+ if (b->hello_time > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
+ }
+
+ if (b->max_age > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
+ }
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ r = sd_netlink_call_async(netdev->manager->rtnl, req, netdev_bridge_set_handler, netdev, 0, NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
+
+ netdev_ref(netdev);
+
+ return r;
+}
const NetDevVTable bridge_vtable = {
.object_size = sizeof(Bridge),
- .sections = "Match\0NetDev\0",
+ .sections = "Match\0NetDev\0Bridge\0",
+ .post_create = netdev_bridge_post_create,
.create_type = NETDEV_CREATE_MASTER,
};
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index a7d02b1c91..d3bd15e0d6 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -27,6 +27,10 @@ typedef struct Bridge Bridge;
struct Bridge {
NetDev meta;
+
+ usec_t forward_delay;
+ usec_t hello_time;
+ usec_t max_age;
};
extern const NetDevVTable bridge_vtable;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index e0bd0e024a..4aac239850 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -86,3 +86,6 @@ Bond.UpDelaySec, config_parse_sec, 0,
Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval)
Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval)
+Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
+Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
+Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c
index 5eb4a1eb36..27cb7d1bf0 100644
--- a/src/network/networkd-netdev-ipvlan.c
+++ b/src/network/networkd-netdev-ipvlan.c
@@ -21,8 +21,9 @@
#include <net/if.h>
-#include "networkd-netdev-ipvlan.h"
#include "conf-parser.h"
+#include "networkd-netdev-ipvlan.h"
+#include "string-table.h"
static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = {
[NETDEV_IPVLAN_MODE_L2] = "L2",
@@ -33,14 +34,17 @@ DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode");
static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
- IPVlan *m = IPVLAN(netdev);
+ IPVlan *m;
int r;
assert(netdev);
- assert(m);
assert(link);
assert(netdev->ifname);
+ m = IPVLAN(netdev);
+
+ assert(m);
+
if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) {
r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode);
if (r < 0)
@@ -51,9 +55,12 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netl
}
static void ipvlan_init(NetDev *n) {
- IPVlan *m = IPVLAN(n);
+ IPVlan *m;
assert(n);
+
+ m = IPVLAN(n);
+
assert(m);
m->mode = _NETDEV_IPVLAN_MODE_INVALID;
diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c
index e17de793ce..7144823b2d 100644
--- a/src/network/networkd-netdev-macvlan.c
+++ b/src/network/networkd-netdev-macvlan.c
@@ -21,8 +21,9 @@
#include <net/if.h>
-#include "networkd-netdev-macvlan.h"
#include "conf-parser.h"
+#include "networkd-netdev-macvlan.h"
+#include "string-table.h"
static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
[NETDEV_MACVLAN_MODE_PRIVATE] = "private",
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index a906e473b6..385338849f 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -26,11 +26,15 @@
#include <linux/ip6_tunnel.h>
#include "sd-netlink.h"
-#include "networkd-netdev-tunnel.h"
+
+#include "conf-parser.h"
+#include "missing.h"
#include "networkd-link.h"
+#include "networkd-netdev-tunnel.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
#include "util.h"
-#include "missing.h"
-#include "conf-parser.h"
#define DEFAULT_TNL_HOP_LIMIT 64
#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
@@ -395,12 +399,12 @@ int config_parse_tunnel_address(const char *unit,
r = in_addr_from_string_auto(rvalue, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
return 0;
}
if (t->family != AF_UNSPEC && t->family != f) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
return 0;
}
@@ -435,13 +439,14 @@ int config_parse_ipv6_flowlabel(const char* unit,
t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
} else {
r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
- if (r >= 0) {
- if (k > 0xFFFFF)
- log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
- else {
- *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
- t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
- }
+ if (r < 0)
+ return r;
+
+ if (k > 0xFFFFF)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
+ else {
+ *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
+ t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
}
}
@@ -471,13 +476,12 @@ int config_parse_encap_limit(const char* unit,
else {
r = safe_atoi(rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
return 0;
}
if (k > 255 || k < 0)
- log_syntax(unit, LOG_ERR, filename, line, k, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
else {
t->encap_limit = k;
t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index 6a808b6205..851e83537e 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -23,7 +23,10 @@
#include <net/if.h>
#include <linux/if_tun.h>
+#include "alloc-util.h"
+#include "fd-util.h"
#include "networkd-netdev-tuntap.h"
+#include "user-util.h"
#define TUN_DEV "/dev/net/tun"
diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c
index e20f9f74e2..bee1a16726 100644
--- a/src/network/networkd-netdev-veth.c
+++ b/src/network/networkd-netdev-veth.c
@@ -26,14 +26,17 @@
#include "networkd-netdev-veth.h"
static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
- Veth *v = VETH(netdev);
+ Veth *v;
int r;
assert(netdev);
assert(!link);
- assert(v);
assert(m);
+ v = VETH(netdev);
+
+ assert(v);
+
r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m");
@@ -58,13 +61,16 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin
}
static int netdev_veth_verify(NetDev *netdev, const char *filename) {
- Veth *v = VETH(netdev);
+ Veth *v;
int r;
assert(netdev);
- assert(v);
assert(filename);
+ v = VETH(netdev);
+
+ assert(v);
+
if (!v->ifname_peer) {
log_warning("Veth NetDev without peer name configured in %s. Ignoring",
filename);
@@ -84,9 +90,12 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) {
}
static void veth_done(NetDev *n) {
- Veth *v = VETH(n);
+ Veth *v;
assert(n);
+
+ v = VETH(n);
+
assert(v);
free(v->ifname_peer);
diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c
index 195d1a944e..75fbdd355e 100644
--- a/src/network/networkd-netdev-vlan.c
+++ b/src/network/networkd-netdev-vlan.c
@@ -24,14 +24,17 @@
#include "networkd-netdev-vlan.h"
static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) {
- VLan *v = VLAN(netdev);
+ VLan *v;
int r;
assert(netdev);
- assert(v);
assert(link);
assert(req);
+ v = VLAN(netdev);
+
+ assert(v);
+
if (v->id <= VLANID_MAX) {
r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id);
if (r < 0)
@@ -42,12 +45,15 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin
}
static int netdev_vlan_verify(NetDev *netdev, const char *filename) {
- VLan *v = VLAN(netdev);
+ VLan *v;
assert(netdev);
- assert(v);
assert(filename);
+ v = VLAN(netdev);
+
+ assert(v);
+
if (v->id > VLANID_MAX) {
log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename);
return -EINVAL;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 2518e2732b..baf6dd6623 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -28,14 +28,16 @@
#include "missing.h"
static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
- VxLan *v = VXLAN(netdev);
+ VxLan *v;
int r;
assert(netdev);
- assert(v);
assert(link);
assert(m);
+ v = VXLAN(netdev);
+
+ assert(v);
if (v->id <= VXLAN_VID_MAX) {
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id);
@@ -131,14 +133,12 @@ int config_parse_vxlan_group_address(const char *unit,
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "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);
+ if (v->family != AF_UNSPEC && v->family != f) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan multicast group incompatible, ignoring assignment: %s", rvalue);
return 0;
}
@@ -164,9 +164,12 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) {
}
static void vxlan_init(NetDev *netdev) {
- VxLan *v = VXLAN(netdev);
+ VxLan *v;
assert(netdev);
+
+ v = VXLAN(netdev);
+
assert(v);
v->id = VXLAN_VID_MAX + 1;
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index ff1edf2c39..dd0b400c6a 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -21,15 +21,19 @@
#include <net/if.h>
+#include "alloc-util.h"
#include "conf-files.h"
#include "conf-parser.h"
+#include "fd-util.h"
#include "list.h"
-#include "siphash24.h"
#include "netlink-util.h"
#include "network-internal.h"
-
-#include "networkd.h"
#include "networkd-netdev.h"
+#include "networkd.h"
+#include "siphash24.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
@@ -245,6 +249,9 @@ static int netdev_enter_ready(NetDev *netdev) {
free(callback);
}
+ if (NETDEV_VTABLE(netdev)->post_create)
+ NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
+
return 0;
}
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 1f8510c4f7..3b9ab27b67 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -141,6 +141,9 @@ struct NetDevVTable {
/* create netdev, if not done via rtnl */
int (*create)(NetDev *netdev);
+ /* perform additional configuration after netdev has been createad */
+ int (*post_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
+
/* verify that compulsory configuration options were specified */
int (*config_verify)(NetDev *netdev, const char *filename);
};
diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c
index 5717a15327..120760a986 100644
--- a/src/network/networkd-network-bus.c
+++ b/src/network/networkd-network-bus.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
-
+#include "alloc-util.h"
#include "networkd.h"
+#include "string-util.h"
+#include "strv.h"
static int property_get_ether_addrs(
sd_bus *bus,
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 8257ab45da..cc01dc24c9 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -51,6 +51,7 @@ Network.IPForward, config_parse_address_family_boolean_with
Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
+Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
@@ -61,6 +62,7 @@ Route.Destination, config_parse_destination,
Route.Source, config_parse_destination, 0, 0
Route.Metric, config_parse_route_priority, 0, 0
Route.Scope, config_parse_route_scope, 0, 0
+Route.PreferredSource, config_parse_preferred_src, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 57495b58e0..0188cb6fe5 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -22,15 +22,20 @@
#include <ctype.h>
#include <net/if.h>
+#include "alloc-util.h"
#include "conf-files.h"
#include "conf-parser.h"
-#include "util.h"
-#include "hostname-util.h"
#include "dns-domain.h"
+#include "fd-util.h"
+#include "hostname-util.h"
#include "network-internal.h"
-
-#include "networkd.h"
#include "networkd-network.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
static int network_load_one(Manager *manager, const char *filename) {
_cleanup_network_free_ Network *network = NULL;
@@ -121,6 +126,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
network->ipv6_accept_ra = -1;
+ network->ipv6_dad_transmits = -1;
r = config_parse(NULL, filename, file,
"Match\0"
@@ -326,12 +332,12 @@ int network_get(Manager *manager, struct udev_device *device,
(void) safe_atou8(attr, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM)
- log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
- IFNAMSIZ, ifname, network->filename);
+ log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
+ ifname, network->filename);
else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
} else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
*ret = network;
return 0;
@@ -346,6 +352,10 @@ int network_get(Manager *manager, struct udev_device *device,
int network_apply(Manager *manager, Network *network, Link *link) {
int r;
+ assert(manager);
+ assert(network);
+ assert(link);
+
link->network = network;
if (network->ipv4ll_route) {
@@ -355,7 +365,7 @@ int network_apply(Manager *manager, Network *network, Link *link) {
if (r < 0)
return r;
- r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in);
+ r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
if (r == 0)
return -EINVAL;
if (r < 0)
@@ -364,14 +374,13 @@ int network_apply(Manager *manager, Network *network, Link *link) {
route->family = AF_INET;
route->dst_prefixlen = 16;
route->scope = RT_SCOPE_LINK;
- route->metrics = IPV4LL_ROUTE_METRIC;
+ route->priority = IPV4LL_ROUTE_METRIC;
route->protocol = RTPROT_STATIC;
}
- if (network->dns || network->ntp) {
- r = link_save(link);
- if (r < 0)
- return r;
+ if (network->dns || network->ntp || network->domains) {
+ manager_dirty(manager);
+ link_dirty(link);
}
return 0;
@@ -409,21 +418,18 @@ int config_parse_netdev(const char *unit,
kind = netdev_kind_from_string(kind_string);
if (kind == _NETDEV_KIND_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid NetDev kind: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
return 0;
}
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (netdev->kind != kind) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
@@ -443,9 +449,7 @@ int config_parse_netdev(const char *unit,
case NETDEV_KIND_VXLAN:
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Can not add VLAN '%s' to network: %m",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue);
return 0;
}
@@ -484,7 +488,7 @@ int config_parse_domains(const char *unit,
STRV_FOREACH(domain, *domains) {
if (is_localhost(*domain))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
else {
r = dns_name_is_valid(*domain);
if (r <= 0 && !streq(*domain, "*")) {
@@ -540,7 +544,7 @@ int config_parse_tunnel(const char *unit,
netdev->kind != NETDEV_KIND_VTI6 &&
netdev->kind != NETDEV_KIND_IP6TNL
) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, 0,
"NetDev is not a tunnel, ignoring assignment: %s", rvalue);
return 0;
}
@@ -625,7 +629,7 @@ int config_parse_dhcp(
else if (streq(rvalue, "both"))
s = ADDRESS_FAMILY_YES;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
return 0;
}
}
@@ -670,13 +674,13 @@ int config_parse_ipv6token(
}
r = in_addr_is_null(AF_INET6, &buffer);
- if (r < 0) {
+ if (r != 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
return 0;
}
if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
return 0;
}
@@ -730,7 +734,7 @@ int config_parse_ipv6_privacy_extensions(
if (streq(rvalue, "kernel"))
s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
return 0;
}
}
@@ -765,7 +769,7 @@ int config_parse_hostname(
return r;
if (!hostname_is_valid(hn, false)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
free(hn);
return 0;
}
@@ -799,7 +803,7 @@ int config_parse_timezone(
return r;
if (!timezone_is_valid(tz)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
free(tz);
return 0;
}
@@ -844,7 +848,7 @@ int config_parse_dhcp_server_dns(
return 0;
if (inet_pton(AF_INET, w, &a) <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
continue;
}
@@ -883,7 +887,7 @@ int config_parse_dhcp_server_ntp(
r = extract_first_word(&p, &w, NULL, 0);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, r, line, "Failed to extract word, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
return 0;
}
@@ -891,7 +895,7 @@ int config_parse_dhcp_server_ntp(
return 0;
if (inet_pton(AF_INET, w, &a) <= 0) {
- log_syntax(unit, LOG_ERR, filename, r, line, "Failed to parse NTP server address, ignoring: %s", w);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
continue;
}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 2a43b6b347..c2872908b5 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -121,6 +121,7 @@ struct Network {
bool ip_masquerade;
int ipv6_accept_ra;
+ int ipv6_dad_transmits;
union in_addr_union ipv6_token;
IPv6PrivacyExtensions ipv6_privacy_extensions;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index fbaad40579..f4bbd06af1 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -19,15 +19,40 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "alloc-util.h"
#include "conf-parser.h"
+#include "event-util.h"
+#include "in-addr-util.h"
#include "netlink-util.h"
-
-#include "networkd.h"
#include "networkd-route.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "util.h"
+
+int route_new(Route **ret) {
+ _cleanup_route_free_ Route *route = NULL;
+
+ route = new0(Route, 1);
+ if (!route)
+ return -ENOMEM;
+
+ route->family = AF_UNSPEC;
+ route->scope = RT_SCOPE_UNIVERSE;
+ route->protocol = RTPROT_UNSPEC;
+ route->table = RT_TABLE_DEFAULT;
+ route->lifetime = USEC_INFINITY;
+
+ *ret = route;
+ route = NULL;
+
+ return 0;
+}
int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
+ int r;
if (section) {
route = hashmap_get(network->routes_by_section,
@@ -40,14 +65,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
}
}
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
+ r = route_new(&route);
+ if (r < 0)
+ return r;
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
route->protocol = RTPROT_STATIC;
-
route->network = network;
LIST_PREPEND(routes, network->static_routes, route);
@@ -64,23 +86,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
return 0;
}
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
- _cleanup_route_free_ Route *route = NULL;
-
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
-
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
- route->protocol = rtm_protocol;
-
- *ret = route;
- route = NULL;
-
- return 0;
-}
-
void route_free(Route *route) {
if (!route)
return;
@@ -93,10 +98,241 @@ void route_free(Route *route) {
UINT_TO_PTR(route->section));
}
+ if (route->link) {
+ set_remove(route->link->routes, route);
+ set_remove(route->link->routes_foreign, route);
+ }
+
+ sd_event_source_unref(route->expire);
+
free(route);
}
-int route_drop(Route *route, Link *link,
+static void route_hash_func(const void *b, struct siphash *state) {
+ const Route *route = b;
+
+ assert(route);
+
+ siphash24_compress(&route->family, sizeof(route->family), state);
+
+ switch (route->family) {
+ case AF_INET:
+ case AF_INET6:
+ /* Equality of routes are given by the 4-touple
+ (dst_prefix,dst_prefixlen,tos,priority,table) */
+ siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
+ siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
+ siphash24_compress(&route->tos, sizeof(route->tos), state);
+ siphash24_compress(&route->priority, sizeof(route->priority), state);
+ siphash24_compress(&route->table, sizeof(route->table), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int route_compare_func(const void *_a, const void *_b) {
+ const Route *a = _a, *b = _b;
+
+ if (a->family < b->family)
+ return -1;
+ if (a->family > b->family)
+ return 1;
+
+ switch (a->family) {
+ case AF_INET:
+ case AF_INET6:
+ if (a->dst_prefixlen < b->dst_prefixlen)
+ return -1;
+ if (a->dst_prefixlen > b->dst_prefixlen)
+ return 1;
+
+ if (a->tos < b->tos)
+ return -1;
+ if (a->tos > b->tos)
+ return 1;
+
+ if (a->priority < b->priority)
+ return -1;
+ if (a->priority > b->priority)
+ return 1;
+
+ if (a->table < b->table)
+ return -1;
+ if (a->table > b->table)
+ return 1;
+
+ return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+static const struct hash_ops route_hash_ops = {
+ .hash = route_hash_func,
+ .compare = route_compare_func
+};
+
+int route_get(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table,
+ Route **ret) {
+ Route route = {
+ .family = family,
+ .dst_prefixlen = dst_prefixlen,
+ .tos = tos,
+ .priority = priority,
+ .table = table,
+ }, *existing;
+
+ assert(link);
+ assert(dst);
+ assert(ret);
+
+ route.dst = *dst;
+
+ existing = set_get(link->routes, &route);
+ if (existing) {
+ *ret = existing;
+ return 1;
+ } else {
+ existing = set_get(link->routes_foreign, &route);
+ if (!existing)
+ return -ENOENT;
+ }
+
+ *ret = existing;
+
+ return 0;
+}
+
+static int route_add_internal(Link *link, Set **routes,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ _cleanup_route_free_ Route *route = NULL;
+ int r;
+
+ assert(link);
+ assert(routes);
+ assert(dst);
+
+ r = route_new(&route);
+ if (r < 0)
+ return r;
+
+ route->family = family;
+ route->dst = *dst;
+ route->dst_prefixlen = dst_prefixlen;
+ route->tos = tos;
+ route->priority = priority;
+ route->table = table;
+
+ r = set_ensure_allocated(routes, &route_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(*routes, route);
+ if (r < 0)
+ return r;
+
+ route->link = link;
+
+ if (ret)
+ *ret = route;
+
+ route = NULL;
+
+ return 0;
+}
+
+int route_add_foreign(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
+}
+
+int route_add(Link *link,
+ int family,
+ union in_addr_union *dst,
+ unsigned char dst_prefixlen,
+ unsigned char tos,
+ uint32_t priority,
+ unsigned char table, Route **ret) {
+ Route *route;
+ int r;
+
+ r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
+ if (r == -ENOENT) {
+ /* Route does not exist, create a new one */
+ r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
+ if (r < 0)
+ return r;
+ } else if (r == 0) {
+ /* Take over a foreign route */
+ r = set_ensure_allocated(&link->routes, &route_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->routes, route);
+ if (r < 0)
+ return r;
+
+ set_remove(link->routes_foreign, route);
+ } else if (r == 1) {
+ /* Route exists, do nothing */
+ ;
+ } else
+ return r;
+
+ *ret = route;
+
+ return 0;
+}
+
+int route_update(Route *route,
+ union in_addr_union *src,
+ unsigned char src_prefixlen,
+ union in_addr_union *gw,
+ union in_addr_union *prefsrc,
+ unsigned char scope,
+ unsigned char protocol) {
+ assert(route);
+ assert(src);
+ assert(gw);
+ assert(prefsrc);
+
+ route->src = *src;
+ route->src_prefixlen = src_prefixlen;
+ route->gw = *gw;
+ route->prefsrc = *prefsrc;
+ route->scope = scope;
+ route->protocol = protocol;
+
+ return 0;
+}
+
+void route_drop(Route *route) {
+ assert(route);
+
+ route_free(route);
+}
+
+int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -113,20 +349,20 @@ int route_drop(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
- if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (!in_addr_is_null(route->family, &route->gw)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -137,9 +373,9 @@ int route_drop(Route *route, Link *link,
if (route->src_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -148,11 +384,11 @@ int route_drop(Route *route, Link *link,
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+ if (!in_addr_is_null(route->family, &route->prefsrc)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
@@ -161,7 +397,7 @@ int route_drop(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
- r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
@@ -178,9 +414,24 @@ int route_drop(Route *route, Link *link,
return 0;
}
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
+ Route *route = userdata;
+ int r;
+
+ assert(route);
+
+ r = route_remove(route, route->link, NULL);
+ if (r < 0)
+ log_warning_errno(r, "Could not remove route: %m");
+
+ return 1;
+}
+
int route_configure(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+ _cleanup_event_source_unref_ sd_event_source *expire = NULL;
+ usec_t lifetime;
int r;
assert(link);
@@ -195,20 +446,20 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
- if (!in_addr_is_null(route->family, &route->in_addr)) {
+ if (!in_addr_is_null(route->family, &route->gw)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
}
if (route->dst_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_DST attribute: %m");
@@ -219,9 +470,9 @@ int route_configure(Route *route, Link *link,
if (route->src_prefixlen) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
@@ -230,11 +481,11 @@ int route_configure(Route *route, Link *link,
return log_error_errno(r, "Could not set source prefix length: %m");
}
- if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
+ if (!in_addr_is_null(route->family, &route->prefsrc)) {
if (route->family == AF_INET)
- r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
+ r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
else if (route->family == AF_INET6)
- r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
+ r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
}
@@ -243,7 +494,7 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set scope: %m");
- r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics);
+ r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
@@ -257,6 +508,26 @@ int route_configure(Route *route, Link *link,
link_ref(link);
+ lifetime = route->lifetime;
+
+ r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
+ if (r < 0)
+ return log_error_errno(r, "Could not add route: %m");
+
+ /* TODO: drop expiration handling once it can be pushed into the kernel */
+ route->lifetime = lifetime;
+
+ if (route->lifetime != USEC_INFINITY) {
+ r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
+ route->lifetime, 0, route_expire_handler, route);
+ if (r < 0)
+ return log_error_errno(r, "Could not arm expiration timer: %m");
+ }
+
+ sd_event_source_unref(route->expire);
+ route->expire = expire;
+ expire = NULL;
+
return 0;
}
@@ -294,13 +565,52 @@ int config_parse_gateway(const char *unit,
r = in_addr_from_string_auto(rvalue, &f, &buffer);
if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ n->family = f;
+ n->gw = buffer;
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_preferred_src(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) {
+
+ Network *network = userdata;
+ _cleanup_route_free_ Route *n = NULL;
+ union in_addr_union buffer;
+ int r, f;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Route is invalid, ignoring assignment: %s", rvalue);
+ "Preferred source is invalid, ignoring assignment: %s", rvalue);
return 0;
}
n->family = f;
- n->in_addr = buffer;
+ n->prefsrc = buffer;
n = NULL;
return 0;
@@ -345,14 +655,12 @@ int config_parse_destination(const char *unit,
r = in_addr_from_string_auto(address, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Destination is invalid, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Destination is invalid, ignoring assignment: %s", address);
return 0;
}
if (f != AF_INET && f != AF_INET6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unknown address family, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address);
return 0;
}
@@ -360,8 +668,7 @@ int config_parse_destination(const char *unit,
if (e) {
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);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
} else {
@@ -377,10 +684,10 @@ int config_parse_destination(const char *unit,
n->family = f;
if (streq(lvalue, "Destination")) {
- n->dst_addr = buffer;
+ n->dst = buffer;
n->dst_prefixlen = prefixlen;
} else if (streq(lvalue, "Source")) {
- n->src_addr = buffer;
+ n->src = buffer;
n->src_prefixlen = prefixlen;
} else
assert_not_reached(lvalue);
@@ -414,9 +721,9 @@ int config_parse_route_priority(const char *unit,
if (r < 0)
return r;
- r = config_parse_unsigned(unit, filename, line, section,
- section_line, lvalue, ltype,
- rvalue, &n->metrics, userdata);
+ r = config_parse_uint32(unit, filename, line, section,
+ section_line, lvalue, ltype,
+ rvalue, &n->priority, userdata);
if (r < 0)
return r;
@@ -456,8 +763,7 @@ int config_parse_route_scope(const char *unit,
else if (streq(rvalue, "global"))
n->scope = RT_SCOPE_UNIVERSE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unknown route scope: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index d090b9c91e..d0a51838ed 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -30,31 +30,47 @@ struct Route {
Network *network;
unsigned section;
+ Link *link;
+
int family;
unsigned char dst_prefixlen;
unsigned char src_prefixlen;
unsigned char scope;
- uint32_t metrics;
unsigned char protocol; /* RTPROT_* */
+ unsigned char tos;
+ uint32_t priority; /* note that ip(8) calls this 'metric' */
+ unsigned char table;
+
+ union in_addr_union gw;
+ union in_addr_union dst;
+ union in_addr_union src;
+ union in_addr_union prefsrc;
- union in_addr_union in_addr;
- union in_addr_union dst_addr;
- union in_addr_union src_addr;
- union in_addr_union prefsrc_addr;
+ usec_t lifetime;
+ sd_event_source *expire;
LIST_FIELDS(Route, routes);
};
int route_new_static(Network *network, unsigned section, Route **ret);
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol);
+int route_new(Route **ret);
void route_free(Route *route);
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
+
+int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
+int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
+void route_drop(Route *route);
+
+int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
#define _cleanup_route_free_ _cleanup_(route_freep)
int config_parse_gateway(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_preferred_src(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_destination(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_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_scope(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);
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c
index a41cd86239..df091393f6 100644
--- a/src/network/networkd-util.c
+++ b/src/network/networkd-util.c
@@ -19,10 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "conf-parser.h"
-
#include "networkd-util.h"
+#include "parse-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
if (b == ADDRESS_FAMILY_YES ||
@@ -82,7 +84,7 @@ int config_parse_address_family_boolean_with_kernel(
if (streq(rvalue, "kernel"))
s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding= option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue);
return 0;
}
}
@@ -133,7 +135,7 @@ int config_parse_resolve(
s = resolve_support_from_string(rvalue);
if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue);
return 0;
}
diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c
index cacb4c257e..c2779ff773 100644
--- a/src/network/networkd-wait-online-link.c
+++ b/src/network/networkd-wait-online-link.c
@@ -20,10 +20,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include "sd-network.h"
+#include "alloc-util.h"
#include "networkd-wait-online-link.h"
+#include "string-util.h"
int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
_cleanup_(link_freep) Link *l = NULL;
diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c
index 112d92a568..0c40ab2bb8 100644
--- a/src/network/networkd-wait-online-manager.c
+++ b/src/network/networkd-wait-online-manager.c
@@ -23,14 +23,13 @@
#include <linux/if.h>
#include <fnmatch.h>
+#include "alloc-util.h"
#include "netlink-util.h"
-
#include "network-internal.h"
#include "networkd-wait-online-link.h"
#include "networkd-wait-online.h"
-
-#include "util.h"
#include "time-util.h"
+#include "util.h"
bool manager_ignore_link(Manager *m, Link *link) {
char **ignore;
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index d958b48771..3220c4b7ef 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -21,10 +21,10 @@
#include <getopt.h>
#include "sd-daemon.h"
-#include "strv.h"
-#include "build.h"
-#include "signal-util.h"
+
#include "networkd-wait-online.h"
+#include "signal-util.h"
+#include "strv.h"
static bool arg_quiet = false;
static usec_t arg_timeout = 120 * USEC_PER_SEC;
@@ -79,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'i':
if (strv_extend(&arg_interfaces, optarg) < 0)
diff --git a/src/network/networkd.c b/src/network/networkd.c
index e6259043fa..ef394e0c04 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -20,9 +20,11 @@
***/
#include "sd-daemon.h"
-#include "capability.h"
-#include "signal-util.h"
+
+#include "capability-util.h"
#include "networkd.h"
+#include "signal-util.h"
+#include "user-util.h"
int main(int argc, char *argv[]) {
_cleanup_manager_free_ Manager *m = NULL;
@@ -107,6 +109,12 @@ int main(int argc, char *argv[]) {
goto out;
}
+ r = manager_rtnl_enumerate_routes(m);
+ if (r < 0) {
+ log_error_errno(r, "Could not enumerate routes: %m");
+ goto out;
+ }
+
log_info("Enumeration completed");
sd_notify(false,
diff --git a/src/network/networkd.h b/src/network/networkd.h
index eea57ac158..97665fac7a 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -48,7 +48,10 @@ struct Manager {
struct udev_monitor *udev_monitor;
sd_event_source *udev_event_source;
- bool enumerating;
+ bool enumerating:1;
+ bool dirty:1;
+
+ Set *dirty_links;
char *state_file;
LinkOperationalState operational_state;
@@ -79,9 +82,13 @@ bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_rtnl_enumerate_routes(Manager *m);
+
+int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata);
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
-int manager_save(Manager *m);
+void manager_dirty(Manager *m);
int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found);
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 5909cc790e..dbed3795e3 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "networkd.h"
#include "network-internal.h"
#include "dhcp-lease-internal.h"
@@ -143,8 +144,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
static void test_address_equality(void) {
_cleanup_address_free_ Address *a1 = NULL, *a2 = NULL;
- assert_se(address_new_dynamic(&a1) >= 0);
- assert_se(address_new_dynamic(&a2) >= 0);
+ assert_se(address_new(&a1) >= 0);
+ assert_se(address_new(&a2) >= 0);
assert_se(address_equal(NULL, NULL));
assert_se(!address_equal(a1, NULL));
@@ -158,17 +159,18 @@ static void test_address_equality(void) {
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in));
- assert_se(address_equal(a1, a2));
+ assert_se(!address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in));
assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(address_equal(a1, a2));
- assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in));
- assert_se(address_equal(a1, a2));
-
a1->family = AF_INET6;
assert_se(!address_equal(a1, a2));
diff --git a/src/notify/notify.c b/src/notify/notify.c
index 7d53cb6d75..b144554702 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -27,10 +27,12 @@
#include "sd-daemon.h"
-#include "build.h"
+#include "alloc-util.h"
#include "env-util.h"
#include "formats-util.h"
#include "log.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -85,9 +87,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_READY:
arg_ready = true;
diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c
index c0e9ccd7a4..270bcf010f 100644
--- a/src/nspawn/nspawn-cgroup.c
+++ b/src/nspawn/nspawn-cgroup.c
@@ -21,13 +21,15 @@
#include <sys/mount.h>
-#include "util.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "fileio.h"
+#include "alloc-util.h"
#include "cgroup-util.h"
-
+#include "fd-util.h"
+#include "fileio.h"
+#include "mkdir.h"
#include "nspawn-cgroup.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
int chown_cgroup(pid_t pid, uid_t uid_shift) {
_cleanup_free_ char *path = NULL, *fs = NULL;
diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c
index 9e63d88b69..38245434da 100644
--- a/src/nspawn/nspawn-expose-ports.c
+++ b/src/nspawn/nspawn-expose-ports.c
@@ -21,13 +21,17 @@
#include "sd-netlink.h"
-#include "util.h"
-#include "in-addr-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "firewall-util.h"
+#include "in-addr-util.h"
#include "local-addresses.h"
#include "netlink-util.h"
-
#include "nspawn-expose-ports.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
int expose_port_parse(ExposePort **l, const char *s) {
@@ -194,7 +198,7 @@ int expose_port_send_rtnl(int send_fd) {
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- r = send_one_fd(send_fd, fd);
+ r = send_one_fd(send_fd, fd, 0);
if (r < 0)
return log_error_errno(r, "Failed to send netlink fd: %m");
@@ -214,7 +218,7 @@ int expose_port_watch_rtnl(
assert(recv_fd >= 0);
assert(ret);
- fd = receive_one_fd(recv_fd);
+ fd = receive_one_fd(recv_fd, 0);
if (fd < 0)
return log_error_errno(fd, "Failed to recv netlink fd: %m");
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 2bca39f45d..c8e627ac78 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -20,17 +20,25 @@
***/
#include <sys/mount.h>
+#include <linux/magic.h>
-#include "util.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "label.h"
-#include "set.h"
+#include "alloc-util.h"
#include "cgroup-util.h"
-
+#include "escape.h"
+#include "fs-util.h"
+#include "label.h"
+#include "mkdir.h"
+#include "mount-util.h"
#include "nspawn-mount.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "set.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) {
CustomMount *c, *ret;
@@ -216,8 +224,67 @@ static int tmpfs_patch_options(
return !!buf;
}
+int mount_sysfs(const char *dest) {
+ const char *full, *top, *x;
+ int r;
+
+ top = prefix_roota(dest, "/sys");
+ r = path_check_fstype(top, SYSFS_MAGIC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top);
+ /* /sys might already be mounted as sysfs by the outer child in the
+ * !netns case. In this case, it's all good. Don't touch it because we
+ * don't have the right to do so, see https://github.com/systemd/systemd/issues/1555.
+ */
+ if (r > 0)
+ return 0;
+
+ full = prefix_roota(top, "/full");
+
+ (void) mkdir(full, 0755);
+
+ if (mount("sysfs", full, "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount sysfs to %s: %m", full);
+
+ FOREACH_STRING(x, "block", "bus", "class", "dev", "devices", "kernel") {
+ _cleanup_free_ char *from = NULL, *to = NULL;
+
+ from = prefix_root(full, x);
+ if (!from)
+ return log_oom();
+
+ to = prefix_root(top, x);
+ if (!to)
+ return log_oom();
+
+ (void) mkdir(to, 0755);
+
+ if (mount(from, to, NULL, MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount /sys/%s into place: %m", x);
+
+ if (mount(NULL, to, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount /sys/%s read-only: %m", x);
+ }
+
+ if (umount(full) < 0)
+ return log_error_errno(errno, "Failed to unmount %s: %m", full);
+
+ if (rmdir(full) < 0)
+ return log_error_errno(errno, "Failed to remove %s: %m", full);
+
+ x = prefix_roota(top, "/fs/kdbus");
+ (void) mkdir(x, 0755);
+
+ if (mount(NULL, top, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0)
+ return log_error_errno(errno, "Failed to make %s read-only: %m", top);
+
+ return 0;
+}
+
int mount_all(const char *dest,
- bool userns, uid_t uid_shift, uid_t uid_range,
+ bool use_userns, bool in_userns,
+ bool use_netns,
+ uid_t uid_shift, uid_t uid_range,
const char *selinux_apifs_context) {
typedef struct MountPoint {
@@ -227,21 +294,23 @@ int mount_all(const char *dest,
const char *options;
unsigned long flags;
bool fatal;
- bool userns;
+ bool in_userns;
+ bool use_netns;
} MountPoint;
static const MountPoint mount_table[] = {
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true },
- { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */
- { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true }, /* Then, make it r/o */
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false },
- { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
- { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false },
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false },
+ { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first */
+ { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* Then, make it r/o */
+ { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true },
+ { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false },
+ { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false },
+ { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false },
#ifdef HAVE_SELINUX
- { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false }, /* Bind mount first */
- { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false }, /* Then, make it r/o */
+ { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */
+ { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */
#endif
};
@@ -252,7 +321,10 @@ int mount_all(const char *dest,
_cleanup_free_ char *where = NULL, *options = NULL;
const char *o;
- if (userns != mount_table[k].userns)
+ if (in_userns != mount_table[k].in_userns)
+ continue;
+
+ if (!use_netns && mount_table[k].use_netns)
continue;
where = prefix_root(dest, mount_table[k].where);
@@ -278,7 +350,7 @@ int mount_all(const char *dest,
o = mount_table[k].options;
if (streq_ptr(mount_table[k].type, "tmpfs")) {
- r = tmpfs_patch_options(o, userns, uid_shift, uid_range, selinux_apifs_context, &options);
+ r = tmpfs_patch_options(o, use_userns, uid_shift, uid_range, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
if (r > 0)
@@ -369,8 +441,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
if (r < 0)
return log_error_errno(r, "Failed to make parents of %s: %m", where);
} else {
- log_error_errno(errno, "Failed to stat %s: %m", where);
- return -errno;
+ return log_error_errno(errno, "Failed to stat %s: %m", where);
}
/* Create the mount point. Any non-directory file can be
@@ -534,7 +605,7 @@ static int mount_legacy_cgroup_hierarchy(const char *dest, const char *controlle
char *to;
int r;
- to = strjoina(dest, "/sys/fs/cgroup/", hierarchy);
+ to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
r = path_is_mount_point(to, 0);
if (r < 0 && r != -ENOENT)
@@ -569,6 +640,8 @@ static int mount_legacy_cgroups(
cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
+ (void) mkdir_p(cgroup_root, 0755);
+
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
r = path_is_mount_point(cgroup_root, AT_SYMLINK_FOLLOW);
if (r < 0)
@@ -661,13 +734,15 @@ static int mount_unified_cgroups(const char *dest) {
assert(dest);
- p = strjoina(dest, "/sys/fs/cgroup");
+ p = prefix_roota(dest, "/sys/fs/cgroup");
+
+ (void) mkdir_p(p, 0755);
r = path_is_mount_point(p, AT_SYMLINK_FOLLOW);
if (r < 0)
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
if (r > 0) {
- p = strjoina(dest, "/sys/fs/cgroup/cgroup.procs");
+ p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
if (access(p, F_OK) >= 0)
return 0;
if (errno != ENOENT)
diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h
index 5abd44cc4b..bdab23bcca 100644
--- a/src/nspawn/nspawn-mount.h
+++ b/src/nspawn/nspawn-mount.h
@@ -57,7 +57,8 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s);
int custom_mount_compare(const void *a, const void *b);
-int mount_all(const char *dest, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_sysfs(const char *dest);
int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int mount_systemd_cgroup_writable(const char *dest, bool unified_requested);
diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c
index 74abe5379a..29384b60b2 100644
--- a/src/nspawn/nspawn-network.c
+++ b/src/nspawn/nspawn-network.c
@@ -22,16 +22,17 @@
#include <linux/veth.h>
#include <net/if.h>
+#include "libudev.h"
#include "sd-id128.h"
#include "sd-netlink.h"
-#include "libudev.h"
-#include "util.h"
+#include "alloc-util.h"
#include "ether-addr-util.h"
-#include "siphash24.h"
#include "netlink-util.h"
+#include "siphash24.h"
+#include "string-util.h"
#include "udev-util.h"
-
+#include "util.h"
#include "nspawn-network.h"
#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c
index b2776a61c2..374f958c20 100644
--- a/src/nspawn/nspawn-register.c
+++ b/src/nspawn/nspawn-register.c
@@ -21,12 +21,12 @@
#include "sd-bus.h"
-#include "util.h"
-#include "strv.h"
-#include "bus-util.h"
#include "bus-error.h"
-
+#include "bus-util.h"
#include "nspawn-register.h"
+#include "stat-util.h"
+#include "strv.h"
+#include "util.h"
int register_machine(
const char *machine_name,
@@ -39,7 +39,8 @@ int register_machine(
unsigned n_mounts,
int kill_signal,
char **properties,
- bool keep_unit) {
+ bool keep_unit,
+ const char *service) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
@@ -61,7 +62,7 @@ int register_machine(
"sayssusai",
machine_name,
SD_BUS_MESSAGE_APPEND_ID128(uuid),
- "nspawn",
+ service,
"container",
(uint32_t) pid,
strempty(directory),
@@ -86,7 +87,7 @@ int register_machine(
"sayssusai",
machine_name,
SD_BUS_MESSAGE_APPEND_ID128(uuid),
- "nspawn",
+ service,
"container",
(uint32_t) pid,
strempty(directory),
diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h
index b27841ff59..d3bfd84e5e 100644
--- a/src/nspawn/nspawn-register.h
+++ b/src/nspawn/nspawn-register.h
@@ -27,5 +27,5 @@
#include "nspawn-mount.h"
-int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit);
+int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service);
int terminate_machine(pid_t pid);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 419f5d1c40..6885d0641e 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -19,12 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "conf-parser.h"
-#include "strv.h"
+#include "alloc-util.h"
#include "cap-list.h"
-
+#include "conf-parser.h"
#include "nspawn-settings.h"
+#include "process-util.h"
+#include "strv.h"
+#include "util.h"
int settings_load(FILE *f, const char *path, Settings **ret) {
_cleanup_(settings_freep) Settings *s = NULL;
@@ -85,6 +86,26 @@ Settings* settings_free(Settings *s) {
return NULL;
}
+bool settings_private_network(Settings *s) {
+ assert(s);
+
+ return
+ s->private_network > 0 ||
+ s->network_veth > 0 ||
+ s->network_bridge ||
+ s->network_interfaces ||
+ s->network_macvlan ||
+ s->network_ipvlan;
+}
+
+bool settings_network_veth(Settings *s) {
+ assert(s);
+
+ return
+ s->network_veth > 0 ||
+ s->network_bridge;
+}
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
int config_parse_expose_port(
@@ -152,7 +173,7 @@ int config_parse_capability(
cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, cap, "Failed to parse capability, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability, ignoring: %s", word);
continue;
}
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index 4cec40c1b7..16e8c54508 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -75,6 +75,9 @@ typedef struct Settings {
int settings_load(FILE *f, const char *path, Settings **ret);
Settings* settings_free(Settings *s);
+bool settings_network_veth(Settings *s);
+bool settings_private_network(Settings *s);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length);
diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c
index eda7f62900..aa6a16309c 100644
--- a/src/nspawn/nspawn-setuid.c
+++ b/src/nspawn/nspawn-setuid.c
@@ -19,16 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <grp.h>
#include <sys/types.h>
#include <unistd.h>
-#include <grp.h>
-#include "util.h"
-#include "signal-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "mkdir.h"
-#include "process-util.h"
-
#include "nspawn-setuid.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
int pipe_fds[2];
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 7451c2bf64..4c48681f17 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -46,21 +46,23 @@
#include "sd-daemon.h"
#include "sd-id128.h"
+#include "alloc-util.h"
#include "barrier.h"
#include "base-filesystem.h"
#include "blkid-util.h"
#include "btrfs-util.h"
-#include "build.h"
#include "cap-list.h"
-#include "capability.h"
+#include "capability-util.h"
#include "cgroup-util.h"
#include "copy.h"
#include "dev-setup.h"
#include "env-util.h"
#include "event-util.h"
+#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
#include "gpt.h"
#include "hostname-util.h"
#include "log.h"
@@ -69,7 +71,16 @@
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
+#include "mount-util.h"
#include "netlink-util.h"
+#include "nspawn-cgroup.h"
+#include "nspawn-expose-ports.h"
+#include "nspawn-mount.h"
+#include "nspawn-network.h"
+#include "nspawn-register.h"
+#include "nspawn-settings.h"
+#include "nspawn-setuid.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "ptyfwd.h"
@@ -79,19 +90,17 @@
#include "seccomp-util.h"
#endif
#include "signal-util.h"
+#include "socket-util.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "udev-util.h"
+#include "umask-util.h"
+#include "user-util.h"
#include "util.h"
-#include "nspawn-settings.h"
-#include "nspawn-mount.h"
-#include "nspawn-network.h"
-#include "nspawn-expose-ports.h"
-#include "nspawn-cgroup.h"
-#include "nspawn-register.h"
-#include "nspawn-setuid.h"
-
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
CONTAINER_REBOOTED
@@ -169,6 +178,7 @@ static bool arg_unified_cgroup_hierarchy = false;
static SettingsMask arg_settings_mask = 0;
static int arg_settings_trusted = -1;
static char **arg_parameters = NULL;
+static const char *arg_container_service_name = "systemd-nspawn";
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
@@ -200,10 +210,10 @@ static void help(void) {
" --network-ipvlan=INTERFACE\n"
" Create a ipvlan network interface based on an\n"
" existing network interface to the container\n"
- " -n --network-veth Add a virtual ethernet connection between host\n"
+ " -n --network-veth Add a virtual Ethernet connection between host\n"
" and container\n"
" --network-bridge=INTERFACE\n"
- " Add a virtual ethernet connection between host\n"
+ " Add a virtual Ethernet connection between host\n"
" and container and add it to an existing bridge on\n"
" the host\n"
" -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
@@ -277,27 +287,6 @@ static int custom_mounts_prepare(void) {
return 0;
}
-static int set_sanitized_path(char **b, const char *path) {
- char *p;
-
- assert(b);
- assert(path);
-
- p = canonicalize_file_name(path);
- if (!p) {
- if (errno != ENOENT)
- return -errno;
-
- p = path_make_absolute_cwd(path);
- if (!p)
- return -ENOMEM;
- }
-
- free(*b);
- *b = path_kill_slashes(p);
- return 0;
-}
-
static int detect_unified_cgroup_hierarchy(void) {
const char *e;
int r;
@@ -399,6 +388,7 @@ static int parse_argv(int argc, char *argv[]) {
};
int c, r;
+ const char *p, *e;
uint64_t plus = 0, minus = 0;
bool mask_all_settings = false, mask_no_settings = false;
@@ -414,29 +404,24 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'D':
- r = set_sanitized_path(&arg_directory, optarg);
+ r = parse_path_argument_and_warn(optarg, false, &arg_directory);
if (r < 0)
- return log_error_errno(r, "Invalid root directory: %m");
-
+ return r;
break;
case ARG_TEMPLATE:
- r = set_sanitized_path(&arg_template, optarg);
+ r = parse_path_argument_and_warn(optarg, false, &arg_template);
if (r < 0)
- return log_error_errno(r, "Invalid template directory: %m");
-
+ return r;
break;
case 'i':
- r = set_sanitized_path(&arg_image, optarg);
+ r = parse_path_argument_and_warn(optarg, false, &arg_image);
if (r < 0)
- return log_error_errno(r, "Invalid image path: %m");
-
+ return r;
break;
case 'x':
@@ -541,15 +526,16 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
- const char *state, *word;
- size_t length;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *t = NULL;
- FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) {
- _cleanup_free_ char *t;
+ r = extract_first_word(&p, &t, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse capability %s.", t);
- t = strndup(word, length);
- if (!t)
- return log_oom();
+ if (r == 0)
+ break;
if (streq(t, "all")) {
if (c == ARG_CAPABILITY)
@@ -924,6 +910,10 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return r;
+ e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE");
+ if (e)
+ arg_container_service_name = e;
+
return 1;
}
@@ -1192,6 +1182,7 @@ static int copy_devnodes(const char *dest) {
static int setup_pts(const char *dest) {
_cleanup_free_ char *options = NULL;
const char *p;
+ int r;
#ifdef HAVE_SELINUX
if (arg_selinux_apifs_context)
@@ -1214,20 +1205,23 @@ static int setup_pts(const char *dest) {
return log_error_errno(errno, "Failed to create /dev/pts: %m");
if (mount("devpts", p, "devpts", MS_NOSUID|MS_NOEXEC, options) < 0)
return log_error_errno(errno, "Failed to mount /dev/pts: %m");
- if (userns_lchown(p, 0, 0) < 0)
- return log_error_errno(errno, "Failed to chown /dev/pts: %m");
+ r = userns_lchown(p, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to chown /dev/pts: %m");
/* Create /dev/ptmx symlink */
p = prefix_roota(dest, "/dev/ptmx");
if (symlink("pts/ptmx", p) < 0)
return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m");
- if (userns_lchown(p, 0, 0) < 0)
- return log_error_errno(errno, "Failed to chown /dev/ptmx: %m");
+ r = userns_lchown(p, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to chown /dev/ptmx: %m");
/* And fix /dev/pts/ptmx ownership */
p = prefix_roota(dest, "/dev/pts/ptmx");
- if (userns_lchown(p, 0, 0) < 0)
- return log_error_errno(errno, "Failed to chown /dev/pts/ptmx: %m");
+ r = userns_lchown(p, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m");
return 0;
}
@@ -1291,7 +1285,7 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- r = send_one_fd(kmsg_socket, fd);
+ r = send_one_fd(kmsg_socket, fd, 0);
safe_close(fd);
if (r < 0)
@@ -1409,7 +1403,7 @@ static int setup_journal(const char *directory) {
r = userns_mkdir(directory, p, 0755, 0, 0);
if (r < 0)
- log_warning_errno(errno, "Failed to create directory %s: %m", q);
+ log_warning_errno(r, "Failed to create directory %s: %m", q);
return 0;
}
@@ -1423,15 +1417,11 @@ static int setup_journal(const char *directory) {
if (errno == ENOTDIR) {
log_error("%s already exists and is neither a symlink nor a directory", p);
return r;
- } else {
- log_error_errno(errno, "Failed to remove %s: %m", p);
- return -errno;
- }
+ } else
+ return log_error_errno(errno, "Failed to remove %s: %m", p);
}
- } else if (r != -ENOENT) {
- log_error_errno(errno, "readlink(%s) failed: %m", p);
- return r;
- }
+ } else if (r != -ENOENT)
+ return log_error_errno(r, "readlink(%s) failed: %m", p);
if (arg_link_journal == LINK_GUEST) {
@@ -1439,15 +1429,13 @@ static int setup_journal(const char *directory) {
if (arg_link_journal_try) {
log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p);
return 0;
- } else {
- log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p);
- return -errno;
- }
+ } else
+ return log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p);
}
r = userns_mkdir(directory, p, 0755, 0, 0);
if (r < 0)
- log_warning_errno(errno, "Failed to create directory %s: %m", q);
+ log_warning_errno(r, "Failed to create directory %s: %m", q);
return 0;
}
@@ -1459,10 +1447,8 @@ static int setup_journal(const char *directory) {
if (arg_link_journal_try) {
log_debug_errno(errno, "Failed to create %s, skipping journal setup: %m", p);
return 0;
- } else {
- log_error_errno(errno, "Failed to create %s: %m", p);
- return r;
- }
+ } else
+ return log_error_errno(errno, "Failed to create %s: %m", p);
}
} else if (access(p, F_OK) < 0)
@@ -1472,10 +1458,8 @@ static int setup_journal(const char *directory) {
log_warning("%s is not empty, proceeding anyway.", q);
r = userns_mkdir(directory, p, 0755, 0, 0);
- if (r < 0) {
- log_error_errno(errno, "Failed to create %s: %m", q);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create %s: %m", q);
if (mount(p, q, NULL, MS_BIND, NULL) < 0)
return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m");
@@ -1616,20 +1600,24 @@ finish:
static int setup_propagate(const char *root) {
const char *p, *q;
+ int r;
(void) mkdir_p("/run/systemd/nspawn/", 0755);
(void) mkdir_p("/run/systemd/nspawn/propagate", 0600);
p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
(void) mkdir_p(p, 0600);
- if (userns_mkdir(root, "/run/systemd", 0755, 0, 0) < 0)
- return log_error_errno(errno, "Failed to create /run/systemd: %m");
+ r = userns_mkdir(root, "/run/systemd", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /run/systemd: %m");
- if (userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0) < 0)
- return log_error_errno(errno, "Failed to create /run/systemd/nspawn: %m");
+ r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m");
- if (userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0) < 0)
- return log_error_errno(errno, "Failed to create /run/systemd/nspawn/incoming: %m");
+ r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m");
q = prefix_roota(root, "/run/systemd/nspawn/incoming");
if (mount(p, q, NULL, MS_BIND, NULL) < 0)
@@ -1679,7 +1667,7 @@ static int setup_image(char **device_path, int *loop_nr) {
}
if (!S_ISREG(st.st_mode)) {
- log_error_errno(errno, "%s is not a regular file or block device: %m", arg_image);
+ log_error("%s is not a regular file or block device.", arg_image);
return -EINVAL;
}
@@ -1771,8 +1759,7 @@ static int dissect_image(
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed to set device on blkid probe: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to set device on blkid probe: %m");
}
blkid_probe_enable_partitions(b, 1);
@@ -1788,8 +1775,7 @@ static int dissect_image(
} else if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error_errno(errno, "Failed to probe: %m");
- return -errno;
+ return log_error_errno(errno, "Failed to probe: %m");
}
(void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
@@ -1912,8 +1898,7 @@ static int dissect_image(
if (!errno)
errno = ENOMEM;
- log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image);
- return -errno;
+ return log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image);
}
qn = udev_device_get_devnum(q);
@@ -2120,8 +2105,7 @@ static int mount_device(const char *what, const char *where, const char *directo
if (!b) {
if (errno == 0)
return log_oom();
- log_error_errno(errno, "Failed to allocate prober for %s: %m", what);
- return -errno;
+ return log_error_errno(errno, "Failed to allocate prober for %s: %m", what);
}
blkid_probe_enable_superblocks(b, 1);
@@ -2135,8 +2119,7 @@ static int mount_device(const char *what, const char *where, const char *directo
} else if (r != 0) {
if (errno == 0)
errno = EIO;
- log_error_errno(errno, "Failed to probe %s: %m", what);
- return -errno;
+ return log_error_errno(errno, "Failed to probe %s: %m", what);
}
errno = 0;
@@ -2282,8 +2265,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
return r;
}
-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;
@@ -2327,9 +2308,9 @@ static int determine_names(void) {
}
if (i->type == IMAGE_RAW)
- r = set_sanitized_path(&arg_image, i->path);
+ r = free_and_strdup(&arg_image, i->path);
else
- r = set_sanitized_path(&arg_directory, i->path);
+ r = free_and_strdup(&arg_directory, i->path);
if (r < 0)
return log_error_errno(r, "Invalid image directory: %m");
@@ -2421,10 +2402,10 @@ static int inner_child(
FDSet *fds) {
_cleanup_free_ char *home = NULL;
- unsigned n_env = 2;
+ unsigned n_env = 1;
const char *envp[] = {
"PATH=" DEFAULT_PATH_SPLIT_USR,
- "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
+ NULL, /* container */
NULL, /* TERM */
NULL, /* HOME */
NULL, /* USER */
@@ -2455,7 +2436,11 @@ static int inner_child(
}
}
- r = mount_all(NULL, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context);
+ if (r < 0)
+ return r;
+
+ r = mount_sysfs(NULL);
if (r < 0)
return r;
@@ -2498,8 +2483,9 @@ static int inner_child(
rtnl_socket = safe_close(rtnl_socket);
}
- if (drop_capabilities() < 0)
- return log_error_errno(errno, "drop_capabilities() failed: %m");
+ r = drop_capabilities();
+ if (r < 0)
+ return log_error_errno(r, "drop_capabilities() failed: %m");
setup_hostname();
@@ -2521,6 +2507,9 @@ static int inner_child(
if (r < 0)
return r;
+ /* LXC sets container=lxc, so follow the scheme here */
+ envp[n_env++] = strjoina("container=", arg_container_service_name);
+
envp[n_env] = strv_find_prefix(environ, "TERM=");
if (envp[n_env])
n_env ++;
@@ -2599,8 +2588,9 @@ static int inner_child(
execle("/bin/sh", "-sh", NULL, env_use);
}
+ r = -errno;
(void) log_open();
- return log_error_errno(errno, "execv() failed: %m");
+ return log_error_errno(r, "execv() failed: %m");
}
static int outer_child(
@@ -2706,7 +2696,7 @@ static int outer_child(
return log_error_errno(r, "Failed to make tree read-only: %m");
}
- r = mount_all(directory, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
if (r < 0)
return r;
@@ -2841,7 +2831,7 @@ static int load_settings(void) {
p = j;
j = NULL;
- /* By default we trust configuration from /etc and /run */
+ /* By default, we trust configuration from /etc and /run */
if (arg_settings_trusted < 0)
arg_settings_trusted = true;
@@ -2871,7 +2861,7 @@ static int load_settings(void) {
if (!f && errno != ENOENT)
return log_error_errno(errno, "Failed to open %s: %m", p);
- /* By default we do not trust configuration from /var/lib/machines */
+ /* By default, we do not trust configuration from /var/lib/machines */
if (arg_settings_trusted < 0)
arg_settings_trusted = false;
}
@@ -2913,11 +2903,17 @@ static int load_settings(void) {
}
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
+ uint64_t plus;
- if (!arg_settings_trusted && settings->capability != 0)
- log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
- else
- arg_retain |= settings->capability;
+ plus = settings->capability;
+ if (settings_private_network(settings))
+ plus |= (1ULL << CAP_NET_ADMIN);
+
+ if (!arg_settings_trusted && plus != 0) {
+ if (settings->capability != 0)
+ log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
+ } else
+ arg_retain |= plus;
arg_retain &= ~settings->drop_capability;
}
@@ -2973,6 +2969,9 @@ static int load_settings(void) {
if (!arg_settings_trusted)
log_warning("Ignoring network settings, file %s is not trusted.", p);
else {
+ arg_network_veth = settings_private_network(settings);
+ arg_private_network = settings_private_network(settings);
+
strv_free(arg_network_interfaces);
arg_network_interfaces = settings->network_interfaces;
settings->network_interfaces = NULL;
@@ -2988,10 +2987,6 @@ static int load_settings(void) {
free(arg_network_bridge);
arg_network_bridge = settings->network_bridge;
settings->network_bridge = NULL;
-
- arg_network_veth = settings->network_veth > 0 || settings->network_bridge;
-
- arg_private_network = true; /* all these settings imply private networking */
}
}
@@ -3097,7 +3092,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
+ r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
if (r < 0) {
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
goto finish;
@@ -3121,7 +3116,7 @@ int main(int argc, char *argv[]) {
}
if (arg_template) {
- r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
+ r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
@@ -3144,10 +3139,9 @@ int main(int argc, char *argv[]) {
} else {
const char *p;
- p = strjoina(arg_directory,
- argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/");
- if (access(p, F_OK) < 0) {
- log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory);
+ p = strjoina(arg_directory, "/usr/");
+ if (laccess(p, F_OK) < 0) {
+ log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory);
r = -EINVAL;
goto finish;
}
@@ -3236,12 +3230,11 @@ int main(int argc, char *argv[]) {
}
for (;;) {
- _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 },
- uid_shift_socket_pair[2] = { -1, -1 };
+ _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = {
- .sa_handler = nop_handler,
+ .sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP,
};
int ifi = 0;
@@ -3338,8 +3331,7 @@ int main(int argc, char *argv[]) {
barrier_set_role(&barrier, BARRIER_PARENT);
- fdset_free(fds);
- fds = NULL;
+ fds = fdset_free(fds);
kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
@@ -3437,7 +3429,8 @@ int main(int argc, char *argv[]) {
arg_custom_mounts, arg_n_custom_mounts,
arg_kill_signal,
arg_property,
- arg_keep_unit);
+ arg_keep_unit,
+ arg_container_service_name);
if (r < 0)
goto finish;
}
@@ -3514,7 +3507,7 @@ int main(int argc, char *argv[]) {
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
- r = pty_forward_new(event, master, true, !interactive, &forward);
+ r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY), &forward);
if (r < 0) {
log_error_errno(r, "Failed to create PTY forwarder: %m");
goto finish;
@@ -3593,7 +3586,7 @@ finish:
if (remove_subvol && arg_directory) {
int k;
- k = btrfs_subvol_remove(arg_directory, true);
+ k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (k < 0)
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
}
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 0dca891447..ee10b105ea 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -19,17 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <nss.h>
-#include <netdb.h>
#include <errno.h>
-#include <string.h>
#include <net/if.h>
+#include <netdb.h>
+#include <nss.h>
#include <stdlib.h>
+#include <string.h>
+#include "alloc-util.h"
+#include "hostname-util.h"
#include "local-addresses.h"
#include "macro.h"
#include "nss-util.h"
-#include "hostname-util.h"
+#include "string-util.h"
#include "util.h"
/* We use 127.0.0.2 as IPv4 address. This has the advantage over
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index 604130ed25..969fa9619e 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -19,18 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <nss.h>
#include <netdb.h>
+#include <nss.h>
#include "sd-bus.h"
#include "sd-login.h"
-#include "macro.h"
-#include "util.h"
-#include "nss-util.h"
-#include "bus-util.h"
+
+#include "alloc-util.h"
#include "bus-common-errors.h"
-#include "in-addr-util.h"
+#include "bus-util.h"
#include "hostname-util.h"
+#include "in-addr-util.h"
+#include "macro.h"
+#include "nss-util.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
NSS_GETPW_PROTOTYPES(mymachines);
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index ef5eb7b4cf..ed59a71e3d 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -19,20 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <nss.h>
-#include <netdb.h>
+#include <dlfcn.h>
#include <errno.h>
-#include <string.h>
+#include <netdb.h>
+#include <nss.h>
#include <stdlib.h>
-#include <dlfcn.h>
+#include <string.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-common-errors.h"
+#include "bus-util.h"
+#include "in-addr-util.h"
#include "macro.h"
#include "nss-util.h"
+#include "string-util.h"
#include "util.h"
-#include "in-addr-util.h"
NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
diff --git a/src/path/path.c b/src/path/path.c
index f7736a4202..0ece72f6fe 100644
--- a/src/path/path.c
+++ b/src/path/path.c
@@ -19,16 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
#include <stdlib.h>
#include "sd-path.h"
-#include "build.h"
+
+#include "alloc-util.h"
+#include "log.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
-#include "log.h"
static const char *arg_suffix = NULL;
@@ -155,9 +157,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_SUFFIX:
arg_suffix = optarg;
diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c
index cf6a239402..dc2911e4e8 100644
--- a/src/quotacheck/quotacheck.c
+++ b/src/quotacheck/quotacheck.c
@@ -19,15 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdbool.h>
#include <errno.h>
-#include <unistd.h>
+#include <stdbool.h>
+#include <stdio.h>
#include <sys/prctl.h>
+#include <unistd.h>
-#include "util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "string-util.h"
+#include "util.h"
+#include "proc-cmdline.h"
static bool arg_skip = false;
static bool arg_force = false;
diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c
index f4778fc16a..d857ade36a 100644
--- a/src/random-seed/random-seed.c
+++ b/src/random-seed/random-seed.c
@@ -19,15 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "log.h"
-#include "util.h"
#include "mkdir.h"
+#include "string-util.h"
+#include "util.h"
#define POOL_SIZE_MIN 512
diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c
index d4e6ba4bf9..6ecadbf3e5 100644
--- a/src/rc-local-generator/rc-local-generator.c
+++ b/src/rc-local-generator/rc-local-generator.c
@@ -24,9 +24,11 @@
#include <stdio.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "log.h"
-#include "util.h"
#include "mkdir.h"
+#include "string-util.h"
+#include "util.h"
#ifndef RC_LOCAL_SCRIPT_PATH_START
#define RC_LOCAL_SCRIPT_PATH_START "/etc/rc.d/rc.local"
@@ -60,8 +62,7 @@ static int add_symlink(const char *service, const char *where) {
if (errno == EEXIST)
return 0;
- log_error_errno(errno, "Failed to create symlink %s: %m", to);
- return -errno;
+ return log_error_errno(errno, "Failed to create symlink %s: %m", to);
}
return 1;
diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c
index f904e48e75..57f99c9ef0 100644
--- a/src/remount-fs/remount-fs.c
+++ b/src/remount-fs/remount-fs.c
@@ -26,12 +26,13 @@
#include <sys/wait.h>
#include <mntent.h>
+#include "exit-status.h"
#include "log.h"
-#include "util.h"
+#include "mount-setup.h"
+#include "mount-util.h"
#include "path-util.h"
#include "signal-util.h"
-#include "mount-setup.h"
-#include "exit-status.h"
+#include "util.h"
/* Goes through /etc/fstab and remounts all API file systems, applying
* options that are in /etc/fstab that systemd might not have
diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c
index d0d61b98ed..166ab470ed 100644
--- a/src/reply-password/reply-password.c
+++ b/src/reply-password/reply-password.c
@@ -19,14 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <string.h>
#include <errno.h>
-#include <sys/un.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "string-util.h"
#include "util.h"
static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
@@ -50,9 +52,10 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
}
int main(int argc, char *argv[]) {
- int fd = -1, r = EXIT_FAILURE;
+ _cleanup_close_ int fd = -1;
char packet[LINE_MAX];
size_t length;
+ int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
@@ -60,14 +63,14 @@ int main(int argc, char *argv[]) {
if (argc != 3) {
log_error("Wrong number of arguments.");
- goto finish;
+ return EXIT_FAILURE;
}
if (streq(argv[1], "1")) {
packet[0] = '+';
if (!fgets(packet+1, sizeof(packet)-1, stdin)) {
- log_error_errno(errno, "Failed to read password: %m");
+ r = log_error_errno(errno, "Failed to read password: %m");
goto finish;
}
@@ -78,22 +81,20 @@ int main(int argc, char *argv[]) {
length = 1;
} else {
log_error("Invalid first argument %s", argv[1]);
+ r = -EINVAL;
goto finish;
}
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
- log_error_errno(errno, "socket() failed: %m");
+ r = log_error_errno(errno, "socket() failed: %m");
goto finish;
}
- if (send_on_socket(fd, argv[2], packet, length) < 0)
- goto finish;
-
- r = EXIT_SUCCESS;
+ r = send_on_socket(fd, argv[2], packet, length);
finish:
- safe_close(fd);
+ memory_erase(packet, sizeof(packet));
- return r;
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 22af092cc0..432e62dd9f 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -23,14 +23,15 @@
#include <getopt.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "af-list.h"
+#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-util.h"
#include "in-addr-util.h"
-#include "af-list.h"
-#include "build.h"
-
-#include "resolved-dns-packet.h"
+#include "parse-util.h"
#include "resolved-def.h"
+#include "resolved-dns-packet.h"
#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
@@ -299,8 +300,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
percent = strchr(s, '%');
if (percent) {
- r = safe_atoi(percent+1, &ifi);
- if (r < 0 || ifi <= 0) {
+ if (parse_ifindex(percent+1, &ifi) < 0) {
ifi = if_nametoindex(percent+1);
if (ifi <= 0)
return -EINVAL;
@@ -507,9 +507,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0; /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case '4':
arg_family = AF_INET;
@@ -522,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) {
case 'i': {
int ifi;
- if (safe_atoi(optarg, &ifi) >= 0 && ifi > 0)
+ if (parse_ifindex(optarg, &ifi) >= 0)
arg_ifindex = ifi;
else {
ifi = if_nametoindex(optarg);
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index bf1b7c8ab4..f0a3b607d4 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-util.h"
-
#include "dns-domain.h"
#include "resolved-bus.h"
#include "resolved-def.h"
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 7af63b0a82..de1bd26174 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -19,13 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "conf-parser.h"
-
+#include "def.h"
+#include "extract-word.h"
+#include "parse-util.h"
#include "resolved-conf.h"
+#include "string-util.h"
int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) {
- const char *word, *state;
- size_t length;
DnsServer *first;
int r;
@@ -34,19 +36,22 @@ int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string)
first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers;
- FOREACH_WORD_QUOTED(word, length, string, state) {
- char buffer[length+1];
- int family;
+ for(;;) {
+ _cleanup_free_ char *word = NULL;
union in_addr_union addr;
bool found = false;
DnsServer *s;
+ int family;
- memcpy(buffer, word, length);
- buffer[length] = 0;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string);
+ if (r == 0)
+ break;
- r = in_addr_from_string_auto(buffer, &family, &addr);
+ r = in_addr_from_string_auto(word, &family, &addr);
if (r < 0) {
- log_warning("Ignoring invalid DNS address '%s'", buffer);
+ log_warning("Ignoring invalid DNS address '%s'", word);
continue;
}
@@ -92,10 +97,10 @@ int config_parse_dnsv(
/* Empty assignment means clear the list */
manager_flush_dns_servers(m, ltype);
else {
- /* Otherwise add to the list */
+ /* Otherwise, add to the list */
r = manager_parse_dns_server(m, ltype, rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
return 0;
}
}
@@ -131,7 +136,7 @@ int config_parse_support(
if (support < 0) {
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse support level '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse support level '%s'. Ignoring.", rvalue);
return 0;
}
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index 89b9b0e1ea..3cf9c68074 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/resolved-dns-answer.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "resolved-dns-answer.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "resolved-dns-answer.h"
+#include "string-util.h"
DnsAnswer *dns_answer_new(unsigned n) {
DnsAnswer *a;
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index ab13636bc1..04f64022e0 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "resolved-dns-cache.h"
#include "resolved-dns-packet.h"
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index bebd1ee4a6..f23b3cf893 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -19,12 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "utf8.h"
-#include "util.h"
-#include "strv.h"
-#include "unaligned.h"
+#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-packet.h"
+#include "string-table.h"
+#include "strv.h"
+#include "unaligned.h"
+#include "utf8.h"
+#include "util.h"
int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
DnsPacket *p;
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index 4b1d18b2ef..f7cb84e2a6 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "hostname-util.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "hostname-util.h"
#include "local-addresses.h"
-
#include "resolved-dns-query.h"
/* How long to wait for the query in total */
diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c
index 1507f22da0..48951221dc 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/resolved-dns-question.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "resolved-dns-question.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "resolved-dns-question.h"
DnsQuestion *dns_question_new(unsigned n) {
DnsQuestion *q;
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index fd2f53f40b..ba2ea686f3 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -21,12 +21,14 @@
#include <math.h>
-#include "strv.h"
-
+#include "alloc-util.h"
#include "dns-domain.h"
-#include "resolved-dns-rr.h"
-#include "resolved-dns-packet.h"
#include "dns-type.h"
+#include "hexdecoct.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-rr.h"
+#include "string-util.h"
+#include "strv.h"
DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
DnsResourceKey *k;
@@ -146,15 +148,14 @@ int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRec
return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
}
-static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
const DnsResourceKey *k = i;
- unsigned long ul;
- ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
- ul = ul * hash_key[0] + ul + k->class;
- ul = ul * hash_key[1] + ul + k->type;
+ assert(k);
- return ul;
+ dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
+ siphash24_compress(&k->class, sizeof(k->class), state);
+ siphash24_compress(&k->type, sizeof(k->type), state);
}
static int dns_resource_key_compare_func(const void *a, const void *b) {
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 9e6f595a1b..b15370b017 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -21,15 +21,17 @@
#include <netinet/tcp.h>
-#include "missing.h"
-#include "strv.h"
-#include "socket-util.h"
#include "af-list.h"
-#include "random-util.h"
-#include "hostname-util.h"
+#include "alloc-util.h"
#include "dns-domain.h"
-#include "resolved-llmnr.h"
+#include "fd-util.h"
+#include "hostname-util.h"
+#include "missing.h"
+#include "random-util.h"
#include "resolved-dns-scope.h"
+#include "resolved-llmnr.h"
+#include "socket-util.h"
+#include "strv.h"
#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
#define MULTICAST_RATELIMIT_BURST 1000
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 2ff5b192df..e803f635ab 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "siphash24.h"
-
+#include "alloc-util.h"
#include "resolved-dns-server.h"
+#include "siphash24.h"
/* After how much time to repeat classic DNS requests */
#define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC)
@@ -137,14 +137,13 @@ void dns_server_packet_lost(DnsServer *s, usec_t usec) {
s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
}
-static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void dns_server_hash_func(const void *p, struct siphash *state) {
const DnsServer *s = p;
- uint64_t u;
- siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key);
- u = u * hash_key[0] + u + s->family;
+ assert(s);
- return u;
+ siphash24_compress(&s->family, sizeof(s->family), state);
+ siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
}
static int dns_server_compare_func(const void *a, const void *b) {
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
index 7f47e7223a..1c501182fb 100644
--- a/src/resolve/resolved-dns-stream.c
+++ b/src/resolve/resolved-dns-stream.c
@@ -21,6 +21,9 @@
#include <netinet/tcp.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "missing.h"
#include "resolved-dns-stream.h"
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index b30473dd7e..6545f6cd8a 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -20,11 +20,13 @@
***/
#include "af-list.h"
-
-#include "resolved-llmnr.h"
-#include "resolved-dns-transaction.h"
-#include "random-util.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "fd-util.h"
+#include "random-util.h"
+#include "resolved-dns-transaction.h"
+#include "resolved-llmnr.h"
+#include "string-table.h"
DnsTransaction* dns_transaction_free(DnsTransaction *t) {
DnsQuery *q;
diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c
index 8a59bd1c3c..48dcf76daa 100644
--- a/src/resolve/resolved-dns-zone.c
+++ b/src/resolve/resolved-dns-zone.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "list.h"
-
-#include "resolved-dns-zone.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "list.h"
#include "resolved-dns-packet.h"
+#include "resolved-dns-zone.h"
+#include "string-util.h"
/* Never allow more than 1K entries */
#define ZONE_MAX 1024
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index b9fd8e3dbc..2892641075 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -22,9 +22,13 @@
#include <net/if.h>
#include "sd-network.h"
-#include "strv.h"
+
+#include "alloc-util.h"
#include "missing.h"
+#include "parse-util.h"
#include "resolved-link.h"
+#include "string-util.h"
+#include "strv.h"
int link_new(Manager *m, Link **ret, int ifindex) {
_cleanup_(link_freep) Link *l = NULL;
diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c
index 8afaf8db6e..5c3a4a00c3 100644
--- a/src/resolve/resolved-llmnr.c
+++ b/src/resolve/resolved-llmnr.c
@@ -22,8 +22,9 @@
#include <resolv.h>
#include <netinet/in.h>
-#include "resolved-manager.h"
+#include "fd-util.h"
#include "resolved-llmnr.h"
+#include "resolved-manager.h"
void manager_llmnr_stop(Manager *m) {
assert(m);
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index de924e3ed9..a588538b52 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -19,26 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <netinet/in.h>
+#include <poll.h>
#include <resolv.h>
#include <sys/ioctl.h>
-#include <poll.h>
-#include <netinet/in.h>
-#include "netlink-util.h"
-#include "network-internal.h"
-#include "socket-util.h"
#include "af-list.h"
-#include "utf8.h"
+#include "alloc-util.h"
+#include "dns-domain.h"
+#include "fd-util.h"
#include "fileio-label.h"
+#include "hostname-util.h"
+#include "io-util.h"
+#include "netlink-util.h"
+#include "network-internal.h"
#include "ordered-set.h"
+#include "parse-util.h"
#include "random-util.h"
-#include "hostname-util.h"
-
-#include "dns-domain.h"
-#include "resolved-conf.h"
#include "resolved-bus.h"
-#include "resolved-manager.h"
+#include "resolved-conf.h"
#include "resolved-llmnr.h"
+#include "resolved-manager.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "utf8.h"
#define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC)
diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c
index 32e61af925..7ba0546f4a 100644
--- a/src/resolve/resolved.c
+++ b/src/resolve/resolved.c
@@ -19,15 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-event.h"
#include "sd-daemon.h"
+#include "sd-event.h"
+
+#include "capability-util.h"
#include "mkdir.h"
-#include "capability.h"
+#include "resolved-conf.h"
+#include "resolved-manager.h"
#include "selinux-util.h"
#include "signal-util.h"
-
-#include "resolved-manager.h"
-#include "resolved-conf.h"
+#include "user-util.h"
int main(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index 904dec6bfc..5c45a3ae6c 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -19,124 +19,410 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "mkdir.h"
-#include "fileio.h"
+#include <linux/rfkill.h>
+#include <poll.h>
+
#include "libudev.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "io-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "string-table.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "util.h"
-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_type = NULL, *escaped_path_id = NULL;
- const char *name, *type, *path_id;
- int r;
+#define EXIT_USEC (5 * USEC_PER_SEC)
- if (argc != 3) {
- log_error("This program requires two arguments.");
- return EXIT_FAILURE;
- }
+static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
+ [RFKILL_TYPE_ALL] = "all",
+ [RFKILL_TYPE_WLAN] = "wlan",
+ [RFKILL_TYPE_BLUETOOTH] = "bluetooth",
+ [RFKILL_TYPE_UWB] = "uwb",
+ [RFKILL_TYPE_WIMAX] = "wimax",
+ [RFKILL_TYPE_WWAN] = "wwan",
+ [RFKILL_TYPE_GPS] = "gps",
+ [RFKILL_TYPE_FM] = "fm",
+ [RFKILL_TYPE_NFC] = "nfc",
+};
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
- umask(0022);
+static int find_device(
+ struct udev *udev,
+ const struct rfkill_event *event,
+ struct udev_device **ret) {
- r = mkdir_p("/var/lib/systemd/rfkill", 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create rfkill directory: %m");
- return EXIT_FAILURE;
- }
+ _cleanup_free_ char *sysname = NULL;
+ struct udev_device *device;
+ const char *name;
- udev = udev_new();
- if (!udev) {
- log_oom();
- return EXIT_FAILURE;
- }
+ assert(udev);
+ assert(event);
+ assert(ret);
- device = udev_device_new_from_subsystem_sysname(udev, "rfkill", argv[2]);
- if (!device) {
- log_debug_errno(errno, "Failed to get rfkill device '%s', ignoring: %m", argv[2]);
- return EXIT_SUCCESS;
- }
+ if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
+ return log_oom();
+
+ device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
+ if (!device)
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
name = udev_device_get_sysattr_value(device, "name");
if (!name) {
- log_error("rfkill device has no name? Ignoring device.");
- return EXIT_SUCCESS;
+ log_debug("Device has no name, ignoring.");
+ udev_device_unref(device);
+ return -ENOENT;
}
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;
+ *ret = device;
+ return 0;
+}
+
+static int wait_for_initialized(
+ struct udev *udev,
+ struct udev_device *device,
+ struct udev_device **ret) {
+
+ _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
+ struct udev_device *d;
+ const char *sysname;
+ int watch_fd, r;
+
+ assert(udev);
+ assert(device);
+ assert(ret);
+
+ if (udev_device_get_is_initialized(device) != 0) {
+ *ret = udev_device_ref(device);
+ return 0;
}
- escaped_type = cescape(type);
- if (!escaped_type) {
- log_oom();
- return EXIT_FAILURE;
+ assert_se(sysname = udev_device_get_sysname(device));
+
+ /* Wait until the device is initialized, so that we can get
+ * access to the ID_PATH property */
+
+ monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!monitor)
+ return log_error_errno(errno, "Failed to acquire monitor: %m");
+
+ r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m");
+
+ r = udev_monitor_enable_receiving(monitor);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable udev receiving: %m");
+
+ watch_fd = udev_monitor_get_fd(monitor);
+ if (watch_fd < 0)
+ return log_error_errno(watch_fd, "Failed to get watch fd: %m");
+
+ /* Check again, maybe things changed */
+ d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
+ if (!d)
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
+
+ if (udev_device_get_is_initialized(d) != 0) {
+ *ret = d;
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_udev_device_unref_ struct udev_device *t = NULL;
+
+ r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
+ if (r == -EINTR)
+ continue;
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch udev monitor: %m");
+
+ t = udev_monitor_receive_device(monitor);
+ if (!t)
+ continue;
+
+ if (streq_ptr(udev_device_get_sysname(device), sysname)) {
+ *ret = udev_device_ref(t);
+ return 0;
+ }
}
+}
+
+static int determine_state_file(
+ struct udev *udev,
+ const struct rfkill_event *event,
+ struct udev_device *d,
+ char **ret) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ const char *path_id, *type;
+ char *state_file;
+ int r;
+
+ assert(event);
+ assert(d);
+ assert(ret);
+
+ r = wait_for_initialized(udev, d, &device);
+ if (r < 0)
+ return r;
+
+ assert_se(type = rfkill_type_to_string(event->type));
path_id = udev_device_get_property_value(device, "ID_PATH");
if (path_id) {
+ _cleanup_free_ char *escaped_path_id = NULL;
+
escaped_path_id = cescape(path_id);
- if (!escaped_path_id) {
- log_oom();
- return EXIT_FAILURE;
- }
+ if (!escaped_path_id)
+ return log_oom();
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_type, NULL);
+ state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type, NULL);
} else
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_type, NULL);
+ state_file = strjoin("/var/lib/systemd/rfkill/", type, NULL);
+
+ if (!state_file)
+ return log_oom();
+
+ *ret = state_file;
+ return 0;
+}
+
+static int load_state(
+ int rfkill_fd,
+ struct udev *udev,
+ const struct rfkill_event *event) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ _cleanup_free_ char *state_file = NULL, *value = NULL;
+ struct rfkill_event we;
+ ssize_t l;
+ int b, r;
- if (!saved) {
- log_oom();
+ assert(rfkill_fd >= 0);
+ assert(udev);
+ assert(event);
+
+ if (shall_restore_state() == 0)
+ return 0;
+
+ r = find_device(udev, event, &device);
+ if (r < 0)
+ return r;
+
+ r = determine_state_file(udev, event, device, &state_file);
+ if (r < 0)
+ return r;
+
+ r = read_one_line_file(state_file, &value);
+ if (r == -ENOENT) {
+ /* No state file? Then save the current state */
+
+ r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write state file %s: %m", state_file);
+
+ log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read state file %s: %m", state_file);
+
+ b = parse_boolean(value);
+ if (b < 0)
+ return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
+
+ we = (struct rfkill_event) {
+ .op = RFKILL_OP_CHANGE,
+ .idx = event->idx,
+ .soft = b,
+ };
+
+ l = write(rfkill_fd, &we, sizeof(we));
+ if (l < 0)
+ return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx);
+ if (l != sizeof(we)) {
+ log_error("Couldn't write rfkill event structure, too short.");
+ return -EIO;
+ }
+
+ log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
+ return 0;
+}
+
+static int save_state(
+ int rfkill_fd,
+ struct udev *udev,
+ const struct rfkill_event *event) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ _cleanup_free_ char *state_file = NULL;
+ int r;
+
+ assert(rfkill_fd >= 0);
+ assert(udev);
+ assert(event);
+
+ r = find_device(udev, event, &device);
+ if (r < 0)
+ return r;
+
+ r = determine_state_file(udev, event, device, &state_file);
+ if (r < 0)
+ return r;
+
+ r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write state file %s: %m", state_file);
+
+ log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_close_ int rfkill_fd = -1;
+ bool ready = false;
+ int r, n;
+
+ if (argc > 1) {
+ log_error("This program requires no arguments.");
return EXIT_FAILURE;
}
- if (streq(argv[1], "load")) {
- _cleanup_free_ char *value = NULL;
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
- if (!shall_restore_state())
- return EXIT_SUCCESS;
+ umask(0022);
- r = read_one_line_file(saved, &value);
- if (r == -ENOENT)
- return EXIT_SUCCESS;
- if (r < 0) {
- log_error_errno(r, "Failed to read %s: %m", saved);
- return EXIT_FAILURE;
+ udev = udev_new();
+ if (!udev) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = mkdir_p("/var/lib/systemd/rfkill", 0755);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create rfkill directory: %m");
+ goto finish;
+ }
+
+ n = sd_listen_fds(false);
+ if (n < 0) {
+ r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
+ goto finish;
+ }
+ if (n > 1) {
+ log_error("Got too many file descriptors.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ if (n == 0) {
+ rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+ if (rfkill_fd < 0) {
+ if (errno == ENOENT) {
+ log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
+ r = 0;
+ goto finish;
+ }
+
+ r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
+ goto finish;
}
+ } else {
+ rfkill_fd = SD_LISTEN_FDS_START;
- r = udev_device_set_sysattr_value(device, "soft", value);
+ r = fd_nonblock(rfkill_fd, 1);
if (r < 0) {
- log_debug_errno(r, "Failed to write 'soft' attribute on rfkill device, ignoring: %m");
- return EXIT_SUCCESS;
+ log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
+ goto finish;
}
+ }
+
+ for (;;) {
+ struct rfkill_event event;
+ const char *type;
+ ssize_t l;
- } else if (streq(argv[1], "save")) {
- const char *value;
+ l = read(rfkill_fd, &event, sizeof(event));
+ if (l < 0) {
+ if (errno == EAGAIN) {
- value = udev_device_get_sysattr_value(device, "soft");
- if (!value) {
- log_debug_errno(r, "Failed to read system attribute, ignoring device: %m");
- return EXIT_SUCCESS;
+ if (!ready) {
+ /* Notify manager that we are
+ * now finished with
+ * processing whatever was
+ * queued */
+ (void) sd_notify(false, "READY=1");
+ ready = true;
+ }
+
+ /* Hang around for a bit, maybe there's more coming */
+
+ r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
+ if (r == -EINTR)
+ continue;
+ if (r < 0) {
+ log_error_errno(r, "Failed to poll() on device: %m");
+ goto finish;
+ }
+ if (r > 0)
+ continue;
+
+ log_debug("All events read and idle, exiting.");
+ break;
+ }
+
+ log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
}
- r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE);
- if (r < 0) {
- log_error_errno(r, "Failed to write %s: %m", saved);
- return EXIT_FAILURE;
+ if (l != RFKILL_EVENT_SIZE_V1) {
+ log_error("Read event structure of invalid size.");
+ r = -EIO;
+ goto finish;
}
- } else {
- log_error("Unknown verb %s.", argv[1]);
- return EXIT_FAILURE;
+ type = rfkill_type_to_string(event.type);
+ if (!type) {
+ log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
+ continue;
+ }
+
+ switch (event.op) {
+
+ case RFKILL_OP_ADD:
+ log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type);
+ (void) load_state(rfkill_fd, udev, &event);
+ break;
+
+ case RFKILL_OP_DEL:
+ log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
+ break;
+
+ case RFKILL_OP_CHANGE:
+ log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type);
+ (void) save_state(rfkill_fd, udev, &event);
+ break;
+
+ default:
+ log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
+ break;
+ }
}
- return EXIT_SUCCESS;
+ r = 0;
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/run/run.c b/src/run/run.c
index 657c6fcaf1..38a482bb11 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -19,24 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <getopt.h>
+#include <stdio.h>
#include "sd-bus.h"
#include "sd-event.h"
+
+#include "alloc-util.h"
+#include "bus-error.h"
#include "bus-util.h"
-#include "event-util.h"
-#include "strv.h"
-#include "build.h"
-#include "unit-name.h"
+#include "calendarspec.h"
#include "env-util.h"
+#include "event-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "path-util.h"
-#include "bus-error.h"
-#include "calendarspec.h"
#include "ptyfwd.h"
-#include "formats-util.h"
#include "signal-util.h"
#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
+#include "user-util.h"
+#include "parse-util.h"
static bool arg_ask_password = true;
static bool arg_scope = false;
@@ -62,7 +67,7 @@ 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 const char *arg_on_calendar = NULL;
static char **arg_timer_property = NULL;
static bool arg_quiet = false;
@@ -181,7 +186,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int r, c;
- CalendarSpec *spec = NULL;
assert(argc >= 0);
assert(argv);
@@ -199,9 +203,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USER:
arg_user = true;
@@ -337,16 +339,19 @@ static int parse_argv(int argc, char *argv[]) {
break;
- case ARG_ON_CALENDAR:
+ case ARG_ON_CALENDAR: {
+ CalendarSpec *spec = NULL;
r = calendar_spec_from_string(optarg, &spec);
if (r < 0) {
log_error("Invalid calendar spec: %s", optarg);
return r;
}
- free(spec);
+
+ calendar_spec_free(spec);
arg_on_calendar = optarg;
break;
+ }
case ARG_TIMER_PROPERTY:
@@ -391,6 +396,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) {
+ log_error("--pty is only supported when connecting to the local system or containers.");
+ return -EINVAL;
+ }
+
if (arg_scope && with_timer()) {
log_error("Timer options are not supported in --scope mode.");
return -EINVAL;
@@ -709,9 +719,9 @@ static int start_transient_service(
_cleanup_bus_unref_ sd_bus *system_bus = NULL;
const char *s;
- r = sd_bus_open_system(&system_bus);
+ r = sd_bus_default_system(&system_bus);
if (r < 0)
- log_error_errno(r, "Failed to connect to system bus: %m");
+ return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_call_method(system_bus,
"org.freedesktop.machine1",
@@ -796,10 +806,8 @@ static int start_transient_service(
polkit_agent_open_if_enabled();
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r));
if (w) {
const char *object;
@@ -830,7 +838,7 @@ static int start_transient_service(
if (!arg_quiet)
log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service);
- r = pty_forward_new(event, master, false, false, &forward);
+ r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -1149,14 +1157,15 @@ int main(int argc, char* argv[]) {
if (r <= 0)
goto finish;
- if (argc > optind) {
- r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command);
+ if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) {
+ /* Patch in an absolute path */
+
+ r = find_binary(argv[optind], &command);
if (r < 0) {
- log_error_errno(r, "Failed to find executable %s%s: %m",
- argv[optind],
- arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system");
+ log_error_errno(r, "Failed to find executable %s: %m", argv[optind]);
goto finish;
}
+
argv[optind] = command;
}
@@ -1176,7 +1185,7 @@ int main(int argc, char* argv[]) {
arg_description = description;
}
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
+ r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c
index bd8c988751..79f5a60579 100644
--- a/src/shared/acl-util.c
+++ b/src/shared/acl-util.c
@@ -22,9 +22,12 @@
#include <errno.h>
#include <stdbool.h>
+#include "alloc-util.h"
#include "acl-util.h"
-#include "util.h"
+#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
+#include "util.h"
int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
acl_entry_t i;
diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c
index 64e50401b9..8e36067f74 100644
--- a/src/shared/acpi-fpdt.c
+++ b/src/shared/acpi-fpdt.c
@@ -19,16 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
+#include <fcntl.h>
#include <stdint.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <util.h>
-#include <fileio.h>
-#include <time-util.h>
-#include <acpi-fpdt.h>
+#include "alloc-util.h"
+#include "acpi-fpdt.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "time-util.h"
+#include "util.h"
struct acpi_table_header {
char signature[4];
diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c
index c2bbd330bd..f6ac43adfe 100644
--- a/src/shared/apparmor-util.c
+++ b/src/shared/apparmor-util.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-#include "util.h"
-#include "fileio.h"
+#include "alloc-util.h"
#include "apparmor-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "util.h"
bool mac_apparmor_use(void) {
static int cached_use = -1;
diff --git a/src/shared/architecture.c b/src/shared/architecture.c
index 8e72e7a36a..e2efa4272b 100644
--- a/src/shared/architecture.c
+++ b/src/shared/architecture.c
@@ -21,6 +21,8 @@
#include <sys/utsname.h>
+#include "string-table.h"
+#include "string-util.h"
#include "architecture.h"
int uname_architecture(void) {
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index f5bbf65a90..61d067cad7 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -78,9 +78,11 @@ int uname_architecture(void);
#if defined(__x86_64__)
# define native_architecture() ARCHITECTURE_X86_64
# define LIB_ARCH_TUPLE "x86_64-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__i386__)
# define native_architecture() ARCHITECTURE_X86
# define LIB_ARCH_TUPLE "i386-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__powerpc64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC64
@@ -89,6 +91,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC64_LE
# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__powerpc__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC
@@ -97,15 +100,18 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC_LE
# error "Missing LIB_ARCH_TUPLE for PPCLE"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__ia64__)
# define native_architecture() ARCHITECTURE_IA64
# define LIB_ARCH_TUPLE "ia64-linux-gnu"
#elif defined(__hppa64__)
# define native_architecture() ARCHITECTURE_PARISC64
# error "Missing LIB_ARCH_TUPLE for HPPA64"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__hppa__)
# define native_architecture() ARCHITECTURE_PARISC
# define LIB_ARCH_TUPLE "hppa‑linux‑gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__s390x__)
# define native_architecture() ARCHITECTURE_S390X
# define LIB_ARCH_TUPLE "s390x-linux-gnu"
@@ -115,9 +121,11 @@ int uname_architecture(void);
#elif defined(__sparc64__)
# define native_architecture() ARCHITECTURE_SPARC64
# define LIB_ARCH_TUPLE "sparc64-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__sparc__)
# define native_architecture() ARCHITECTURE_SPARC
# define LIB_ARCH_TUPLE "sparc-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__mips64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS64
@@ -126,6 +134,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS64_LE
# error "Missing LIB_ARCH_TUPLE for MIPS64_LE"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__mips__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS
@@ -134,6 +143,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS_LE
# define LIB_ARCH_TUPLE "mipsel-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__alpha__)
# define native_architecture() ARCHITECTURE_ALPHA
# define LIB_ARCH_TUPLE "alpha-linux-gnu"
@@ -169,6 +179,7 @@ int uname_architecture(void);
# define LIB_ARCH_TUPLE "arm-linux-gnu"
# endif
# endif
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__sh64__)
# define native_architecture() ARCHITECTURE_SH64
# error "Missing LIB_ARCH_TUPLE for SH64"
@@ -188,5 +199,10 @@ int uname_architecture(void);
# error "Please register your architecture here!"
#endif
+#ifndef PROC_CPUINFO_MODEL
+#warning "PROC_CPUINFO_MODEL not defined for your architecture"
+#define PROC_CPUINFO_MODEL "model name"
+#endif
+
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 b02cdf9a17..fbe2b6fecb 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -18,27 +18,167 @@
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 <termios.h>
-#include <unistd.h>
-#include <poll.h>
-#include <sys/inotify.h>
+
#include <errno.h>
#include <fcntl.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/un.h>
+#include <poll.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/inotify.h>
#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+#include <unistd.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "io-util.h"
+#include "missing.h"
#include "mkdir.h"
-#include "strv.h"
#include "random-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
-#include "ask-password-api.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "umask-util.h"
+#include "util.h"
+
+#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
+
+static int lookup_key(const char *keyname, key_serial_t *ret) {
+ key_serial_t serial;
+
+ assert(keyname);
+ assert(ret);
+
+ serial = request_key("user", keyname, NULL, 0);
+ if (serial == -1)
+ return -errno;
+
+ *ret = serial;
+ return 0;
+}
+
+static int retrieve_key(key_serial_t serial, char ***ret) {
+ _cleanup_free_ char *p = NULL;
+ long m = 100, n;
+ char **l;
+
+ assert(ret);
+
+ for (;;) {
+ p = new(char, m);
+ if (!p)
+ return -ENOMEM;
+
+ n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
+ if (n < 0)
+ return -errno;
+
+ if (n < m)
+ break;
+
+ memory_erase(p, n);
+ free(p);
+ m *= 2;
+ }
+
+ l = strv_parse_nulstr(p, n);
+ if (!l)
+ return -ENOMEM;
+
+ memory_erase(p, n);
+
+ *ret = l;
+ return 0;
+}
+
+static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ _cleanup_strv_free_erase_ char **l = NULL;
+ _cleanup_free_ char *p = NULL;
+ key_serial_t serial;
+ size_t n;
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ if (!(flags & ASK_PASSWORD_PUSH_CACHE))
+ return 0;
+
+ r = lookup_key(keyname, &serial);
+ if (r >= 0) {
+ r = retrieve_key(serial, &l);
+ if (r < 0)
+ return r;
+ } else if (r != -ENOKEY)
+ return r;
+
+ r = strv_extend_strv(&l, passwords, true);
+ if (r <= 0)
+ return r;
+
+ r = strv_make_nulstr(l, &p, &n);
+ if (r < 0)
+ return r;
+
+ /* Truncate trailing NUL */
+ assert(n > 0);
+ assert(p[n-1] == 0);
+
+ serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING);
+ memory_erase(p, n);
+ if (serial == -1)
+ return -errno;
+
+ if (keyctl(KEYCTL_SET_TIMEOUT,
+ (unsigned long) serial,
+ (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
+ log_debug_errno(errno, "Failed to adjust timeout: %m");
+
+ log_debug("Added key to keyring as %" PRIi32 ".", serial);
+
+ return 1;
+}
+
+static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ r = add_to_keyring(keyname, flags, passwords);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add password to keyring: %m");
+
+ return 0;
+}
+
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
+
+ key_serial_t serial;
+ int r;
+
+ assert(keyname);
+ assert(ret);
+
+ if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
+ return -EUNATCH;
+
+ r = lookup_key(keyname, &serial);
+ if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
+ return -ENOKEY;
+ if (r < 0)
+ return r;
+
+ return retrieve_key(serial, ret);
+}
static void backspace_chars(int ttyfd, size_t p) {
@@ -54,10 +194,11 @@ static void backspace_chars(int ttyfd, size_t p) {
int ask_password_tty(
const char *message,
+ const char *keyname,
usec_t until,
- bool echo,
+ AskPasswordFlags flags,
const char *flag_file,
- char **_passphrase) {
+ char **ret) {
struct termios old_termios, new_termios;
char passphrase[LINE_MAX], *x;
@@ -66,15 +207,19 @@ int ask_password_tty(
_cleanup_close_ int ttyfd = -1, notify = -1;
struct pollfd pollfd[2];
bool reset_tty = false;
- bool silent_mode = false;
bool dirty = false;
enum {
POLL_TTY,
POLL_INOTIFY
};
- assert(message);
- assert(_passphrase);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_TTY)
+ return -EUNATCH;
+
+ if (!message)
+ message = "Password:";
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -97,10 +242,10 @@ int ask_password_tty(
goto finish;
}
- loop_write(ttyfd, ANSI_HIGHLIGHT, sizeof(ANSI_HIGHLIGHT)-1, false);
+ loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false);
loop_write(ttyfd, message, strlen(message), false);
loop_write(ttyfd, " ", 1, false);
- loop_write(ttyfd, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1, false);
+ loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false);
new_termios = old_termios;
new_termios.c_lflag &= ~(ICANON|ECHO);
@@ -145,7 +290,7 @@ int ask_password_tty(
goto finish;
}
- k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+ k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (k < 0) {
if (errno == EINTR)
continue;
@@ -157,7 +302,7 @@ int ask_password_tty(
goto finish;
}
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+ if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
if (pollfd[POLL_TTY].revents == 0)
@@ -178,7 +323,7 @@ int ask_password_tty(
break;
else if (c == 21) { /* C-u */
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, p);
p = 0;
@@ -186,28 +331,28 @@ int ask_password_tty(
if (p > 0) {
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, 1);
p--;
- } else if (!dirty && !silent_mode) {
+ } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* There are two ways to enter silent
* mode. Either by pressing backspace
- * as first key (and only as first key),
- * or ... */
+ * as first key (and only as first
+ * key), or ... */
if (ttyfd >= 0)
loop_write(ttyfd, "(no echo) ", 10, false);
} else if (ttyfd >= 0)
loop_write(ttyfd, "\a", 1, false);
- } else if (c == '\t' && !silent_mode) {
+ } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
backspace_chars(ttyfd, p);
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* ... or by pressing TAB at any time. */
@@ -221,20 +366,26 @@ int ask_password_tty(
passphrase[p++] = c;
- if (!silent_mode && ttyfd >= 0)
- loop_write(ttyfd, echo ? &c : "*", 1, false);
+ if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0)
+ loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
dirty = true;
}
+
+ c = 'x';
}
x = strndup(passphrase, p);
+ memory_erase(passphrase, p);
if (!x) {
r = -ENOMEM;
goto finish;
}
- *_passphrase = x;
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x));
+
+ *ret = x;
r = 0;
finish:
@@ -247,52 +398,38 @@ finish:
}
static int create_socket(char **name) {
- int fd;
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
- int one = 1;
- int r = 0;
+ _cleanup_close_ int fd = -1;
+ static const int one = 1;
char *c;
+ int r;
assert(name);
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
- return log_error_errno(errno, "socket() failed: %m");
+ return -errno;
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- }
-
- if (r < 0) {
- r = -errno;
- log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- goto fail;
+ if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ return -errno;
}
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
- r = -errno;
- log_error_errno(errno, "SO_PASSCRED failed: %m");
- goto fail;
- }
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+ return -errno;
c = strdup(sa.un.sun_path);
- if (!c) {
- r = log_oom();
- goto fail;
- }
+ if (!c)
+ return -ENOMEM;
*name = c;
- return fd;
-fail:
- safe_close(fd);
+ r = fd;
+ fd = -1;
return r;
}
@@ -301,10 +438,10 @@ int ask_password_agent(
const char *message,
const char *icon,
const char *id,
+ const char *keyname,
usec_t until,
- bool echo,
- bool accept_cached,
- char ***_passphrases) {
+ AskPasswordFlags flags,
+ char ***ret) {
enum {
FD_SOCKET,
@@ -312,35 +449,38 @@ int ask_password_agent(
_FD_MAX
};
+ _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
char final[sizeof(temp)] = "";
- _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *socket_name = NULL;
- _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
- sigset_t mask, oldmask;
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
struct pollfd pollfd[_FD_MAX];
+ sigset_t mask, oldmask;
int r;
- assert(_passphrases);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_AGENT)
+ return -EUNATCH;
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
- mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_p_label("/run/systemd/ask-password", 0755);
fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- r = log_error_errno(errno,
- "Failed to create password file: %m");
+ r = fd;
goto finish;
}
- fchmod(fd, 0644);
+ (void) fchmod(fd, 0644);
f = fdopen(fd, "w");
if (!f) {
- r = log_error_errno(errno, "Failed to allocate FILE: %m");
+ r = -errno;
goto finish;
}
@@ -348,7 +488,7 @@ int ask_password_agent(
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0) {
- r = log_error_errno(errno, "signalfd(): %m");
+ r = -errno;
goto finish;
}
@@ -367,8 +507,8 @@ int ask_password_agent(
"NotAfter="USEC_FMT"\n",
getpid(),
socket_name,
- accept_cached ? 1 : 0,
- echo ? 1 : 0,
+ (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
+ (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
until);
if (message)
@@ -381,10 +521,8 @@ int ask_password_agent(
fprintf(f, "Id=%s\n", id);
r = fflush_and_check(f);
- if (r < 0) {
- log_error_errno(r, "Failed to write query file: %m");
+ if (r < 0)
goto finish;
- }
memcpy(final, temp, sizeof(temp));
@@ -393,7 +531,7 @@ int ask_password_agent(
final[sizeof(final)-9] = 'k';
if (rename(temp, final) < 0) {
- r = log_error_errno(errno, "Failed to rename query file: %m");
+ r = -errno;
goto finish;
}
@@ -419,7 +557,6 @@ int ask_password_agent(
t = now(CLOCK_MONOTONIC);
if (until > 0 && until <= t) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -429,12 +566,11 @@ int ask_password_agent(
if (errno == EINTR)
continue;
- r = log_error_errno(errno, "poll() failed: %m");
+ r = -errno;
goto finish;
}
if (k <= 0) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -445,7 +581,6 @@ int ask_password_agent(
}
if (pollfd[FD_SOCKET].revents != POLLIN) {
- log_error("Unexpected poll() event.");
r = -EIO;
goto finish;
}
@@ -467,14 +602,14 @@ int ask_password_agent(
errno == EINTR)
continue;
- r = log_error_errno(errno, "recvmsg() failed: %m");
+ r = -errno;
goto finish;
}
cmsg_close_all(&msghdr);
if (n <= 0) {
- log_error("Message too short");
+ log_debug("Message too short");
continue;
}
@@ -482,84 +617,104 @@ int ask_password_agent(
control.cmsghdr.cmsg_level != SOL_SOCKET ||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received message without credentials. Ignoring.");
+ log_debug("Received message without credentials. Ignoring.");
continue;
}
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
if (ucred->uid != 0) {
- log_warning("Got request from unprivileged user. Ignoring.");
+ log_debug("Got request from unprivileged user. Ignoring.");
continue;
}
if (passphrase[0] == '+') {
- char **l;
-
+ /* An empty message refers to the empty password */
if (n == 1)
l = strv_new("", NULL);
else
l = strv_parse_nulstr(passphrase+1, n-1);
- /* An empty message refers to the empty password */
-
+ memory_erase(passphrase, n);
if (!l) {
r = -ENOMEM;
goto finish;
}
if (strv_length(l) <= 0) {
- strv_free(l);
- log_error("Invalid packet");
+ l = strv_free(l);
+ log_debug("Invalid packet");
continue;
}
- *_passphrases = l;
+ break;
+ }
- } else if (passphrase[0] == '-') {
+ if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
- } else {
- log_error("Invalid packet");
- continue;
}
- break;
+ log_debug("Invalid packet");
}
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, l);
+
+ *ret = l;
+ l = NULL;
r = 0;
finish:
if (socket_name)
- unlink(socket_name);
+ (void) unlink(socket_name);
- unlink(temp);
+ (void) unlink(temp);
if (final[0])
- unlink(final);
+ (void) unlink(final);
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
-
return r;
}
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases) {
- assert(message);
- assert(_passphrases);
+int ask_password_auto(
+ const char *message,
+ const char *icon,
+ const char *id,
+ const char *keyname,
+ usec_t until,
+ AskPasswordFlags flags,
+ char ***ret) {
- if (isatty(STDIN_FILENO)) {
- int r;
- char *s = NULL, **l = NULL;
+ int r;
- r = ask_password_tty(message, until, false, NULL, &s);
- if (r < 0)
+ assert(ret);
+
+ if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
+ r = ask_password_keyring(keyname, flags, ret);
+ if (r != -ENOKEY)
return r;
+ }
- r = strv_consume(&l, s);
+ if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
+ char *s = NULL, **l = NULL;
+
+ r = ask_password_tty(message, keyname, until, flags, NULL, &s);
if (r < 0)
return r;
- *_passphrases = l;
- return r;
- } else
- return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases);
+ r = strv_push(&l, s);
+ if (r < 0) {
+ string_erase(s);
+ free(s);
+ return -ENOMEM;
+ }
+
+ *ret = l;
+ return 0;
+ }
+
+ if (!(flags & ASK_PASSWORD_NO_AGENT))
+ return ask_password_agent(message, icon, id, keyname, until, flags, ret);
+
+ return -EUNATCH;
}
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 0954e072be..913cad9f8a 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -21,11 +21,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase);
-
-int ask_password_agent(const char *message, const char *icon, const char *id,
- usec_t until, bool echo, bool accept_cached, char ***_passphrases);
-
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases);
+#include <stdbool.h>
+
+#include "time-util.h"
+
+typedef enum AskPasswordFlags {
+ ASK_PASSWORD_ACCEPT_CACHED = 1,
+ ASK_PASSWORD_PUSH_CACHE = 2,
+ ASK_PASSWORD_ECHO = 4, /* show the password literally while reading, instead of "*" */
+ ASK_PASSWORD_SILENT = 8, /* do no show any password at all while reading */
+ ASK_PASSWORD_NO_TTY = 16,
+ ASK_PASSWORD_NO_AGENT = 32,
+} AskPasswordFlags;
+
+int ask_password_tty(const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret);
+int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret);
+int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index ab6fc171b0..e605490c32 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -20,13 +20,18 @@
***/
#include <errno.h>
-#include <sys/stat.h>
#include <stdlib.h>
+#include <sys/stat.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "base-filesystem.h"
+#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "string-util.h"
+#include "umask-util.h"
+#include "user-util.h"
#include "util.h"
typedef struct BaseFilesystem {
@@ -34,12 +39,13 @@ typedef struct BaseFilesystem {
mode_t mode;
const char *target;
const char *exists;
+ bool ignore_failure;
} BaseFilesystem;
static const BaseFilesystem table[] = {
{ "bin", 0, "usr/bin\0", NULL },
{ "lib", 0, "usr/lib\0", NULL },
- { "root", 0755, NULL, NULL },
+ { "root", 0755, NULL, NULL, true },
{ "sbin", 0, "usr/sbin\0", NULL },
{ "usr", 0755, NULL, NULL },
{ "var", 0755, NULL, NULL },
@@ -104,8 +110,13 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
RUN_WITH_UMASK(0000)
r = mkdirat(fd, table[i].dir, table[i].mode);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir);
+ if (r < 0 && errno != EEXIST) {
+ log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to create directory at %s/%s: %m", root, table[i].dir);
+
+ if (!table[i].ignore_failure)
+ return -errno;
+ }
if (uid != UID_INVALID || gid != UID_INVALID) {
if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 16b17c2c82..a13991a960 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -21,27 +21,39 @@
#include <sys/socket.h>
+#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-event.h"
-#include "sd-bus.h"
+#include "alloc-util.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-label.h"
#include "bus-message.h"
+#include "bus-util.h"
#include "cgroup-util.h"
#include "def.h"
+#include "env-util.h"
+#include "escape.h"
+#include "fd-util.h"
#include "macro.h"
#include "missing.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "rlimit-util.h"
#include "set.h"
#include "signal-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "syslog-util.h"
#include "unit-name.h"
+#include "user-util.h"
+#include "utf8.h"
#include "util.h"
-#include "bus-util.h"
-
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
@@ -574,14 +586,14 @@ int bus_check_peercred(sd_bus *c) {
return 1;
}
-int bus_open_system_systemd(sd_bus **_bus) {
+int bus_connect_system_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
assert(_bus);
if (geteuid() != 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
/* If we are root and kdbus is not available, then let's talk
* directly to the system instance, instead of going via the
@@ -616,7 +628,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -628,7 +640,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
return 0;
}
-int bus_open_user_systemd(sd_bus **_bus) {
+int bus_connect_user_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
_cleanup_free_ char *ee = NULL;
const char *e;
@@ -658,7 +670,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
e = secure_getenv("XDG_RUNTIME_DIR");
if (!e)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
ee = bus_address_escape(e);
if (!ee)
@@ -674,7 +686,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -1209,7 +1221,7 @@ int bus_map_all_properties(
return bus_message_map_all_properties(m, map, userdata);
}
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1244,7 +1256,7 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b
return r;
}
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1258,9 +1270,9 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us
case BUS_TRANSPORT_LOCAL:
if (user)
- r = bus_open_user_systemd(bus);
+ r = bus_connect_user_systemd(bus);
else
- r = bus_open_system_systemd(bus);
+ r = bus_connect_system_systemd(bus);
break;
@@ -1416,6 +1428,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
return 0;
+ } else if (streq(field, "EnvironmentFile")) {
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "v", "a(sb)", 1,
+ eq[0] == '-' ? eq + 1 : eq,
+ eq[0] == '-');
+ if (r < 0)
+ return r;
+ return 0;
}
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
@@ -1426,7 +1449,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges")) {
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+ "SyslogLevelPrefix", "Delegate")) {
r = parse_boolean(eq);
if (r < 0) {
@@ -1493,10 +1517,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
"StandardInput", "StandardOutput", "StandardError",
"Description", "Slice", "Type", "WorkingDirectory",
- "RootDirectory"))
+ "RootDirectory", "SyslogIdentifier", "ProtectSystem",
+ "ProtectHome"))
r = sd_bus_message_append(m, "v", "s", eq);
- else if (streq(field, "DeviceAllow")) {
+ else if (streq(field, "SyslogLevel")) {
+ int level;
+
+ level = log_level_from_string(eq);
+ if (level < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", level);
+
+ } else if (streq(field, "SyslogFacility")) {
+ int facility;
+
+ facility = log_facility_unshifted_from_string(eq);
+ if (facility < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", facility);
+
+ } else if (streq(field, "DeviceAllow")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(ss)", 0);
@@ -1608,8 +1655,44 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", i);
} else if (streq(field, "Environment")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
+ if (r < 0) {
+ log_error("Failed to parse Environment value %s", eq);
+ return -EINVAL;
+ }
+ if (r == 0)
+ break;
- r = sd_bus_message_append(m, "v", "as", 1, eq);
+ if (!env_assignment_is_valid(word)) {
+ log_error("Invalid environment assignment: %s", eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
} else if (streq(field, "KillSignal")) {
int sig;
@@ -1632,6 +1715,113 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
}
r = sd_bus_message_append(m, "v", "t", u);
+ } else if (streq(field, "TimerSlackNSec")) {
+ nsec_t n;
+
+ r = parse_nsec(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
+ } else if (streq(field, "OOMScoreAdjust")) {
+ int oa;
+
+ r = safe_atoi(eq, &oa);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ if (!oom_score_adjust_is_valid(oa)) {
+ log_error("OOM score adjust value out of range");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", oa);
+ } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ int offset;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+ if (r == 0)
+ break;
+
+ if (!utf8_is_valid(word)) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ offset = word[0] == '-';
+ if (!path_is_absolute(word + offset)) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ path_kill_slashes(word + offset);
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (streq(field, "RuntimeDirectory")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
} else {
log_error("Unknown assignment %s.", assignment);
@@ -2137,3 +2327,42 @@ bool is_kdbus_available(void) {
return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
}
+
+int bus_property_get_rlimit(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ struct rlimit *rl;
+ uint64_t u;
+ rlim_t x;
+
+ assert(bus);
+ assert(reply);
+ assert(userdata);
+
+ rl = *(struct rlimit**) userdata;
+ if (rl)
+ x = rl->rlim_max;
+ else {
+ struct rlimit buf = {};
+ int z;
+
+ z = rlimit_from_string(strstr(property, "Limit"));
+ assert(z >= 0);
+
+ getrlimit(z, &buf);
+ x = buf.rlim_max;
+ }
+
+ /* rlim_t might have different sizes, let's map
+ * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
+ * all archs */
+ u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
+
+ return sd_bus_message_append(reply, "t", u);
+}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index d2b2d701ce..3925c10fde 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -21,10 +21,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-event.h"
#include "sd-bus.h"
+#include "sd-event.h"
+
#include "hashmap.h"
#include "install.h"
+#include "string-util.h"
#include "time-util.h"
typedef enum BusTransport {
@@ -65,11 +67,11 @@ int bus_test_polkit(sd_bus_message *call, int capability, const char *action, co
int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
void bus_verify_polkit_async_registry_free(Hashmap *registry);
-int bus_open_system_systemd(sd_bus **_bus);
-int bus_open_user_systemd(sd_bus **_bus);
+int bus_connect_system_systemd(sd_bus **_bus);
+int bus_connect_user_systemd(sd_bus **_bus);
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
int bus_print_property(const char *name, sd_bus_message *property, bool all);
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
@@ -200,3 +202,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
bool is_kdbus_wanted(void);
bool is_kdbus_available(void);
+
+int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 31b4f6c684..129ffc7056 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -19,19 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <string.h>
#include <dirent.h>
#include <errno.h>
+#include <stdio.h>
+#include <string.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "cgroup-show.h"
+#include "cgroup-util.h"
+#include "fd-util.h"
#include "formats-util.h"
-#include "process-util.h"
+#include "locale-util.h"
#include "macro.h"
#include "path-util.h"
-#include "cgroup-util.h"
-#include "cgroup-show.h"
+#include "process-util.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
static int compare(const void *a, const void *b) {
const pid_t *p = a, *q = b;
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index d1cdb151b2..835fe52423 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -19,19 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <dirent.h>
+#include <fcntl.h>
+#include <mqueue.h>
#include <sys/ipc.h>
-#include <sys/shm.h>
-#include <sys/sem.h>
#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <mqueue.h>
-#include "util.h"
+#include "clean-ipc.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "clean-ipc.h"
+#include "util.h"
+#include "dirent-util.h"
static int clean_sysvipc_shm(uid_t delete_uid) {
_cleanup_fclose_ FILE *f = NULL;
@@ -44,8 +48,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
}
FOREACH_LINE(line, f, goto fail) {
@@ -87,8 +90,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) {
return ret;
fail:
- log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
}
static int clean_sysvipc_sem(uid_t delete_uid) {
@@ -102,8 +104,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
}
FOREACH_LINE(line, f, goto fail) {
@@ -140,8 +141,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) {
return ret;
fail:
- log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
}
static int clean_sysvipc_msg(uid_t delete_uid) {
@@ -155,8 +155,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
if (errno == ENOENT)
return 0;
- log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
}
FOREACH_LINE(line, f, goto fail) {
@@ -194,8 +193,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) {
return ret;
fail:
- log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
}
static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
@@ -273,8 +271,7 @@ static int clean_posix_shm(uid_t uid) {
if (errno == ENOENT)
return 0;
- log_warning_errno(errno, "Failed to open /dev/shm: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to open /dev/shm: %m");
}
return clean_posix_shm_internal(dir, uid);
@@ -290,8 +287,7 @@ static int clean_posix_mq(uid_t uid) {
if (errno == ENOENT)
return 0;
- log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
}
FOREACH_DIRENT(de, dir, goto fail) {
@@ -330,8 +326,7 @@ static int clean_posix_mq(uid_t uid) {
return ret;
fail:
- log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
- return -errno;
+ return log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
}
int clean_ipc(uid_t uid) {
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 1d7dd49e04..a69719116c 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -19,25 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
+#include <fnmatch.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <fnmatch.h>
#include "sd-id128.h"
-#include "util.h"
-#include "virt.h"
-#include "path-util.h"
-#include "architecture.h"
-#include "smack-util.h"
+
+#include "alloc-util.h"
#include "apparmor-util.h"
-#include "ima-util.h"
-#include "selinux-util.h"
-#include "audit.h"
+#include "architecture.h"
+#include "audit-util.h"
#include "cap-list.h"
-#include "hostname-util.h"
#include "condition.h"
+#include "extract-word.h"
+#include "fd-util.h"
+#include "glob-util.h"
+#include "hostname-util.h"
+#include "ima-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+#include "virt.h"
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
Condition *c;
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 946eac6823..3f8eaf7d9a 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -19,21 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "sd-messages.h"
+
+#include "alloc-util.h"
#include "conf-files.h"
-#include "util.h"
-#include "macro.h"
-#include "strv.h"
+#include "conf-parser.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "log.h"
-#include "utf8.h"
+#include "macro.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "signal-util.h"
-#include "conf-parser.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "utf8.h"
+#include "util.h"
int config_item_table_lookup(
const void *table,
@@ -147,8 +155,7 @@ static int next_assignment(const char *unit,
/* Warn about unknown non-extension fields. */
if (!relaxed && !startswith(lvalue, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown lvalue '%s' in section '%s'", lvalue, section);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
return 0;
}
@@ -196,8 +203,7 @@ static int parse_line(const char* unit,
* Support for them should be eventually removed. */
if (!allow_include) {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- ".include not allowed here. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
return 0;
}
@@ -216,8 +222,7 @@ static int parse_line(const char* unit,
assert(k > 0);
if (l[k-1] != ']') {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- "Invalid section header '%s'", l);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
return -EBADMSG;
}
@@ -228,8 +233,7 @@ static int parse_line(const char* unit,
if (sections && !nulstr_contains(sections, n)) {
if (!relaxed && !startswith(n, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown section '%s'. Ignoring.", n);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
free(n);
*section = mfree(*section);
@@ -248,16 +252,15 @@ static int parse_line(const char* unit,
if (sections && !*section) {
if (!relaxed && !*section_ignored)
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Assignment outside of section. Ignoring.");
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
return 0;
}
e = strchr(l, '=');
if (!e) {
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
- return -EBADMSG;
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
+ return -EINVAL;
}
*e = 0;
@@ -420,16 +423,17 @@ int config_parse_many(const char *conf_file,
}
#define DEFINE_PARSER(type, vartype, conv_func) \
- int config_parse_##type(const char *unit, \
- const char *filename, \
- unsigned line, \
- const char *section, \
- unsigned section_line, \
- const char *lvalue, \
- int ltype, \
- const char *rvalue, \
- void *data, \
- void *userdata) { \
+ int config_parse_##type( \
+ const char *unit, \
+ const char *filename, \
+ unsigned line, \
+ const char *section, \
+ unsigned section_line, \
+ const char *lvalue, \
+ int ltype, \
+ const char *rvalue, \
+ void *data, \
+ void *userdata) { \
\
vartype *i = data; \
int r; \
@@ -441,21 +445,23 @@ int config_parse_many(const char *conf_file,
\
r = conv_func(rvalue, i); \
if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
+ log_syntax(unit, LOG_ERR, filename, line, r, \
"Failed to parse %s value, ignoring: %s", \
#type, rvalue); \
\
return 0; \
- }
-
-DEFINE_PARSER(int, int, safe_atoi)
-DEFINE_PARSER(long, long, safe_atoli)
-DEFINE_PARSER(uint32, uint32_t, safe_atou32)
-DEFINE_PARSER(uint64, uint64_t, safe_atou64)
-DEFINE_PARSER(unsigned, unsigned, safe_atou)
-DEFINE_PARSER(double, double, safe_atod)
-DEFINE_PARSER(nsec, nsec_t, parse_nsec)
-DEFINE_PARSER(sec, usec_t, parse_sec)
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+DEFINE_PARSER(int, int, safe_atoi);
+DEFINE_PARSER(long, long, safe_atoli);
+DEFINE_PARSER(uint32, uint32_t, safe_atou32);
+DEFINE_PARSER(uint64, uint64_t, safe_atou64);
+DEFINE_PARSER(unsigned, unsigned, safe_atou);
+DEFINE_PARSER(double, double, safe_atod);
+DEFINE_PARSER(nsec, nsec_t, parse_nsec);
+DEFINE_PARSER(sec, usec_t, parse_sec);
+DEFINE_PARSER(mode, mode_t, parse_mode);
int config_parse_iec_size(const char* unit,
const char *filename,
@@ -479,7 +485,7 @@ int config_parse_iec_size(const char* unit,
r = parse_size(rvalue, 1024, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -509,7 +515,7 @@ int config_parse_si_size(const char* unit,
r = parse_size(rvalue, 1000, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -564,8 +570,7 @@ int config_parse_bool(const char* unit,
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -626,7 +631,7 @@ int config_parse_string(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
@@ -664,12 +669,12 @@ int config_parse_path(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
return 0;
}
@@ -730,7 +735,7 @@ int config_parse_strv(const char *unit,
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
free(n);
continue;
}
@@ -740,35 +745,7 @@ int config_parse_strv(const char *unit,
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-int config_parse_mode(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- mode_t *m = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (parse_mode(rvalue, m) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
- return 0;
- }
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -795,7 +772,7 @@ int config_parse_log_facility(
x = log_facility_unshifted_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
return 0;
}
@@ -826,7 +803,7 @@ int config_parse_log_level(
x = log_level_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
return 0;
}
@@ -855,7 +832,7 @@ int config_parse_signal(
r = signal_from_string_try_harder(rvalue);
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
return 0;
}
@@ -884,7 +861,7 @@ int config_parse_personality(
p = personality_from_string(rvalue);
if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 4efed138c9..fb0234baae 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -123,13 +123,6 @@ int config_parse_log_level(const char *unit, const char *filename, unsigned line
int config_parse_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_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);
-#define log_invalid_utf8(unit, level, config_file, config_line, error, rvalue) \
- do { \
- _cleanup_free_ char *_p = utf8_escape_invalid(rvalue); \
- log_syntax(unit, level, config_file, config_line, error, \
- "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
- } while(false)
-
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function(const char *unit, \
const char *filename, \
diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c
index 25ad918b85..ad3c17d5bd 100644
--- a/src/shared/dev-setup.c
+++ b/src/shared/dev-setup.c
@@ -23,10 +23,12 @@
#include <stdlib.h>
#include <unistd.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "dev-setup.h"
#include "label.h"
#include "path-util.h"
-#include "dev-setup.h"
+#include "user-util.h"
+#include "util.h"
int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
static const char symlinks[] =
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 6dc04d51e4..7af15e0098 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -24,7 +24,11 @@
#include <stringprep.h>
#endif
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "hexdecoct.h"
+#include "parse-util.h"
+#include "string-util.h"
int dns_label_unescape(const char **name, char *dest, size_t sz) {
const char *n;
@@ -379,9 +383,8 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
return 0;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+void dns_name_hash_func(const void *s, struct siphash *state) {
const char *p = s;
- unsigned long ul = hash_key[0];
int r;
assert(p);
@@ -400,13 +403,17 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
if (k > 0)
r = k;
+ if (r == 0)
+ break;
+
label[r] = 0;
ascii_strlower(label);
- ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+ string_hash_func(label, state);
}
- return ul;
+ /* enforce that all names are terminated by the empty label */
+ string_hash_func("", state);
}
int dns_name_compare_func(const void *a, const void *b) {
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 8e73d9c20f..1f0d242c18 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -54,7 +54,7 @@ static inline int dns_name_is_valid(const char *s) {
return 1;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
+void dns_name_hash_func(const void *s, struct siphash *state);
int dns_name_compare_func(const void *a, const void *b);
extern const struct hash_ops dns_name_hash_ops;
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 963d05d32e..0d44401cc2 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -19,12 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "conf-files.h"
#include "dropin.h"
-#include "util.h"
-#include "strv.h"
-#include "mkdir.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio-label.h"
-#include "conf-files.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
int drop_in_file(const char *dir, const char *unit, unsigned level,
const char *name, char **_p, char **_q) {
@@ -78,7 +83,7 @@ int write_drop_in(const char *dir, const char *unit, unsigned level,
if (r < 0)
return r;
- mkdir_p(p, 0755);
+ (void) mkdir_p(p, 0755);
return write_string_file_atomic_label(q, data);
}
@@ -132,8 +137,7 @@ static int iterate_dir(
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open directory %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to open directory %s: %m", path);
}
for (;;) {
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index f087c2a566..86bb0b57c3 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -23,10 +23,16 @@
#include <string.h>
#include <fcntl.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "stdio-util.h"
#include "utf8.h"
+#include "util.h"
#include "virt.h"
-#include "efivars.h"
#ifdef ENABLE_EFI
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index effc6e8e70..e178287872 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -27,8 +27,9 @@
#include <linux/netfilter/xt_addrtype.h>
#include <libiptc/libiptc.h>
-#include "util.h"
+#include "alloc-util.h"
#include "firewall-util.h"
+#include "util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index e231a0ff80..eb2845cddf 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -19,10 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "device-nodes.h"
#include "fstab-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
+bool fstab_is_mount_point(const char *mount) {
+ _cleanup_endmntent_ FILE *f = NULL;
+ struct mntent *m;
+
+ f = setmntent("/etc/fstab", "r");
+ if (!f)
+ return false;
+
+ while ((m = getmntent(f)))
+ if (path_equal(m->mnt_dir, mount))
+ return true;
+
+ return false;
+}
+
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered) {
const char *name, *n = NULL, *x;
@@ -178,3 +199,60 @@ int fstab_find_pri(const char *options, int *ret) {
*ret = (int) pri;
return 1;
}
+
+static char *unquote(const char *s, const char* quotes) {
+ size_t l;
+ assert(s);
+
+ /* This is rather stupid, simply removes the heading and
+ * trailing quotes if there is one. Doesn't care about
+ * escaping or anything.
+ *
+ * DON'T USE THIS FOR NEW CODE ANYMORE!*/
+
+ l = strlen(s);
+ if (l < 2)
+ return strdup(s);
+
+ if (strchr(quotes, s[0]) && s[l-1] == s[0])
+ return strndup(s+1, l-2);
+
+ return strdup(s);
+}
+
+static char *tag_to_udev_node(const char *tagvalue, const char *by) {
+ _cleanup_free_ char *t = NULL, *u = NULL;
+ size_t enc_len;
+
+ u = unquote(tagvalue, QUOTES);
+ if (!u)
+ return NULL;
+
+ enc_len = strlen(u) * 4 + 1;
+ t = new(char, enc_len);
+ if (!t)
+ return NULL;
+
+ if (encode_devnode_name(u, t, enc_len) < 0)
+ return NULL;
+
+ return strjoin("/dev/disk/by-", by, "/", t, NULL);
+}
+
+char *fstab_node_to_udev_node(const char *p) {
+ assert(p);
+
+ if (startswith(p, "LABEL="))
+ return tag_to_udev_node(p+6, "label");
+
+ if (startswith(p, "UUID="))
+ return tag_to_udev_node(p+5, "uuid");
+
+ if (startswith(p, "PARTUUID="))
+ return tag_to_udev_node(p+9, "partuuid");
+
+ if (startswith(p, "PARTLABEL="))
+ return tag_to_udev_node(p+10, "partlabel");
+
+ return strdup(p);
+}
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 387c562a96..5ebea44019 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -23,10 +23,12 @@
#include <stdbool.h>
#include <stddef.h>
+
#include "macro.h"
-int fstab_filter_options(const char *opts, const char *names,
- const char **namefound, char **value, char **filtered);
+bool fstab_is_mount_point(const char *mount);
+
+int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered);
int fstab_extract_values(const char *opts, const char *name, char ***values);
@@ -48,3 +50,5 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no
return opt == yes_no;
}
+
+char *fstab_node_to_udev_node(const char *p);
diff --git a/src/shared/generator.c b/src/shared/generator.c
index e58bbea77c..cb4ebc606e 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -21,21 +21,25 @@
#include <unistd.h>
-#include "util.h"
-#include "special.h"
-#include "mkdir.h"
-#include "unit-name.h"
+#include "alloc-util.h"
+#include "dropin.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fstab-util.h"
#include "generator.h"
+#include "mkdir.h"
+#include "mount-util.h"
#include "path-util.h"
-#include "fstab-util.h"
-#include "fileio.h"
-#include "dropin.h"
+#include "special.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "util.h"
static int write_fsck_sysroot_service(const char *dir, const char *what) {
- const char *unit;
- _cleanup_free_ char *device = NULL;
- _cleanup_free_ char *escaped;
+ _cleanup_free_ char *device = NULL, *escaped = NULL;
_cleanup_fclose_ FILE *f = NULL;
+ const char *unit;
int r;
escaped = cescape(what);
@@ -101,16 +105,17 @@ int generator_write_fsck_deps(
if (!isempty(fstype) && !streq(fstype, "auto")) {
r = fsck_exists(fstype);
- if (r == -ENOENT) {
+ if (r < 0)
+ log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
+ else if (r == 0) {
/* treat missing check as essentially OK */
- log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype);
+ log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
return 0;
- } else if (r < 0)
- return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype);
+ }
}
if (path_equal(where, "/")) {
- char *lnk;
+ const char *lnk;
lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
diff --git a/src/shared/import-util.c b/src/shared/import-util.c
index 001a8a37e8..ddc8c00a2d 100644
--- a/src/shared/import-util.c
+++ b/src/shared/import-util.c
@@ -19,8 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "alloc-util.h"
+#include "btrfs-util.h"
#include "import-util.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
int import_url_last_component(const char *url, char **ret) {
const char *e, *p;
@@ -201,3 +206,29 @@ bool dkr_id_is_valid(const char *id) {
return true;
}
+
+int import_assign_pool_quota_and_warn(const char *path) {
+ int r;
+
+ r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
+ if (r == -ENOTTY) {
+ log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring.");
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m");
+ if (r > 0)
+ log_info("Set up default quota hierarchy for /var/lib/machines.");
+
+ r = btrfs_subvol_auto_qgroup(path, 0, true);
+ if (r == -ENOTTY) {
+ log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path);
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
+ if (r > 0)
+ log_info("Set up default quota hierarchy for %s.", path);
+
+ return 0;
+}
diff --git a/src/shared/import-util.h b/src/shared/import-util.h
index 7bf7d4ca40..9120a5119f 100644
--- a/src/shared/import-util.h
+++ b/src/shared/import-util.h
@@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id);
bool dkr_ref_is_valid(const char *ref);
bool dkr_digest_is_valid(const char *digest);
#define dkr_tag_is_valid(tag) filename_is_valid(tag)
+
+int import_assign_pool_quota_and_warn(const char *path);
diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c
index cbe984d2fb..e1cb5d27ff 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -21,11 +21,13 @@
#include <stdlib.h>
+#include "alloc-util.h"
+#include "formats-util.h"
+#include "install-printf.h"
#include "specifier.h"
#include "unit-name.h"
+#include "user-util.h"
#include "util.h"
-#include "install-printf.h"
-#include "formats-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
UnitFileInstallInfo *i = userdata;
diff --git a/src/shared/install.c b/src/shared/install.c
index 3d2b5ae77f..b7d1d22505 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -21,23 +21,30 @@
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
#include <fnmatch.h>
+#include <string.h>
+#include <unistd.h>
-#include "util.h"
-#include "mkdir.h"
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "conf-parser.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "hashmap.h"
-#include "set.h"
-#include "path-util.h"
+#include "install-printf.h"
+#include "install.h"
+#include "mkdir.h"
#include "path-lookup.h"
+#include "path-util.h"
+#include "set.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
-#include "install.h"
-#include "conf-parser.h"
-#include "conf-files.h"
-#include "install-printf.h"
-#include "special.h"
+#include "util.h"
typedef struct {
OrderedHashmap *will_install;
@@ -46,13 +53,12 @@ typedef struct {
static int in_search_path(const char *path, char **search) {
_cleanup_free_ char *parent = NULL;
- int r;
assert(path);
- r = path_get_parent(path, &parent);
- if (r < 0)
- return r;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
return strv_contains(search, parent);
}
@@ -923,8 +929,6 @@ static int config_parse_also(
void *data,
void *userdata) {
- size_t l;
- const char *word, *state;
InstallContext *c = data;
UnitFileInstallInfo *i = userdata;
@@ -932,13 +936,18 @@ static int config_parse_also(
assert(lvalue);
assert(rvalue);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ for(;;) {
+ _cleanup_free_ char *n = NULL;
int r;
- n = strndup(word, l);
- if (!n)
- return -ENOMEM;
+ r = extract_first_word(&rvalue, &n, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse config %s, ignoring.", rvalue);
+ return 0;
+ }
+
+ if (r == 0)
+ break;
r = install_info_add(c, n, NULL);
if (r < 0)
@@ -948,9 +957,6 @@ static int config_parse_also(
if (r < 0)
return r;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
return 0;
}
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index dbc07aa7ad..0313b0946f 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -19,25 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <time.h>
#include <errno.h>
-#include <sys/socket.h>
-#include <string.h>
#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
-#include "logs-show.h"
-#include "log.h"
-#include "util.h"
-#include "utf8.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "hashmap.h"
+#include "hostname-util.h"
+#include "io-util.h"
#include "journal-internal.h"
-#include "formats-util.h"
+#include "log.h"
+#include "logs-show.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "string-table.h"
+#include "string-util.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "utf8.h"
+#include "util.h"
-/* up to three lines (each up to 100 characters),
- or 300 characters, whichever is less */
+/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
#define PRINT_LINE_THRESHOLD 3
#define PRINT_CHAR_THRESHOLD 300
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 9c1e4d5e13..2c1da0a40d 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -23,15 +23,22 @@
#include <linux/fs.h>
#include <sys/statfs.h>
+#include "alloc-util.h"
#include "btrfs-util.h"
+#include "chattr-util.h"
#include "copy.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "machine-image.h"
#include "mkdir.h"
#include "path-util.h"
#include "rm-rf.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
#include "utf8.h"
-
-#include "machine-image.h"
+#include "xattr-util.h"
static const char image_search_path[] =
"/var/lib/machines\0"
@@ -176,11 +183,10 @@ static int image_make(
return r;
if (r) {
BtrfsSubvolInfo info;
- BtrfsQuotaInfo quota;
/* It's a btrfs subvolume */
- r = btrfs_subvol_get_info_fd(fd, &info);
+ r = btrfs_subvol_get_info_fd(fd, 0, &info);
if (r < 0)
return r;
@@ -195,13 +201,17 @@ static int image_make(
if (r < 0)
return r;
- r = btrfs_subvol_get_quota_fd(fd, &quota);
- if (r >= 0) {
- (*ret)->usage = quota.referenced;
- (*ret)->usage_exclusive = quota.exclusive;
+ if (btrfs_quota_scan_ongoing(fd) == 0) {
+ BtrfsQuotaInfo quota;
- (*ret)->limit = quota.referenced_max;
- (*ret)->limit_exclusive = quota.exclusive_max;
+ r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
+ if (r >= 0) {
+ (*ret)->usage = quota.referenced;
+ (*ret)->usage_exclusive = quota.exclusive;
+
+ (*ret)->limit = quota.referenced_max;
+ (*ret)->limit_exclusive = quota.exclusive_max;
+ }
}
return 1;
@@ -397,7 +407,7 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- r = btrfs_subvol_remove(i->path, true);
+ r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0)
return r;
break;
@@ -587,7 +597,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_DIRECTORY:
new_path = strjoina("/var/lib/machines/", new_name);
- r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
+ r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+
+ /* Enable "subtree" quotas for the copy, if we didn't
+ * copy any quota from the source. */
+ (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+
break;
case IMAGE_RAW:
@@ -629,6 +644,10 @@ int image_read_only(Image *i, bool b) {
switch (i->type) {
case IMAGE_SUBVOLUME:
+
+ /* Note that we set the flag only on the top-level
+ * subvolume of the image. */
+
r = btrfs_subvol_set_read_only(i->path, b);
if (r < 0)
return r;
@@ -729,7 +748,14 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
if (i->type != IMAGE_SUBVOLUME)
return -EOPNOTSUPP;
- return btrfs_quota_limit(i->path, referenced_max);
+ /* We set the quota both for the subvolume as well as for the
+ * subtree. The latter is mostly for historical reasons, since
+ * we didn't use to have a concept of subtree quota, and hence
+ * only modified the subvolume quota. */
+
+ (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
+ (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+ return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
}
int image_name_lock(const char *name, int operation, LockFile *ret) {
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
index 8af78f47d5..4172a63fd0 100644
--- a/src/shared/machine-pool.c
+++ b/src/shared/machine-pool.c
@@ -19,19 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/mount.h>
#include <sys/prctl.h>
-#include <sys/vfs.h>
#include <sys/statvfs.h>
-#include <sys/mount.h>
+#include <sys/vfs.h>
-#include "util.h"
-#include "process-util.h"
+#include "alloc-util.h"
+#include "btrfs-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "lockfile-util.h"
+#include "machine-pool.h"
#include "mkdir.h"
-#include "btrfs-util.h"
+#include "mount-util.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "signal-util.h"
-#include "machine-pool.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "util.h"
#define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)
#define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL)
@@ -170,7 +178,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
};
_cleanup_close_ int fd = -1, control = -1, loop = -1;
_cleanup_free_ char* loopdev = NULL;
- char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
+ char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL;
bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
char buf[FORMAT_BYTES_MAX];
int r, nr = -1;
@@ -194,14 +202,35 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
r = btrfs_quota_enable("/var/lib/machines", true);
if (r < 0)
- log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+ log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
+
+ r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
+
+ return 1;
+ }
+ if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0) {
+ log_debug("/var/lib/machines is already a mount point, not creating loopback file for it.");
return 0;
}
- if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
- dir_is_empty("/var/lib/machines") == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
+ r = dir_is_populated("/var/lib/machines");
+ if (r < 0 && r != -ENOENT)
+ return r;
+ if (r > 0) {
+ log_debug("/var/log/machines is already populated, not creating loopback file for it.");
+ return 0;
+ }
+
+ r = mkfs_exists("btrfs");
+ if (r == -ENOENT) {
+ log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines.");
+ return 0;
+ }
+ if (r < 0)
+ return r;
fd = setup_machine_raw(size, error);
if (fd < 0)
@@ -266,6 +295,10 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
if (r < 0)
log_warning_errno(r, "Failed to enable quota, ignoring: %m");
+ r = btrfs_subvol_auto_qgroup(mntdir, 0, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m");
+
if (chmod(mntdir, 0700) < 0) {
r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
goto fail;
@@ -286,7 +319,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
(void) rmdir(mntdir);
(void) rmdir(tmpdir);
- return 0;
+ return 1;
fail:
if (mntdir_mounted)
@@ -345,7 +378,7 @@ int grow_machine_directory(void) {
if (b.f_bavail > b.f_blocks / 3)
return 0;
- /* Calculate how much we are willing to add at maximum */
+ /* Calculate how much we are willing to add at most */
max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN;
/* Calculate the old size */
@@ -370,9 +403,11 @@ int grow_machine_directory(void) {
if (r <= 0)
return r;
- r = btrfs_quota_limit("/var/lib/machines", new_size);
- if (r < 0)
- return r;
+ /* Also bump the quota, of both the subvolume leaf qgroup, as
+ * well as of any subtree quota group by the same id but a
+ * higher level, if it exists. */
+ (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
+ (void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
return 1;
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 41da820938..d149bc1722 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -21,17 +21,20 @@
#include <fcntl.h>
#include <stdlib.h>
-#include <unistd.h>
#include <string.h>
#include <sys/prctl.h>
+#include <unistd.h>
+#include "copy.h"
+#include "fd-util.h"
+#include "locale-util.h"
+#include "macro.h"
#include "pager.h"
-#include "util.h"
#include "process-util.h"
-#include "macro.h"
-#include "terminal-util.h"
#include "signal-util.h"
-#include "copy.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
static pid_t pager_pid = 0;
@@ -48,24 +51,27 @@ noreturn static void pager_fallback(void) {
}
int pager_open(bool jump_to_end) {
- int fd[2];
+ _cleanup_close_pair_ int fd[2] = { -1, -1 };
const char *pager;
pid_t parent_pid;
- int r;
if (pager_pid > 0)
return 1;
- if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
- if (!*pager || streq(pager, "cat"))
- return 0;
-
if (!on_tty())
return 0;
+ pager = getenv("SYSTEMD_PAGER");
+ if (!pager)
+ pager = getenv("PAGER");
+
+ /* If the pager is explicitly turned off, honour it */
+ if (pager && (pager[0] == 0 || streq(pager, "cat")))
+ return 0;
+
/* Determine and cache number of columns before we spawn the
* pager so that we get the value from the actual tty */
- columns();
+ (void) columns();
if (pipe(fd) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
@@ -73,11 +79,8 @@ int pager_open(bool jump_to_end) {
parent_pid = getpid();
pager_pid = fork();
- if (pager_pid < 0) {
- r = log_error_errno(errno, "Failed to fork pager: %m");
- safe_close_pair(fd);
- return r;
- }
+ if (pager_pid < 0)
+ return log_error_errno(errno, "Failed to fork pager: %m");
/* In the child start the pager */
if (pager_pid == 0) {
@@ -86,7 +89,7 @@ int pager_open(bool jump_to_end) {
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
- dup2(fd[0], STDIN_FILENO);
+ (void) dup2(fd[0], STDIN_FILENO);
safe_close_pair(fd);
/* Initialize a good set of less options */
@@ -141,7 +144,6 @@ int pager_open(bool jump_to_end) {
if (dup2(fd[1], STDERR_FILENO) < 0)
return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
- safe_close_pair(fd);
return 1;
}
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index d803bbe07e..d71f379e76 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -24,11 +24,13 @@
#include <string.h>
#include <errno.h>
+#include "alloc-util.h"
#include "util.h"
#include "strv.h"
#include "path-util.h"
-#include "path-lookup.h"
#include "install.h"
+#include "string-util.h"
+#include "path-lookup.h"
int user_config_home(char **config_home) {
const char *e;
@@ -181,7 +183,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) config_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
return NULL;
if (runtime_dir)
@@ -203,14 +205,14 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) data_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
if (generator_late)
if (strv_extend(&res, generator_late) < 0)
return NULL;
- if (!path_strv_make_absolute_cwd(res))
+ if (path_strv_make_absolute_cwd(res) < 0)
return NULL;
tmp = res;
@@ -244,6 +246,7 @@ int lookup_paths_init(
const char *e;
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
+ int r;
assert(p);
@@ -259,9 +262,9 @@ int lookup_paths_init(
/* FIXME: empty components in other places should be
* rejected. */
- p->unit_path = path_split_and_make_absolute(e);
- if (!p->unit_path)
- return -ENOMEM;
+ r = path_split_and_make_absolute(e, &p->unit_path);
+ if (r < 0)
+ return r;
} else
p->unit_path = NULL;
@@ -269,7 +272,6 @@ int lookup_paths_init(
/* Let's figure something out. */
_cleanup_strv_free_ char **unit_path;
- int r;
/* For the user units we include share/ in the search
* path in order to comply with the XDG basedir spec.
@@ -318,7 +320,7 @@ int lookup_paths_init(
if (!unit_path)
return -ENOMEM;
- r = strv_extend_strv(&p->unit_path, unit_path);
+ r = strv_extend_strv(&p->unit_path, unit_path, false);
if (r < 0)
return r;
}
@@ -342,9 +344,9 @@ int lookup_paths_init(
e = getenv("SYSTEMD_SYSVINIT_PATH");
if (e) {
- p->sysvinit_path = path_split_and_make_absolute(e);
- if (!p->sysvinit_path)
- return -ENOMEM;
+ r = path_split_and_make_absolute(e, &p->sysvinit_path);
+ if (r < 0)
+ return r;
} else
p->sysvinit_path = NULL;
@@ -360,9 +362,9 @@ int lookup_paths_init(
e = getenv("SYSTEMD_SYSVRCND_PATH");
if (e) {
- p->sysvrcnd_path = path_split_and_make_absolute(e);
- if (!p->sysvrcnd_path)
- return -ENOMEM;
+ r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
+ if (r < 0)
+ return r;
} else
p->sysvrcnd_path = NULL;
@@ -417,9 +419,8 @@ void lookup_paths_free(LookupPaths *p) {
p->unit_path = strv_free(p->unit_path);
#ifdef HAVE_SYSV_COMPAT
- strv_free(p->sysvinit_path);
- strv_free(p->sysvrcnd_path);
- p->sysvinit_path = p->sysvrcnd_path = NULL;
+ p->sysvinit_path = strv_free(p->sysvinit_path);
+ p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
#endif
}
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 789f217efc..63e81f4894 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -24,14 +24,18 @@
#include <limits.h>
#include <termios.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "ptyfwd.h"
+#include "util.h"
struct PTYForward {
sd_event *event;
int master;
+ PTYForwardFlags flags;
+
sd_event_source *stdin_event_source;
sd_event_source *stdout_event_source;
sd_event_source *master_event_source;
@@ -41,8 +45,6 @@ struct PTYForward {
struct termios saved_stdin_attr;
struct termios saved_stdout_attr;
- bool read_only:1;
-
bool saved_stdin:1;
bool saved_stdout:1;
@@ -54,8 +56,7 @@ struct PTYForward {
bool master_writable:1;
bool master_hangup:1;
- /* Continue reading after hangup? */
- bool ignore_vhangup:1;
+ bool read_from_master:1;
bool last_char_set:1;
char last_char;
@@ -100,6 +101,18 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
return false;
}
+static bool ignore_vhangup(PTYForward *f) {
+ assert(f);
+
+ if (f->flags & PTY_FORWARD_IGNORE_VHANGUP)
+ return true;
+
+ if ((f->flags & PTY_FORWARD_IGNORE_INITIAL_VHANGUP) && !f->read_from_master)
+ return true;
+
+ return false;
+}
+
static int shovel(PTYForward *f) {
ssize_t k;
@@ -179,7 +192,7 @@ static int shovel(PTYForward *f) {
* EAGAIN here and try again, unless
* ignore_vhangup is off. */
- if (errno == EAGAIN || (errno == EIO && f->ignore_vhangup))
+ if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f)))
f->master_readable = false;
else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
f->master_readable = f->master_writable = false;
@@ -190,8 +203,10 @@ static int shovel(PTYForward *f) {
log_error_errno(errno, "read(): %m");
return sd_event_exit(f->event, EXIT_FAILURE);
}
- } else
+ } else {
+ f->read_from_master = true;
f->out_buffer_full += (size_t) k;
+ }
}
if (f->stdout_writable && f->out_buffer_full > 0) {
@@ -302,8 +317,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
int pty_forward_new(
sd_event *event,
int master,
- bool ignore_vhangup,
- bool read_only,
+ PTYForwardFlags flags,
PTYForward **ret) {
_cleanup_(pty_forward_freep) PTYForward *f = NULL;
@@ -314,8 +328,7 @@ int pty_forward_new(
if (!f)
return -ENOMEM;
- f->read_only = read_only;
- f->ignore_vhangup = ignore_vhangup;
+ f->flags = flags;
if (event)
f->event = sd_event_ref(event);
@@ -325,7 +338,7 @@ int pty_forward_new(
return r;
}
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
r = fd_nonblock(STDIN_FILENO, true);
if (r < 0)
return r;
@@ -344,7 +357,7 @@ int pty_forward_new(
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
(void) ioctl(master, TIOCSWINSZ, &ws);
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
struct termios raw_stdin_attr;
@@ -400,6 +413,7 @@ PTYForward *pty_forward_free(PTYForward *f) {
sd_event_source_unref(f->stdin_event_source);
sd_event_source_unref(f->stdout_event_source);
sd_event_source_unref(f->master_event_source);
+ sd_event_source_unref(f->sigwinch_event_source);
sd_event_unref(f->event);
if (f->saved_stdout)
@@ -429,16 +443,20 @@ int pty_forward_get_last_char(PTYForward *f, char *ch) {
return 0;
}
-int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
+int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
int r;
assert(f);
- if (f->ignore_vhangup == ignore_vhangup)
+ if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b)
return 0;
- f->ignore_vhangup = ignore_vhangup;
- if (!f->ignore_vhangup) {
+ if (b)
+ f->flags |= PTY_FORWARD_IGNORE_VHANGUP;
+ else
+ f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP;
+
+ if (!ignore_vhangup(f)) {
/* We shall now react to vhangup()s? Let's check
* immediately if we might be in one */
@@ -455,5 +473,5 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
int pty_forward_get_ignore_vhangup(PTYForward *f) {
assert(f);
- return f->ignore_vhangup;
+ return !!(f->flags & PTY_FORWARD_IGNORE_VHANGUP);
}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index 6f84e4036a..9b3214221b 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -27,7 +27,17 @@
typedef struct PTYForward PTYForward;
-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f);
+typedef enum PTYForwardFlags {
+ PTY_FORWARD_READ_ONLY = 1,
+
+ /* Continue reading after hangup? */
+ PTY_FORWARD_IGNORE_VHANGUP = 2,
+
+ /* Continue reading after hangup but only if we never read anything else? */
+ PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4,
+} PTYForwardFlags;
+
+int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f);
PTYForward *pty_forward_free(PTYForward *f);
int pty_forward_get_last_char(PTYForward *f, char *ch);
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index d73a74912e..c518cf83ec 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -21,6 +21,7 @@
#include <seccomp.h>
+#include "string-util.h"
#include "util.h"
#include "seccomp-util.h"
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 1064fd5cbd..102c5cc992 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -21,10 +21,15 @@
#include <stdio.h>
+#include "alloc-util.h"
#include "conf-parser.h"
-#include "sleep-config.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio.h"
#include "log.h"
+#include "parse-util.h"
+#include "sleep-config.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -226,7 +231,7 @@ static bool enough_memory_for_hibernation(void) {
if (r < 0)
return false;
- r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
+ r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
if (r < 0) {
log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
return false;
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index 70466d17e5..29db855c67 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
-#include <signal.h>
#include "log.h"
-#include "util.h"
#include "process-util.h"
+#include "util.h"
#include "spawn-ask-password-agent.h"
static pid_t agent_pid = 0;
@@ -46,9 +46,9 @@ 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_errno(r, "Failed to fork TTY ask password agent: %m");
+ return log_error_errno(r, "Failed to fork TTY ask password agent: %m");
- return r;
+ return 1;
}
void ask_password_agent_close(void) {
@@ -57,8 +57,8 @@ void ask_password_agent_close(void) {
return;
/* Inform agent that we are done */
- kill(agent_pid, SIGTERM);
- kill(agent_pid, SIGCONT);
+ (void) kill(agent_pid, SIGTERM);
+ (void) kill(agent_pid, SIGCONT);
(void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index 4db249e1ca..ec6e5a8312 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -25,10 +25,13 @@
#include <errno.h>
#include <poll.h>
+#include "fd-util.h"
+#include "io-util.h"
#include "log.h"
-#include "util.h"
#include "process-util.h"
#include "spawn-polkit-agent.h"
+#include "stdio-util.h"
+#include "util.h"
#ifdef ENABLE_POLKIT
static pid_t agent_pid = 0;
@@ -76,8 +79,9 @@ void polkit_agent_close(void) {
return;
/* Inform agent that we are done */
- kill(agent_pid, SIGTERM);
- kill(agent_pid, SIGCONT);
+ (void) kill(agent_pid, SIGTERM);
+ (void) kill(agent_pid, SIGCONT);
+
(void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index 85bd477f2d..c5c4a4d7d7 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -22,10 +22,12 @@
#include <string.h>
#include <sys/utsname.h>
-#include "macro.h"
-#include "util.h"
+#include "alloc-util.h"
#include "hostname-util.h"
+#include "macro.h"
#include "specifier.h"
+#include "string-util.h"
+#include "util.h"
/*
* Generic infrastructure for replacing %x style specifiers in
diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c
index b12189cd10..fc885f6cb8 100644
--- a/src/shared/switch-root.c
+++ b/src/shared/switch-root.c
@@ -19,21 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <stdbool.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
#include <string.h>
#include <sys/mount.h>
+#include <sys/stat.h>
#include <unistd.h>
-#include <fcntl.h>
-#include "util.h"
-#include "path-util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
#include "base-filesystem.h"
+#include "fd-util.h"
#include "missing.h"
+#include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
#include "switch-root.h"
+#include "user-util.h"
+#include "util.h"
int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) {
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
index 1de0b94fd5..21cb82ea1c 100644
--- a/src/shared/sysctl-util.c
+++ b/src/shared/sysctl-util.c
@@ -19,18 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fileio.h"
#include "log.h"
+#include "string-util.h"
#include "util.h"
-#include "fileio.h"
-#include "build.h"
#include "sysctl-util.h"
char *sysctl_normalize(char *s) {
diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c
index 4794ff45bb..079dd8752c 100644
--- a/src/shared/uid-range.c
+++ b/src/shared/uid-range.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "uid-range.h"
+#include "user-util.h"
+#include "util.h"
static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
assert(range);
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index 63f1e4ca6f..13b32a0509 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -19,18 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <utmpx.h>
#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
#include <string.h>
#include <sys/utsname.h>
-#include <fcntl.h>
#include <unistd.h>
-#include <poll.h>
+#include <utmpx.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "hostname-util.h"
#include "macro.h"
#include "path-util.h"
+#include "string-util.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "user-util.h"
#include "utmp-wtmp.h"
int utmp_get_runlevel(int *runlevel, int *previous) {
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
index 9d39beb340..d58f9873d5 100644
--- a/src/shared/watchdog.c
+++ b/src/shared/watchdog.c
@@ -27,6 +27,7 @@
#include "watchdog.h"
#include "log.h"
+#include "fd-util.h"
static int watchdog_fd = -1;
static usec_t watchdog_timeout = USEC_INFINITY;
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 2b2310152d..95de369817 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -20,18 +20,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
#include <getopt.h>
+#include <stdio.h>
#include "sd-messages.h"
-#include "log.h"
-#include "util.h"
-#include "strv.h"
+
+#include "def.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "build.h"
+#include "log.h"
#include "sleep-config.h"
-#include "def.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
static char* arg_verb = NULL;
@@ -165,9 +167,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0; /* done */
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 715f440cb1..ba82adadb4 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -20,12 +20,12 @@
***/
#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <netdb.h>
-#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
@@ -33,12 +33,15 @@
#include "sd-daemon.h"
#include "sd-event.h"
#include "sd-resolve.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
#include "log.h"
+#include "path-util.h"
+#include "set.h"
#include "socket-util.h"
+#include "string-util.h"
#include "util.h"
-#include "build.h"
-#include "set.h"
-#include "path-util.h"
#define BUFFER_SIZE (256 * 1024)
#define CONNECTIONS_MAX 256
@@ -603,9 +606,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 618844382f..152c98b348 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -19,23 +19,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include "log.h"
-#include "strv.h"
-#include "util.h"
-#include "hashmap.h"
-#include "path-util.h"
#include "conf-files.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "build.h"
+#include "hashmap.h"
+#include "log.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "strv.h"
#include "sysctl-util.h"
+#include "util.h"
static char **arg_prefixes = NULL;
@@ -86,8 +88,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno
if (feof(f))
break;
- log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
}
p = strstrip(l);
@@ -195,9 +196,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_PREFIX: {
char *p;
diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c
index 00045150f6..6c2f53774d 100644
--- a/src/system-update-generator/system-update-generator.c
+++ b/src/system-update-generator/system-update-generator.c
@@ -22,7 +22,9 @@
#include <errno.h>
#include <unistd.h>
+#include "fs-util.h"
#include "log.h"
+#include "string-util.h"
#include "util.h"
/*
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 34e4751b94..70871cf3e6 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -37,7 +37,7 @@
#include "sd-daemon.h"
#include "sd-login.h"
-#include "build.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-message.h"
@@ -49,31 +49,42 @@
#include "efivars.h"
#include "env-util.h"
#include "exit-status.h"
+#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
#include "hostname-util.h"
#include "initreq.h"
#include "install.h"
+#include "io-util.h"
#include "list.h"
+#include "locale-util.h"
#include "log.h"
#include "logs-show.h"
#include "macro.h"
#include "mkdir.h"
#include "pager.h"
+#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
#include "process-util.h"
+#include "rlimit-util.h"
#include "set.h"
#include "signal-util.h"
#include "socket-util.h"
#include "spawn-ask-password-agent.h"
#include "spawn-polkit-agent.h"
#include "special.h"
+#include "stat-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-name.h"
+#include "user-util.h"
#include "util.h"
#include "utmp-wtmp.h"
+#include "verbs.h"
+#include "virt.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -107,7 +118,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
static char **arg_wall = NULL;
static const char *arg_kill_who = NULL;
static int arg_signal = SIGTERM;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
static usec_t arg_when = 0;
static enum action {
_ACTION_INVALID,
@@ -134,23 +145,61 @@ static enum action {
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
+static const char *arg_host = NULL;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
static bool arg_firmware_setup = false;
static bool arg_now = false;
-static bool original_stdout_is_tty;
-
-static int daemon_reload(sd_bus *bus, char **args);
+static int daemon_reload(int argc, char *argv[], void* userdata);
static int halt_now(enum action a);
static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
-static char** strv_skip_first(char **strv) {
- if (strv_length(strv) > 0)
- return strv + 1;
- return NULL;
+static bool original_stdout_is_tty;
+
+typedef enum BusFocus {
+ BUS_FULL, /* The full bus indicated via --system or --user */
+ BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */
+ _BUS_FOCUS_MAX
+} BusFocus;
+
+static sd_bus *busses[_BUS_FOCUS_MAX] = {};
+
+static int acquire_bus(BusFocus focus, sd_bus **ret) {
+ int r;
+
+ assert(focus < _BUS_FOCUS_MAX);
+ assert(ret);
+
+ /* We only go directly to the manager, if we are using a local transport */
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ focus = BUS_FULL;
+
+ if (!busses[focus]) {
+ bool user;
+
+ user = arg_scope != UNIT_FILE_SYSTEM;
+
+ if (focus == BUS_MANAGER)
+ r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]);
+ else
+ r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to bus: %m");
+
+ (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password);
+ }
+
+ *ret = busses[focus];
+ return 0;
+}
+
+static void release_busses(void) {
+ BusFocus w;
+
+ for (w = 0; w < _BUS_FOCUS_MAX; w++)
+ busses[w] = sd_bus_flush_close_unref(busses[w]);
}
static void pager_open_if_enabled(void) {
@@ -230,42 +279,10 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error)
return EXIT_FAILURE;
}
-static void warn_wall(enum action a) {
- static const char *table[_ACTION_MAX] = {
- [ACTION_HALT] = "The system is going down for system halt NOW!",
- [ACTION_REBOOT] = "The system is going down for reboot NOW!",
- [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
- [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
- [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
- [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
- [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
- };
-
- if (arg_no_wall)
- return;
-
- if (arg_wall) {
- _cleanup_free_ char *p;
+static bool install_client_side(void) {
- p = strv_join(arg_wall, " ");
- if (!p) {
- log_oom();
- return;
- }
-
- if (*p) {
- utmp_wall(p, NULL, NULL, NULL, NULL);
- return;
- }
- }
-
- if (!table[a])
- return;
-
- utmp_wall(table[a], NULL, NULL, NULL, NULL);
-}
-
-static bool avoid_bus(void) {
+ /* Decides when to execute enable/disable/... operations
+ * client-side rather than server-side. */
if (running_in_chroot() > 0)
return true;
@@ -279,6 +296,10 @@ static bool avoid_bus(void) {
if (arg_scope == UNIT_FILE_GLOBAL)
return true;
+ /* Unsupported environment variable, mostly for debugging purposes */
+ if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
+ return true;
+
return false;
}
@@ -652,15 +673,20 @@ static int get_unit_list_recursive(
return c;
}
-static int list_units(sd_bus *bus, char **args) {
+static int list_units(int argc, char *argv[], void *userdata) {
_cleanup_free_ UnitInfo *unit_infos = NULL;
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
- r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
@@ -676,6 +702,10 @@ static int get_triggered_units(
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ assert(bus);
+ assert(path);
+ assert(ret);
+
r = sd_bus_get_property_strv(
bus,
"org.freedesktop.systemd1",
@@ -684,9 +714,8 @@ static int get_triggered_units(
"Triggers",
&error,
ret);
-
if (r < 0)
- log_error("Failed to determine triggers: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
return 0;
}
@@ -710,10 +739,8 @@ static int get_listening(
&error,
&reply,
"a(ss)");
- if (r < 0) {
- log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -853,7 +880,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
return 0;
}
-static int list_sockets(sd_bus *bus, char **args) {
+static int list_sockets(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
@@ -863,10 +890,15 @@ static int list_sockets(sd_bus *bus, char **args) {
unsigned cs = 0;
size_t size = 0;
int r = 0, n;
+ sd_bus *bus;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -947,10 +979,8 @@ static int get_next_elapse(
&error,
't',
&t.monotonic);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
r = sd_bus_get_property_trivial(
bus,
@@ -961,10 +991,8 @@ static int get_next_elapse(
&error,
't',
&t.realtime);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
*next = t;
return 0;
@@ -991,10 +1019,8 @@ static int get_last_trigger(
&error,
't',
last);
- if (r < 0) {
- log_error("Failed to get last trigger time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
return 0;
}
@@ -1160,7 +1186,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
return next_elapse;
}
-static int list_timers(sd_bus *bus, char **args) {
+static int list_timers(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ struct timer_info *timer_infos = NULL;
@@ -1170,11 +1196,16 @@ static int list_timers(sd_bus *bus, char **args) {
size_t size = 0;
int n, c = 0;
dual_timestamp nw;
+ sd_bus *bus;
int r = 0;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -1326,7 +1357,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
printf("\n%u unit files listed.\n", c);
}
-static int list_unit_files(sd_bus *bus, char **args) {
+static int list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
UnitFileList *unit;
@@ -1338,7 +1369,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
pager_open_if_enabled();
- if (avoid_bus()) {
+ if (install_client_side()) {
Hashmap *h;
UnitFileList *u;
Iterator i;
@@ -1351,8 +1382,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_errno(r, "Failed to get unit file list: %m");
- return r;
+ return log_error_errno(r, "Failed to get unit file list: %m");
}
n_units = hashmap_size(h);
@@ -1364,7 +1394,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
}
HASHMAP_FOREACH(u, h, i) {
- if (!output_show_unit_file(u, strv_skip_first(args)))
+ if (!output_show_unit_file(u, strv_skip(argv, 1)))
continue;
units[c++] = *u;
@@ -1375,6 +1405,11 @@ static int list_unit_files(sd_bus *bus, char **args) {
hashmap_free(h);
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1385,10 +1420,8 @@ static int list_unit_files(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list unit files: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -1404,7 +1437,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
unit_file_state_from_string(state)
};
- if (output_show_unit_file(&units[c], strv_skip_first(args)))
+ if (output_show_unit_file(&units[c], strv_skip(argv, 1)))
c ++;
}
@@ -1419,7 +1452,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (avoid_bus()) {
+ if (install_client_side()) {
for (unit = units; unit < units + c; unit++)
free(unit->path);
}
@@ -1511,10 +1544,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
&error,
&reply,
"s", "org.freedesktop.systemd1.Unit");
- if (r < 0) {
- log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
@@ -1638,16 +1669,15 @@ static int list_dependencies_one(
return 0;
}
-static int list_dependencies(sd_bus *bus, char **args) {
+static int list_dependencies(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **units = NULL;
_cleanup_free_ char *unit = NULL;
const char *u;
+ sd_bus *bus;
int r;
- assert(bus);
-
- if (args[1]) {
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+ if (argv[1]) {
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -1657,6 +1687,10 @@ static int list_dependencies(sd_bus *bus, char **args) {
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
puts(u);
return list_dependencies_one(bus, u, 0, &units, 0);
@@ -1872,12 +1906,11 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
printf("\n%u machines listed.\n", n);
}
-static int list_machines(sd_bus *bus, char **args) {
+static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
-
if (geteuid() != 0) {
log_error("Must be root.");
return -EPERM;
@@ -1885,7 +1918,11 @@ static int list_machines(sd_bus *bus, char **args) {
pager_open_if_enabled();
- r = get_machine_list(bus, &machine_infos, strv_skip_first(args));
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
if (r < 0)
return r;
@@ -1896,13 +1933,13 @@ static int list_machines(sd_bus *bus, char **args) {
return 0;
}
-static int get_default(sd_bus *bus, char **args) {
+static int get_default(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *_path = NULL;
const char *path;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_get_default(arg_scope, arg_root, &_path);
if (r < 0)
return log_error_errno(r, "Failed to get default target: %m");
@@ -1910,6 +1947,11 @@ static int get_default(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1920,10 +1962,8 @@ static int get_default(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to get default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &path);
if (r < 0)
@@ -1949,17 +1989,21 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha
}
}
-static int set_default(sd_bus *bus, char **args) {
+static int set_default(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *unit = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
int r;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+ assert(argc >= 2);
+ assert(argv);
+
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
if (r < 0)
return log_error_errno(r, "Failed to set default target: %m");
@@ -1967,13 +2011,19 @@ static int set_default(sd_bus *bus, char **args) {
if (!arg_quiet)
dump_unit_file_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
r = 0;
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1983,10 +2033,8 @@ static int set_default(sd_bus *bus, char **args) {
&error,
&reply,
"sb", unit, 1);
- if (r < 0) {
- log_error("Failed to set default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
@@ -1994,13 +2042,11 @@ static int set_default(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
- unit_file_changes_free(changes, n_changes);
-
return r;
}
@@ -2085,17 +2131,24 @@ static bool output_show_job(struct job_info *job, char **patterns) {
return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
}
-static int list_jobs(sd_bus *bus, char **args) {
+static int list_jobs(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *name, *type, *state, *job_path, *unit_path;
_cleanup_free_ struct job_info *jobs = NULL;
size_t size = 0;
unsigned c = 0;
+ sd_bus *bus;
uint32_t id;
int r;
bool skipped = false;
+ pager_open_if_enabled();
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -2105,10 +2158,8 @@ static int list_jobs(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list jobs: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
if (r < 0)
@@ -2117,7 +2168,7 @@ static int list_jobs(sd_bus *bus, char **args) {
while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
struct job_info job = { id, name, type, state };
- if (!output_show_job(&job, strv_skip_first(args))) {
+ if (!output_show_job(&job, strv_skip(argv, 1))) {
skipped = true;
continue;
}
@@ -2138,18 +2189,21 @@ static int list_jobs(sd_bus *bus, char **args) {
return r;
}
-static int cancel_job(sd_bus *bus, char **args) {
+static int cancel_job(int argc, char *argv[], void *userdata) {
+ sd_bus *bus;
char **name;
int r = 0;
- assert(args);
-
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- STRV_FOREACH(name, args+1) {
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
uint32_t id;
int q;
@@ -2168,7 +2222,7 @@ static int cancel_job(sd_bus *bus, char **args) {
NULL,
"u", id);
if (q < 0) {
- log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -2253,7 +2307,6 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
static int unit_find_paths(
sd_bus *bus,
const char *unit_name,
- bool avoid_bus_cache,
LookupPaths *lp,
char **fragment_path,
char ***dropin_paths) {
@@ -2274,7 +2327,7 @@ static int unit_find_paths(
assert(fragment_path);
assert(lp);
- if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+ if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
_cleanup_free_ char *unit = NULL;
@@ -2471,10 +2524,8 @@ static int check_triggering_units(
"LoadState",
&error,
&state);
- if (r < 0) {
- log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r));
if (streq(state, "masked"))
return 0;
@@ -2487,10 +2538,8 @@ static int check_triggering_units(
"TriggeredBy",
&error,
&triggered_by);
- if (r < 0) {
- log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
STRV_FOREACH(i, triggered_by) {
r = check_one_unit(bus, *i, "active\0reloading\0", true);
@@ -2586,8 +2635,7 @@ static int start_unit_one(
verb = method_to_verb(method);
- log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
- return r;
+ return log_error_errno(r, "Failed to %s %s: %s", verb, name, bus_error_message(error, r));
}
r = sd_bus_message_read(reply, "o", &path);
@@ -2608,11 +2656,13 @@ static int start_unit_one(
}
static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
-
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
char **name;
int r, i;
+ assert(bus);
+ assert(ret);
+
STRV_FOREACH(name, names) {
char *t;
@@ -2637,9 +2687,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
- if (!bus)
- return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented.");
-
r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
if (r < 0)
return r;
@@ -2687,24 +2734,28 @@ static enum action verb_to_action(const char *verb) {
return _ACTION_INVALID;
}
-static int start_unit(sd_bus *bus, char **args) {
+static int start_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
const char *method, *mode, *one_name, *suffix = NULL;
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r = 0;
- assert(bus);
-
ask_password_agent_open_if_enabled();
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_SYSTEMCTL) {
enum action action;
- method = verb_to_method(args[0]);
- action = verb_to_action(args[0]);
- if (streq(args[0], "isolate")) {
+ method = verb_to_method(argv[0]);
+ action = verb_to_action(argv[0]);
+
+ if (streq(argv[0], "isolate")) {
mode = "isolate";
suffix = ".target";
} else
@@ -2724,9 +2775,9 @@ static int start_unit(sd_bus *bus, char **args) {
if (one_name)
names = strv_new(one_name, NULL);
else {
- r = expand_names(bus, args + 1, suffix, &names);
+ r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
}
if (!arg_no_block) {
@@ -2761,18 +2812,55 @@ static int start_unit(sd_bus *bus, char **args) {
return r;
}
+static int logind_set_wall_message(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ _cleanup_free_ char *m = NULL;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ m = strv_join(arg_wall, " ");
+ if (!m)
+ return log_oom();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
+
+ if (r < 0)
+ return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
+
+#endif
+ return 0;
+}
+
/* Ask systemd-logind, which might grant access to unprivileged users
* through PolicyKit */
-static int reboot_with_logind(sd_bus *bus, enum action a) {
+static int logind_reboot(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method, *description;
+ sd_bus *bus;
int r;
- if (!bus)
- return -EIO;
-
polkit_agent_open_if_enabled();
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
switch (a) {
@@ -2805,33 +2893,6 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
return -EINVAL;
}
- if (!strv_isempty(arg_wall)) {
- _cleanup_free_ char *m;
-
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
- }
-
-
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2842,27 +2903,25 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
NULL,
"b", arg_ask_password);
if (r < 0)
- log_error("Failed to %s via logind: %s", description, bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
- return r;
+ return 0;
#else
return -ENOSYS;
#endif
}
-static int check_inhibitors(sd_bus *bus, enum action a) {
+static int logind_check_inhibitors(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **sessions = NULL;
const char *what, *who, *why, *mode;
uint32_t uid, pid;
+ sd_bus *bus;
unsigned c = 0;
char **s;
int r;
- if (!bus)
- return 0;
-
if (arg_ignore_inhibitors || arg_force > 0)
return 0;
@@ -2875,6 +2934,10 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
if (!on_tty())
return 0;
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2964,10 +3027,36 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
#endif
}
-static int prepare_firmware_setup(sd_bus *bus) {
+static int logind_prepare_firmware_setup(void) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetRebootToFirmwareSetup",
+ &error,
+ NULL,
+ "b", true);
+ if (r < 0)
+ return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Cannot remotely indicate to EFI to boot into setup mode.");
+ return -ENOSYS;
#endif
+}
+
+static int prepare_firmware_setup(void) {
int r;
if (!arg_firmware_setup)
@@ -2982,38 +3071,42 @@ static int prepare_firmware_setup(sd_bus *bus) {
return r;
}
-#ifdef HAVE_LOGIND
+ return logind_prepare_firmware_setup();
+}
+
+static int set_exit_code(uint8_t code) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToFirmwareSetup",
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetExitCode",
&error,
NULL,
- "b", true);
- if (r < 0) {
- log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
- return r;
- }
+ "y", code);
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return 0;
-#else
- log_error("Cannot remotely indicate to EFI to boot into setup mode.");
- return -EINVAL;
-#endif
}
-static int start_special(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+static int start_special(int argc, char *argv[], void *userdata) {
enum action a;
int r;
- assert(args);
+ assert(argv);
- a = verb_to_action(args[0]);
+ a = verb_to_action(argv[0]);
- r = check_inhibitors(bus, a);
+ r = logind_check_inhibitors(a);
if (r < 0)
return r;
@@ -3022,39 +3115,29 @@ static int start_special(sd_bus *bus, char **args) {
return -EPERM;
}
- r = prepare_firmware_setup(bus);
+ r = prepare_firmware_setup();
if (r < 0)
return r;
- if (a == ACTION_REBOOT && args[1]) {
- r = update_reboot_param_file(args[1]);
+ if (a == ACTION_REBOOT && argc > 1) {
+ r = update_reboot_param_file(argv[1]);
if (r < 0)
return r;
- } else if (a == ACTION_EXIT && strv_length(args) > 1) {
- /* If the exit code is not given on the command line, don't
- * reset it to zero: just keep it as it might have been set
- * previously. */
- uint8_t code = 0;
- r = safe_atou8(args[1], &code);
- if (r < 0) {
- log_error("Invalid exit code.");
- return -EINVAL;
- }
+ } else if (a == ACTION_EXIT && argc > 1) {
+ uint8_t code;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetExitCode",
- &error,
- NULL,
- "y", code);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ /* If the exit code is not given on the command line,
+ * don't reset it to zero: just keep it as it might
+ * have been set previously. */
+
+ r = safe_atou8(argv[1], &code);
+ if (r < 0)
+ return log_error_errno(r, "Invalid exit code.");
+
+ r = set_exit_code(code);
+ if (r < 0)
return r;
- }
}
if (arg_force >= 2 &&
@@ -3071,39 +3154,37 @@ static int start_special(sd_bus *bus, char **args) {
ACTION_REBOOT,
ACTION_KEXEC,
ACTION_EXIT))
- return daemon_reload(bus, args);
+ return daemon_reload(argc, argv, userdata);
- /* first try logind, to allow authentication with polkit */
- if (geteuid() != 0 &&
- IN_SET(a,
+ /* First try logind, to allow authentication with polkit */
+ if (IN_SET(a,
ACTION_POWEROFF,
ACTION_REBOOT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP)) {
- r = reboot_with_logind(bus, a);
+ r = logind_reboot(a);
if (r >= 0)
return r;
if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
/* requested operation is not supported or already in progress */
return r;
- /* on all other errors, try low-level operation */
- }
- r = start_unit(bus, args);
- if (r == EXIT_SUCCESS)
- warn_wall(a);
+ /* On all other errors, try low-level operation */
+ }
- return r;
+ return start_unit(argc, argv, userdata);
}
-static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
+static int check_unit_generic(int code, const char *good_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(bus);
- assert(args);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = expand_names(bus, args, NULL, &names);
if (r < 0)
@@ -3122,25 +3203,27 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
return r;
}
-static int check_unit_active(sd_bus *bus, char **args) {
+static int check_unit_active(int argc, char *argv[], void *userdata) {
/* According to LSB: 3, "program is not running" */
- return check_unit_generic(bus, 3, "active\0reloading\0", args + 1);
+ return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1));
}
-static int check_unit_failed(sd_bus *bus, char **args) {
- return check_unit_generic(bus, 1, "failed\0", args + 1);
+static int check_unit_failed(int argc, char *argv[], void *userdata) {
+ return check_unit_generic(1, "failed\0", strv_skip(argv, 1));
}
-static int kill_unit(sd_bus *bus, char **args) {
+static int kill_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
char *kill_who = NULL, **name;
+ sd_bus *bus;
int r, q;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (!arg_kill_who)
arg_kill_who = "all";
@@ -3148,9 +3231,9 @@ static int kill_unit(sd_bus *bus, char **args) {
if (streq(arg_job_mode, "fail"))
kill_who = strjoina(arg_kill_who, "-fail", NULL);
- r = expand_names(bus, args + 1, NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -3165,7 +3248,7 @@ static int kill_unit(sd_bus *bus, char **args) {
NULL,
"ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal);
if (q < 0) {
- log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -3407,7 +3490,8 @@ static void print_status_info(
dir = mfree(dir);
- if (path_get_parent(*dropin, &dir) < 0) {
+ dir = dirname_malloc(*dropin);
+ if (!dir) {
log_oom();
return;
}
@@ -3456,7 +3540,7 @@ static void print_status_info(
printf("Condition: start %scondition failed%s at %s%s%s\n",
ansi_highlight_yellow(), ansi_normal(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_condition_trigger)
printf(" none of the trigger conditions were met\n");
else if (i->failed_condition)
@@ -3472,7 +3556,7 @@ static void print_status_info(
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
ansi_highlight_red(), ansi_normal(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_assert_trigger)
printf(" none of the trigger assertions were met\n");
else if (i->failed_assert)
@@ -3861,13 +3945,13 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
info->name = strdup(name);
if (!info->name)
- log_oom();
+ return log_oom();
LIST_PREPEND(exec, i->exec, info);
info = new0(ExecStatusInfo, 1);
if (!info)
- log_oom();
+ return log_oom();
}
if (r < 0)
@@ -4439,10 +4523,8 @@ static int get_unit_dbus_path_by_pid(
&error,
&reply,
"u", pid);
- if (r < 0) {
- log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &u);
if (r < 0)
@@ -4551,16 +4633,22 @@ static int show_system_status(sd_bus *bus) {
return 0;
}
-static int show(sd_bus *bus, char **args) {
- bool show_properties, show_status, new_line = false;
+static int show(int argc, char *argv[], void *userdata) {
+ bool show_properties, show_status, show_help, new_line = false;
bool ellipsized = false;
int r, ret = 0;
+ sd_bus *bus;
- assert(bus);
- assert(args);
+ assert(argv);
- show_properties = streq(args[0], "show");
- show_status = streq(args[0], "status");
+ show_properties = streq(argv[0], "show");
+ show_status = streq(argv[0], "status");
+ show_help = streq(argv[0], "help");
+
+ if (show_help && argc <= 1) {
+ log_error("This command expects one or more unit names. Did you mean --help?");
+ return -EINVAL;
+ }
if (show_properties)
pager_open_if_enabled();
@@ -4571,24 +4659,27 @@ static int show(sd_bus *bus, char **args) {
* be split up into many files. */
setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
- /* If no argument is specified inspect the manager itself */
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
- if (show_properties && strv_length(args) <= 1)
- return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
+ /* If no argument is specified inspect the manager itself */
+ if (show_properties && argc <= 1)
+ return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
- if (show_status && strv_length(args) <= 1) {
+ if (show_status && argc <= 1) {
pager_open_if_enabled();
show_system_status(bus);
new_line = true;
if (arg_all)
- ret = show_all(args[0], bus, false, &new_line, &ellipsized);
+ ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
} else {
_cleanup_free_ char **patterns = NULL;
char **name;
- STRV_FOREACH(name, args + 1) {
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_free_ char *unit = NULL;
uint32_t id;
@@ -4611,8 +4702,7 @@ static int show(sd_bus *bus, char **args) {
}
}
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4624,7 +4714,7 @@ static int show(sd_bus *bus, char **args) {
r = expand_names(bus, patterns, NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_free_ char *unit;
@@ -4633,8 +4723,7 @@ static int show(sd_bus *bus, char **args) {
if (!unit)
return log_oom();
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4694,19 +4783,18 @@ static int cat_file(const char *filename, bool newline) {
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
}
-static int cat(sd_bus *bus, char **args) {
+static int cat(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
char **name;
- bool first = true, avoid_bus_cache;
+ sd_bus *bus;
+ bool first = true;
int r;
- assert(args);
-
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely cat units");
+ log_error("Cannot remotely cat units.");
return -EINVAL;
}
@@ -4714,11 +4802,13 @@ static int cat(sd_bus *bus, char **args) {
if (r < 0)
return r;
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- return log_error_errno(r, "Failed to expand names: %m");
+ return r;
- avoid_bus_cache = !bus || avoid_bus();
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
pager_open_if_enabled();
@@ -4727,7 +4817,7 @@ static int cat(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **dropin_paths = NULL;
char **path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
+ r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
if (r < 0)
return r;
else if (r == 0)
@@ -4754,15 +4844,20 @@ static int cat(sd_bus *bus, char **args) {
return 0;
}
-static int set_property(sd_bus *bus, char **args) {
+static int set_property(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *n = NULL;
+ sd_bus *bus;
char **i;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -4773,7 +4868,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -4785,7 +4880,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(i, args + 2) {
+ STRV_FOREACH(i, strv_skip(argv, 2)) {
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
if (r < 0)
return bus_log_create_error(r);
@@ -4804,25 +4899,24 @@ static int set_property(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
return 0;
}
-static int snapshot(sd_bus *bus, char **args) {
+static int snapshot(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *n = NULL, *id = NULL;
const char *path;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
- if (strv_length(args) > 1) {
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+ if (argc > 1) {
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
} else {
@@ -4831,6 +4925,10 @@ static int snapshot(sd_bus *bus, char **args) {
return log_oom();
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -4840,10 +4938,8 @@ static int snapshot(sd_bus *bus, char **args) {
&error,
&reply,
"sb", n, false);
- if (r < 0) {
- log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
@@ -4857,10 +4953,8 @@ static int snapshot(sd_bus *bus, char **args) {
"Id",
&error,
&id);
- if (r < 0) {
- log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r));
if (!arg_quiet)
puts(id);
@@ -4868,18 +4962,21 @@ static int snapshot(sd_bus *bus, char **args) {
return 0;
}
-static int delete_snapshot(sd_bus *bus, char **args) {
+static int delete_snapshot(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(args);
-
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, ".snapshot", &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4895,7 +4992,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4904,13 +5001,18 @@ static int delete_snapshot(sd_bus *bus, char **args) {
return r;
}
-static int daemon_reload(sd_bus *bus, char **args) {
+static int daemon_reload(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_RELOAD)
method = "Reload";
else if (arg_action == ACTION_REEXEC)
@@ -4919,15 +5021,15 @@ static int daemon_reload(sd_bus *bus, char **args) {
assert(arg_action == ACTION_SYSTEMCTL);
method =
- streq(args[0], "clear-jobs") ||
- streq(args[0], "cancel") ? "ClearJobs" :
- streq(args[0], "daemon-reexec") ? "Reexecute" :
- streq(args[0], "reset-failed") ? "ResetFailed" :
- streq(args[0], "halt") ? "Halt" :
- streq(args[0], "poweroff") ? "PowerOff" :
- streq(args[0], "reboot") ? "Reboot" :
- streq(args[0], "kexec") ? "KExec" :
- streq(args[0], "exit") ? "Exit" :
+ streq(argv[0], "clear-jobs") ||
+ streq(argv[0], "cancel") ? "ClearJobs" :
+ streq(argv[0], "daemon-reexec") ? "Reexecute" :
+ streq(argv[0], "reset-failed") ? "ResetFailed" :
+ streq(argv[0], "halt") ? "Halt" :
+ streq(argv[0], "poweroff") ? "PowerOff" :
+ streq(argv[0], "reboot") ? "Reboot" :
+ streq(argv[0], "kexec") ? "KExec" :
+ streq(argv[0], "exit") ? "Exit" :
/* "daemon-reload" */ "Reload";
}
@@ -4949,24 +5051,29 @@ static int daemon_reload(sd_bus *bus, char **args) {
* reply */
r = 0;
else if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return r < 0 ? r : 0;
}
-static int reset_failed(sd_bus *bus, char **args) {
+static int reset_failed(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r, q;
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4981,7 +5088,7 @@ static int reset_failed(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4990,14 +5097,19 @@ static int reset_failed(sd_bus *bus, char **args) {
return r;
}
-static int show_environment(sd_bus *bus, char **args) {
+static int show_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *text;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
@@ -5007,10 +5119,8 @@ static int show_environment(sd_bus *bus, char **args) {
&error,
&reply,
"as");
- if (r < 0) {
- log_error("Failed to get environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
if (r < 0)
@@ -5028,23 +5138,27 @@ static int show_environment(sd_bus *bus, char **args) {
return 0;
}
-static int switch_root(sd_bus *bus, char **args) {
+static int switch_root(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *cmdline_init = NULL;
const char *root, *init;
- unsigned l;
+ sd_bus *bus;
int r;
- l = strv_length(args);
- if (l < 2 || l > 3) {
+ if (arg_transport != BUS_TRANSPORT_LOCAL) {
+ log_error("Cannot switch root remotely.");
+ return -EINVAL;
+ }
+
+ if (argc < 2 || argc > 3) {
log_error("Wrong number of arguments.");
return -EINVAL;
}
- root = args[1];
+ root = argv[1];
- if (l >= 3)
- init = args[2];
+ if (argc >= 3)
+ init = argv[2];
else {
r = parse_env_file("/proc/cmdline", WHITESPACE,
"init", &cmdline_init,
@@ -5070,6 +5184,10 @@ static int switch_root(sd_bus *bus, char **args) {
init = NULL;
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
log_debug("Switching root - root: %s; init: %s", root, strna(init));
r = sd_bus_call_method(
@@ -5081,26 +5199,29 @@ static int switch_root(sd_bus *bus, char **args) {
&error,
NULL,
"ss", root, init);
- if (r < 0) {
- log_error("Failed to switch root: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
return 0;
}
-static int set_environment(sd_bus *bus, char **args) {
+static int set_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *method;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
+ assert(argc > 1);
+ assert(argv);
polkit_agent_open_if_enabled();
- method = streq(args[0], "set-environment")
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ method = streq(argv[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
@@ -5114,29 +5235,29 @@ static int set_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_strv(m, args + 1);
+ r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
return 0;
}
-static int import_environment(sd_bus *bus, char **args) {
+static int import_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5147,7 +5268,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- if (strv_isempty(args + 1))
+ if (argc < 2)
r = sd_bus_message_append_strv(m, environ);
else {
char **a, **b;
@@ -5156,7 +5277,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(a, args + 1) {
+ STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a)) {
log_error("Not a valid environment variable name: %s", *a);
@@ -5184,10 +5305,8 @@ static int import_environment(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to import environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
return 0;
}
@@ -5202,6 +5321,9 @@ static int enable_sysv_units(const char *verb, char **args) {
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
+ if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
+ return 0;
+
if (!STR_IN_SET(verb,
"enable",
"disable",
@@ -5290,13 +5412,13 @@ static int enable_sysv_units(const char *verb, char **args) {
(void) reset_signal_mask();
execv(argv[0], (char**) argv);
- log_error("Failed to execute %s: %m", argv[0]);
+ log_error_errno(r, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
j = wait_for_terminate(pid, &status);
if (j < 0) {
- log_error_errno(r, "Failed to wait for child: %m");
+ log_error_errno(j, "Failed to wait for child: %m");
return j;
}
@@ -5366,18 +5488,18 @@ static int mangle_names(char **original_names, char ***mangled_names) {
return 0;
}
-static int enable_unit(sd_bus *bus, char **args) {
+static int enable_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int carries_install_info = -1;
int r;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
@@ -5390,7 +5512,7 @@ static int enable_unit(sd_bus *bus, char **args) {
if (strv_isempty(names))
return 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
if (streq(verb, "enable")) {
r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
carries_install_info = r;
@@ -5426,9 +5548,14 @@ static int enable_unit(sd_bus *bus, char **args) {
int expect_carries_install_info = false;
bool send_force = true, send_preset_mode = false;
const char *method;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (streq(verb, "enable")) {
method = "EnableUnitFiles";
expect_carries_install_info = true;
@@ -5488,10 +5615,8 @@ static int enable_unit(sd_bus *bus, char **args) {
}
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
if (expect_carries_install_info) {
r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5505,7 +5630,7 @@ static int enable_unit(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5521,16 +5646,21 @@ static int enable_unit(sd_bus *bus, char **args) {
"3) A unit may be started when needed via activation (socket, path, timer,\n"
" D-Bus, udev, scripted systemctl call, ...).\n");
- if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+ if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
char *new_args[n_changes + 2];
+ sd_bus *bus;
unsigned i;
- new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
for (i = 0; i < n_changes; i++)
new_args[i + 1] = basename(changes[i].path);
new_args[i + 1] = NULL;
- r = start_unit(bus, new_args);
+ r = start_unit(strv_length(new_args), new_args, userdata);
}
finish:
@@ -5539,21 +5669,21 @@ finish:
return r;
}
-static int add_dependency(sd_bus *bus, char **args) {
+static int add_dependency(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_free_ char *target = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitDependency dep;
int r = 0;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- r = mangle_names(args+2, &names);
+ r = mangle_names(strv_skip(argv, 2), &names);
if (r < 0)
return r;
@@ -5564,7 +5694,7 @@ static int add_dependency(sd_bus *bus, char **args) {
else
assert_not_reached("Unknown verb");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
@@ -5581,9 +5711,14 @@ static int add_dependency(sd_bus *bus, char **args) {
} else {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5603,17 +5738,15 @@ static int add_dependency(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5621,12 +5754,12 @@ static int add_dependency(sd_bus *bus, char **args) {
return r;
}
-static int preset_all(sd_bus *bus, char **args) {
+static int preset_all(int argc, char *argv[], void *userdata) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
if (r < 0) {
@@ -5642,9 +5775,14 @@ static int preset_all(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5657,17 +5795,15 @@ static int preset_all(sd_bus *bus, char **args) {
unit_file_preset_mode_to_string(arg_preset_mode),
arg_runtime,
arg_force);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5678,25 +5814,24 @@ finish:
return r;
}
-static int unit_is_enabled(sd_bus *bus, char **args) {
+static int unit_is_enabled(int argc, char *argv[], void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
bool enabled;
char **name;
int r;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
- r = enable_sysv_units(args[0], names);
+ r = enable_sysv_units(argv[0], names);
if (r < 0)
return r;
enabled = r > 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
STRV_FOREACH(name, names) {
UnitFileState state;
@@ -5717,6 +5852,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
}
} else {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *s;
@@ -5730,10 +5872,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
&error,
&reply,
"s", *name);
- if (r < 0) {
- log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &s);
if (r < 0)
@@ -5750,10 +5890,21 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
return !enabled;
}
-static int is_system_running(sd_bus *bus, char **args) {
+static int is_system_running(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *state = NULL;
+ sd_bus *bus;
int r;
+ if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) {
+ if (!arg_quiet)
+ puts("offline");
+ return EXIT_FAILURE;
+ }
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
@@ -5775,7 +5926,7 @@ static int is_system_running(sd_bus *bus, char **args) {
}
static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
- char *t;
+ _cleanup_free_ char *t = NULL;
int r;
assert(new_path);
@@ -5787,27 +5938,21 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
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;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
r = copy_file(original_path, t, 0, 0644, 0);
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;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
*ret_tmp_fn = t;
+ t = NULL;
return 0;
}
@@ -5815,6 +5960,9 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
_cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
+ assert(name);
+ assert(ret_path);
+
switch (arg_scope) {
case UNIT_FILE_SYSTEM:
path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
@@ -5845,12 +5993,16 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return log_oom();
if (arg_runtime) {
- if (access(path, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path);
- if (path2 && access(path2, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path2);
+ if (access(path, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
+ return -EEXIST;
+ }
+
+ if (path2 && access(path2, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
+ return -EEXIST;
+ }
+
*ret_path = run;
run = NULL;
} else {
@@ -5862,8 +6014,7 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
}
static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
- char *tmp_new_path, *ending;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path, *ending;
int r;
assert(unit_name);
@@ -5895,8 +6046,7 @@ static int unit_file_create_copy(
char **ret_new_path,
char **ret_tmp_path) {
- char *tmp_new_path;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path;
int r;
assert(fragment_path);
@@ -5943,10 +6093,8 @@ static int run_editor(char **paths) {
assert(paths);
pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
- return -errno;
- }
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
if (pid == 0) {
const char **args;
@@ -6004,7 +6152,7 @@ static int run_editor(char **paths) {
* failing.
*/
if (errno != ENOENT) {
- log_error("Failed to execute %s: %m", editor);
+ log_error_errno(errno, "Failed to execute %s: %m", editor);
_exit(EXIT_FAILURE);
}
}
@@ -6017,14 +6165,13 @@ static int run_editor(char **paths) {
if (r < 0)
return log_error_errno(r, "Failed to wait for child: %m");
- return r;
+ return 0;
}
static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
- bool avoid_bus_cache;
char **name;
int r;
@@ -6035,13 +6182,11 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
if (r < 0)
return r;
- avoid_bus_cache = !bus || avoid_bus();
-
STRV_FOREACH(name, names) {
_cleanup_free_ char *path = NULL;
char *new_path, *tmp_path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
+ r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
return r;
else if (r == 0)
@@ -6067,25 +6212,28 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
return 0;
}
-static int edit(sd_bus *bus, char **args) {
+static int edit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_strv_free_ char **paths = NULL;
char **original, **tmp;
+ sd_bus *bus;
int r;
- assert(args);
-
if (!on_tty()) {
- log_error("Cannot edit units if not on a tty");
+ log_error("Cannot edit units if not on a tty.");
return -EINVAL;
}
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely edit units");
+ log_error("Cannot edit units remotely.");
return -EINVAL;
}
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
@@ -6101,13 +6249,14 @@ static int edit(sd_bus *bus, char **args) {
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 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("Editing \"%s\" canceled: temporary file is empty", *original);
+ log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
continue;
}
+
r = rename(*tmp, *original);
if (r < 0) {
r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
@@ -6115,12 +6264,14 @@ static int edit(sd_bus *bus, char **args) {
}
}
- if (!arg_no_reload && bus && !avoid_bus())
- r = daemon_reload(bus, args);
+ r = 0;
+
+ if (!arg_no_reload && !install_client_side())
+ r = daemon_reload(argc, argv, userdata);
end:
STRV_FOREACH_PAIR(original, tmp, paths)
- unlink_noerrno(*tmp);
+ (void) unlink(*tmp);
return r;
}
@@ -6314,15 +6465,90 @@ static void runlevel_help(void) {
static void help_types(void) {
int i;
- const char *t;
if (!arg_no_legend)
puts("Available unit types:");
- for (i = 0; i < _UNIT_TYPE_MAX; i++) {
- t = unit_type_to_string(i);
- if (t)
- puts(t);
- }
+ for (i = 0; i < _UNIT_TYPE_MAX; i++)
+ puts(unit_type_to_string(i));
+}
+
+static void help_states(void) {
+ int i;
+
+ if (!arg_no_legend)
+ puts("Available unit load states:");
+ for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
+ puts(unit_load_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable unit active states:");
+ for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
+ puts(unit_active_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable automount unit substates:");
+ for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
+ puts(automount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable busname unit substates:");
+ for (i = 0; i < _BUSNAME_STATE_MAX; i++)
+ puts(busname_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable device unit substates:");
+ for (i = 0; i < _DEVICE_STATE_MAX; i++)
+ puts(device_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable mount unit substates:");
+ for (i = 0; i < _MOUNT_STATE_MAX; i++)
+ puts(mount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable path unit substates:");
+ for (i = 0; i < _PATH_STATE_MAX; i++)
+ puts(path_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable scope unit substates:");
+ for (i = 0; i < _SCOPE_STATE_MAX; i++)
+ puts(scope_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable service unit substates:");
+ for (i = 0; i < _SERVICE_STATE_MAX; i++)
+ puts(service_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable slice unit substates:");
+ for (i = 0; i < _SLICE_STATE_MAX; i++)
+ puts(slice_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable snapshot unit substates:");
+ for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
+ puts(snapshot_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable socket unit substates:");
+ for (i = 0; i < _SOCKET_STATE_MAX; i++)
+ puts(socket_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable swap unit substates:");
+ for (i = 0; i < _SWAP_STATE_MAX; i++)
+ puts(swap_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable target unit substates:");
+ for (i = 0; i < _TARGET_STATE_MAX; i++)
+ puts(target_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable timer unit substates:");
+ for (i = 0; i < _TIMER_STATE_MAX; i++)
+ puts(timer_state_to_string(i));
}
static int systemctl_parse_argv(int argc, char *argv[]) {
@@ -6405,7 +6631,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{}
};
- int c;
+ const char *p;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -6422,20 +6649,22 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 't': {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--type requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- _cleanup_free_ char *type;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *type = NULL;
- type = strndup(word, size);
- if (!type)
- return -ENOMEM;
+ r = extract_first_word(&p, &type, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse type: %s", optarg);
+
+ if (r == 0)
+ break;
if (streq(type, "help")) {
help_types();
@@ -6443,7 +6672,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
if (unit_type_from_string(type) >= 0) {
- if (strv_push(&arg_types, type))
+ if (strv_push(&arg_types, type) < 0)
return log_oom();
type = NULL;
continue;
@@ -6453,7 +6682,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
* load states, but let's support this
* in --types= too for compatibility
* with old versions */
- if (unit_load_state_from_string(optarg) >= 0) {
+ if (unit_load_state_from_string(type) >= 0) {
if (strv_push(&arg_states, type) < 0)
return log_oom();
type = NULL;
@@ -6476,18 +6705,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
if (!arg_properties)
return log_oom();
} else {
- const char *word, *state;
- size_t size;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *prop = NULL;
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *prop;
+ r = extract_first_word(&p, &prop, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse property: %s", optarg);
- prop = strndup(word, size);
- if (!prop)
- return log_oom();
+ if (r == 0)
+ break;
- if (strv_consume(&arg_properties, prop) < 0)
+ if (strv_push(&arg_properties, prop) < 0)
return log_oom();
+
+ prop = NULL;
}
}
@@ -6564,7 +6796,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- arg_root = optarg;
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case 'l':
@@ -6598,7 +6832,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case 's':
- if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
+ arg_signal = signal_from_string_try_harder(optarg);
+ if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
@@ -6650,18 +6885,29 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_STATE: {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--signal requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *s;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *s = NULL;
- s = strndup(word, size);
- if (!s)
- return log_oom();
+ r = extract_first_word(&p, &s, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse signal: %s", optarg);
+
+ if (r == 0)
+ break;
+
+ if (streq(s, "help")) {
+ help_states();
+ return 0;
+ }
- if (strv_consume(&arg_states, s) < 0)
+ if (strv_push(&arg_states, s) < 0)
return log_oom();
+
+ s = NULL;
}
break;
}
@@ -6800,7 +7046,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
return 1;
}
-static int parse_time_spec(const char *t, usec_t *_u) {
+static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
assert(t);
assert(_u);
@@ -6866,12 +7112,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
{}
};
+ char **wall = NULL;
int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
switch (c) {
case ARG_HELP:
@@ -6929,7 +7176,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
}
if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
- r = parse_time_spec(argv[optind], &arg_when);
+ r = parse_shutdown_time_spec(argv[optind], &arg_when);
if (r < 0) {
log_error("Failed to parse time specification: %s", argv[optind]);
return r;
@@ -6939,10 +7186,16 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
/* No time argument for shutdown cancel */
- arg_wall = argv + optind;
+ wall = argv + optind;
else if (argc > optind + 1)
/* We skip the time argument */
- arg_wall = argv + optind + 1;
+ wall = argv + optind + 1;
+
+ if (wall) {
+ arg_wall = strv_copy(wall);
+ if (!arg_wall)
+ return log_oom();
+ }
optind = argc;
@@ -7006,8 +7259,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
}
if (optind >= argc) {
- log_error("%s: required argument missing.",
- program_invocation_short_name);
+ log_error("%s: required argument missing.", program_invocation_short_name);
return -EINVAL;
}
@@ -7142,7 +7394,7 @@ _pure_ static int action_to_runlevel(void) {
}
static int talk_initctl(void) {
-
+#ifdef HAVE_SYSV_COMPAT
struct init_request request = {
.magic = INIT_MAGIC,
.sleeptime = 0,
@@ -7164,8 +7416,7 @@ static int talk_initctl(void) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
}
r = loop_write(fd, &request, sizeof(request), false);
@@ -7173,177 +7424,91 @@ static int talk_initctl(void) {
return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
return 1;
+#else
+ return 0;
+#endif
}
-static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
-
- static const struct {
- const char* verb;
- const enum {
- MORE,
- LESS,
- EQUAL
- } argc_cmp;
- const int argc;
- int (* const dispatch)(sd_bus *bus, char **args);
- const enum {
- NOBUS = 1,
- FORCE,
- } bus;
- } verbs[] = {
- { "list-units", MORE, 0, list_units },
- { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
- { "list-sockets", MORE, 1, list_sockets },
- { "list-timers", MORE, 1, list_timers },
- { "list-jobs", MORE, 1, list_jobs },
- { "list-machines", MORE, 1, list_machines },
- { "clear-jobs", EQUAL, 1, daemon_reload },
- { "cancel", MORE, 2, cancel_job },
- { "start", MORE, 2, start_unit },
- { "stop", MORE, 2, start_unit },
- { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "reload", MORE, 2, start_unit },
- { "restart", MORE, 2, start_unit },
- { "try-restart", MORE, 2, start_unit },
- { "reload-or-restart", MORE, 2, start_unit },
- { "reload-or-try-restart", MORE, 2, start_unit },
- { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
- { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
- { "isolate", EQUAL, 2, start_unit },
- { "kill", MORE, 2, kill_unit },
- { "is-active", MORE, 2, check_unit_active },
- { "check", MORE, 2, check_unit_active },
- { "is-failed", MORE, 2, check_unit_failed },
- { "show", MORE, 1, show },
- { "cat", MORE, 2, cat, NOBUS },
- { "status", MORE, 1, show },
- { "help", MORE, 2, show },
- { "snapshot", LESS, 2, snapshot },
- { "delete", MORE, 2, delete_snapshot },
- { "daemon-reload", EQUAL, 1, daemon_reload },
- { "daemon-reexec", EQUAL, 1, daemon_reload },
- { "show-environment", EQUAL, 1, show_environment },
- { "set-environment", MORE, 2, set_environment },
- { "unset-environment", MORE, 2, set_environment },
- { "import-environment", MORE, 1, import_environment},
- { "halt", EQUAL, 1, start_special, FORCE },
- { "poweroff", EQUAL, 1, start_special, FORCE },
- { "reboot", MORE, 1, start_special, FORCE },
- { "kexec", EQUAL, 1, start_special },
- { "suspend", EQUAL, 1, start_special },
- { "hibernate", EQUAL, 1, start_special },
- { "hybrid-sleep", EQUAL, 1, start_special },
- { "default", EQUAL, 1, start_special },
- { "rescue", EQUAL, 1, start_special },
- { "emergency", EQUAL, 1, start_special },
- { "exit", LESS, 2, start_special },
- { "reset-failed", MORE, 1, reset_failed },
- { "enable", MORE, 2, enable_unit, NOBUS },
- { "disable", MORE, 2, enable_unit, NOBUS },
- { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
- { "reenable", MORE, 2, enable_unit, NOBUS },
- { "preset", MORE, 2, enable_unit, NOBUS },
- { "preset-all", EQUAL, 1, preset_all, NOBUS },
- { "mask", MORE, 2, enable_unit, NOBUS },
- { "unmask", MORE, 2, enable_unit, NOBUS },
- { "link", MORE, 2, enable_unit, NOBUS },
- { "switch-root", MORE, 2, switch_root },
- { "list-dependencies", LESS, 2, list_dependencies },
- { "set-default", EQUAL, 2, set_default, NOBUS },
- { "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 },
- { "edit", MORE, 2, edit, NOBUS },
+static int systemctl_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units },
+ { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
+ { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets },
+ { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers },
+ { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs },
+ { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines },
+ { "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
+ { "cancel", 2, VERB_ANY, 0, cancel_job },
+ { "start", 2, VERB_ANY, 0, start_unit },
+ { "stop", 2, VERB_ANY, 0, start_unit },
+ { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "reload", 2, VERB_ANY, 0, start_unit },
+ { "restart", 2, VERB_ANY, 0, start_unit },
+ { "try-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit },
+ { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */
+ { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */
+ { "isolate", 2, 2, 0, start_unit },
+ { "kill", 2, VERB_ANY, 0, kill_unit },
+ { "is-active", 2, VERB_ANY, 0, check_unit_active },
+ { "check", 2, VERB_ANY, 0, check_unit_active },
+ { "is-failed", 2, VERB_ANY, 0, check_unit_failed },
+ { "show", VERB_ANY, VERB_ANY, 0, show },
+ { "cat", 2, VERB_ANY, 0, cat },
+ { "status", VERB_ANY, VERB_ANY, 0, show },
+ { "help", VERB_ANY, VERB_ANY, 0, show },
+ { "snapshot", VERB_ANY, 2, 0, snapshot },
+ { "delete", 2, VERB_ANY, 0, delete_snapshot },
+ { "daemon-reload", VERB_ANY, 1, 0, daemon_reload },
+ { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload },
+ { "show-environment", VERB_ANY, 1, 0, show_environment },
+ { "set-environment", 2, VERB_ANY, 0, set_environment },
+ { "unset-environment", 2, VERB_ANY, 0, set_environment },
+ { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment},
+ { "halt", VERB_ANY, 1, 0, start_special },
+ { "poweroff", VERB_ANY, 1, 0, start_special },
+ { "reboot", VERB_ANY, 2, 0, start_special },
+ { "kexec", VERB_ANY, 1, 0, start_special },
+ { "suspend", VERB_ANY, 1, 0, start_special },
+ { "hibernate", VERB_ANY, 1, 0, start_special },
+ { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
+ { "default", VERB_ANY, 1, 0, start_special },
+ { "rescue", VERB_ANY, 1, 0, start_special },
+ { "emergency", VERB_ANY, 1, 0, start_special },
+ { "exit", VERB_ANY, 2, 0, start_special },
+ { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed },
+ { "enable", 2, VERB_ANY, 0, enable_unit },
+ { "disable", 2, VERB_ANY, 0, enable_unit },
+ { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
+ { "reenable", 2, VERB_ANY, 0, enable_unit },
+ { "preset", 2, VERB_ANY, 0, enable_unit },
+ { "preset-all", VERB_ANY, 1, 0, preset_all },
+ { "mask", 2, VERB_ANY, 0, enable_unit },
+ { "unmask", 2, VERB_ANY, 0, enable_unit },
+ { "link", 2, VERB_ANY, 0, enable_unit },
+ { "switch-root", 2, VERB_ANY, 0, switch_root },
+ { "list-dependencies", VERB_ANY, 2, 0, list_dependencies },
+ { "set-default", 2, 2, 0, set_default },
+ { "get-default", VERB_ANY, 1, 0, get_default, },
+ { "set-property", 3, VERB_ANY, 0, set_property },
+ { "is-system-running", VERB_ANY, 1, 0, is_system_running },
+ { "add-wants", 3, VERB_ANY, 0, add_dependency },
+ { "add-requires", 3, VERB_ANY, 0, add_dependency },
+ { "edit", 2, VERB_ANY, 0, edit },
{}
- }, *verb = verbs;
-
- int left;
-
- assert(argc >= 0);
- assert(argv);
-
- left = argc - optind;
-
- /* Special rule: no arguments (left == 0) means "list-units" */
- if (left > 0) {
- if (streq(argv[optind], "help") && !argv[optind+1]) {
- log_error("This command expects one or more "
- "unit names. Did you mean --help?");
- return -EINVAL;
- }
-
- for (; verb->verb; verb++)
- if (streq(argv[optind], verb->verb))
- goto found;
-
- log_error("Unknown operation '%s'.", argv[optind]);
- return -EINVAL;
- }
-found:
-
- switch (verb->argc_cmp) {
-
- case EQUAL:
- if (left != verb->argc) {
- log_error("Invalid number of arguments.");
- return -EINVAL;
- }
-
- break;
-
- case MORE:
- if (left < verb->argc) {
- log_error("Too few arguments.");
- return -EINVAL;
- }
-
- break;
-
- case LESS:
- if (left > verb->argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
-
- break;
-
- default:
- assert_not_reached("Unknown comparison operator.");
- }
-
- /* Require a bus connection for all operations but
- * enable/disable */
- if (verb->bus == NOBUS) {
- if (!bus && !avoid_bus()) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
-
- } else {
- if (running_in_chroot() > 0) {
- log_info("Running in chroot, ignoring request.");
- return 0;
- }
-
- if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
- }
+ };
- return verb->dispatch(bus, argv + optind);
+ return dispatch_verb(argc, argv, verbs, NULL);
}
-static int reload_with_fallback(sd_bus *bus) {
+static int reload_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (daemon_reload(bus, NULL) >= 0)
- return 0;
- }
+ /* First, try systemd via D-Bus. */
+ if (daemon_reload(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try signals */
assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
@@ -7354,25 +7519,19 @@ static int reload_with_fallback(sd_bus *bus) {
return 0;
}
-static int start_with_fallback(sd_bus *bus) {
+static int start_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (start_unit(bus, NULL) >= 0)
- goto done;
- }
+ /* First, try systemd via D-Bus. */
+ if (start_unit(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try
* /dev/initctl */
if (talk_initctl() > 0)
- goto done;
+ return 0;
log_error("Failed to talk to init daemon.");
return -EIO;
-
-done:
- warn_wall(arg_action);
- return 0;
}
static int halt_now(enum action a) {
@@ -7380,22 +7539,22 @@ static int halt_now(enum action a) {
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
* explicitly in advance. */
- sync();
+ (void) sync();
/* Make sure C-A-D is handled by the kernel from this point
* on... */
- reboot(RB_ENABLE_CAD);
+ (void) reboot(RB_ENABLE_CAD);
switch (a) {
case ACTION_HALT:
log_info("Halting.");
- reboot(RB_HALT_SYSTEM);
+ (void) reboot(RB_HALT_SYSTEM);
return -errno;
case ACTION_POWEROFF:
log_info("Powering off.");
- reboot(RB_POWER_OFF);
+ (void) reboot(RB_POWER_OFF);
return -errno;
case ACTION_KEXEC:
@@ -7404,12 +7563,11 @@ static int halt_now(enum action a) {
if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
log_info("Rebooting with argument '%s'.", param);
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, param);
+ (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
}
log_info("Rebooting.");
- reboot(RB_AUTOBOOT);
+ (void) reboot(RB_AUTOBOOT);
return -errno;
}
@@ -7418,17 +7576,77 @@ static int halt_now(enum action a) {
}
}
-static int halt_main(sd_bus *bus) {
+static int logind_schedule_shutdown(void) {
+
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char date[FORMAT_TIMESTAMP_MAX];
+ const char *action;
+ sd_bus *bus;
int r;
- r = check_inhibitors(bus, arg_action);
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
+ switch (arg_action) {
+ case ACTION_HALT:
+ action = "halt";
+ break;
+ case ACTION_POWEROFF:
+ action = "poweroff";
+ break;
+ case ACTION_KEXEC:
+ action = "kexec";
+ break;
+ case ACTION_EXIT:
+ action = "exit";
+ break;
+ case ACTION_REBOOT:
+ default:
+ action = "reboot";
+ break;
+ }
+
+ if (arg_dry)
+ action = strjoina("dry-", action);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ScheduleShutdown",
+ &error,
+ NULL,
+ "st",
+ action,
+ arg_when);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
+
+ log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
+ return 0;
+#else
+ log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
+ return -ENOSYS;
+#endif
+}
+
+static int halt_main(void) {
+ int r;
+
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
+
+ if (arg_when > 0)
+ return logind_schedule_shutdown();
+
if (geteuid() != 0) {
- if (arg_when > 0 ||
- arg_dry ||
- arg_force > 0) {
+ if (arg_dry || arg_force > 0) {
log_error("Must be root.");
return -EPERM;
}
@@ -7436,101 +7654,21 @@ static int halt_main(sd_bus *bus) {
/* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown
* the machine. */
- if (IN_SET(arg_action,
- ACTION_POWEROFF,
- ACTION_REBOOT)) {
- r = reboot_with_logind(bus, arg_action);
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
+ r = logind_reboot(arg_action);
if (r >= 0)
return r;
if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not supported or already in progress */
+ /* requested operation is not
+ * supported on the local system or
+ * already in progress */
return r;
/* on all other errors, try low-level operation */
}
}
- if (arg_when > 0) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
- const char *action;
-
- assert(geteuid() == 0);
-
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
-
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
-
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
-
- switch (arg_action) {
- case ACTION_HALT:
- action = "halt";
- break;
- case ACTION_POWEROFF:
- action = "poweroff";
- break;
- case ACTION_KEXEC:
- action = "kexec";
- break;
- default:
- action = "reboot";
- break;
- }
-
- if (arg_dry)
- action = strjoina("dry-", action);
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ScheduleShutdown",
- &error,
- NULL,
- "st",
- action,
- arg_when);
- if (r < 0)
- log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
- bus_error_message(&error, r));
- else {
- char date[FORMAT_TIMESTAMP_MAX];
-
- log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
- format_timestamp(date, sizeof(date), arg_when));
- return 0;
- }
- }
-
if (!arg_dry && !arg_force)
- return start_with_fallback(bus);
+ return start_with_fallback();
assert(geteuid() == 0);
@@ -7548,9 +7686,7 @@ static int halt_main(sd_bus *bus) {
return 0;
r = halt_now(arg_action);
- log_error_errno(r, "Failed to reboot: %m");
-
- return r;
+ return log_error_errno(r, "Failed to reboot: %m");
}
static int runlevel_main(void) {
@@ -7569,8 +7705,37 @@ static int runlevel_main(void) {
return 0;
}
+static int logind_cancel_shutdown(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ (void) logind_set_wall_message();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CancelScheduledShutdown",
+ &error,
+ NULL, NULL);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
+ return -ENOSYS;
+#endif
+}
+
int main(int argc, char*argv[]) {
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
@@ -7586,39 +7751,26 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- /* /sbin/runlevel doesn't need to communicate via D-Bus, so
- * let's shortcut this */
- if (arg_action == ACTION_RUNLEVEL) {
- r = runlevel_main();
- goto finish;
- }
-
if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
log_info("Running in chroot, ignoring request.");
r = 0;
goto finish;
}
- if (!avoid_bus())
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
-
- if (bus)
- sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
-
/* systemctl_main() will print an error message for the bus
* connection, but only if it needs to */
switch (arg_action) {
case ACTION_SYSTEMCTL:
- r = systemctl_main(bus, argc, argv, r);
+ r = systemctl_main(argc, argv);
break;
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
case ACTION_KEXEC:
- r = halt_main(bus);
+ r = halt_main();
break;
case ACTION_RUNLEVEL2:
@@ -7628,69 +7780,22 @@ int main(int argc, char*argv[]) {
case ACTION_RESCUE:
case ACTION_EMERGENCY:
case ACTION_DEFAULT:
- r = start_with_fallback(bus);
+ r = start_with_fallback();
break;
case ACTION_RELOAD:
case ACTION_REEXEC:
- r = reload_with_fallback(bus);
+ r = reload_with_fallback();
break;
- case ACTION_CANCEL_SHUTDOWN: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
-
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
-
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
-
- if (arg_wall) {
- m = strv_join(arg_wall, " ");
- if (!m) {
- r = log_oom();
- goto finish;
- }
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CancelScheduledShutdown",
- &error,
- NULL, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
- bus_error_message(&error, r));
+ case ACTION_CANCEL_SHUTDOWN:
+ r = logind_cancel_shutdown();
break;
- }
case ACTION_RUNLEVEL:
+ r = runlevel_main();
+ break;
+
case _ACTION_INVALID:
default:
assert_not_reached("Unknown action");
@@ -7705,7 +7810,10 @@ finish:
strv_free(arg_states);
strv_free(arg_properties);
- sd_bus_default_flush_close();
+ strv_free(arg_wall);
+ free(arg_root);
+
+ release_busses();
return r < 0 ? EXIT_FAILURE : r;
}
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 0883203ae7..43cf247cdf 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -420,7 +420,9 @@ int sd_bus_error_add_map(const sd_bus_error_map *map);
/* Label escaping */
int sd_bus_path_encode(const char *prefix, const char *external_id, char **ret_path);
+int sd_bus_path_encode_many(char **out, const char *path_template, ...);
int sd_bus_path_decode(const char *path, const char *prefix, char **ret_external_id);
+int sd_bus_path_decode_many(const char *path, const char *path_template, ...);
/* Tracking peers */
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index 861dc8f1f4..214e77cab1 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -76,6 +76,8 @@ _SD_BEGIN_DECLARATIONS;
*/
int sd_listen_fds(int unset_environment);
+int sd_listen_fds_with_names(int unset_environment, char ***names);
+
/*
Helper call for identifying a passed file descriptor. Returns 1 if
the file descriptor is a FIFO in the file system stored under the
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index 38cb2a1102..fc11725821 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -24,7 +24,7 @@
***/
#include <sys/types.h>
-#include <stdint.h>
+#include <inttypes.h>
#include "_sd-common.h"
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 4291fb7ebc..c0146158f3 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -22,12 +22,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/in.h>
+#include <inttypes.h>
#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
#include "sd-event.h"
#include "sd-dhcp-lease.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
enum {
SD_DHCP_CLIENT_EVENT_STOP = 0,
SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
@@ -72,4 +78,6 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h
index ed5bceecdd..38222594e7 100644
--- a/src/systemd/sd-dhcp-lease.h
+++ b/src/systemd/sd-dhcp-lease.h
@@ -23,8 +23,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <netinet/in.h>
+#include <inttypes.h>
#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp_lease sd_dhcp_lease;
struct sd_dhcp_route;
@@ -52,4 +58,6 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len);
int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h
index 4b0c7a1852..55bceb1ea5 100644
--- a/src/systemd/sd-dhcp-server.h
+++ b/src/systemd/sd-dhcp-server.h
@@ -23,10 +23,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
+#include <inttypes.h>
#include <netinet/in.h>
#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
typedef struct sd_dhcp_server sd_dhcp_server;
@@ -39,7 +42,7 @@ int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int pri
int sd_dhcp_server_detach_event(sd_dhcp_server *client);
sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
-bool sd_dhcp_server_is_running(sd_dhcp_server *server);
+int sd_dhcp_server_is_running(sd_dhcp_server *server);
int sd_dhcp_server_start(sd_dhcp_server *server);
int sd_dhcp_server_stop(sd_dhcp_server *server);
@@ -55,4 +58,6 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
int sd_dhcp_server_forcerenew(sd_dhcp_server *server);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index 90c35ef3f6..13182a481d 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -22,12 +22,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
#include <net/ethernet.h>
+#include <sys/types.h>
#include "sd-event.h"
-
#include "sd-dhcp6-lease.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
enum {
SD_DHCP6_CLIENT_EVENT_STOP = 0,
SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
@@ -48,10 +53,8 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
size_t addr_len, uint16_t arp_type);
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
size_t duid_len);
-int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client,
- bool enabled);
-int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client,
- bool *enabled);
+int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled);
+int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled);
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client,
uint16_t option);
@@ -67,4 +70,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client);
int sd_dhcp6_client_new(sd_dhcp6_client **ret);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h
index dc3df3bbf7..3fc0ee4bed 100644
--- a/src/systemd/sd-dhcp6-lease.h
+++ b/src/systemd/sd-dhcp6-lease.h
@@ -23,8 +23,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
#include <netinet/in.h>
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
@@ -42,4 +47,6 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-hwdb.h b/src/systemd/sd-hwdb.h
index 3c44b981d6..49269a073a 100644
--- a/src/systemd/sd-hwdb.h
+++ b/src/systemd/sd-hwdb.h
@@ -39,9 +39,11 @@ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char
int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias);
int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value);
-/* the inverse condition avoids ambiguity of danling 'else' after the macro */
+/* the inverse condition avoids ambiguity of dangling 'else' after the macro */
#define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) \
if (sd_hwdb_seek(hwdb, modalias) < 0) { } \
else while (sd_hwdb_enumerate(hwdb, &(key), &(value)) > 0)
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h
deleted file mode 100644
index cb6c24a0cb..0000000000
--- a/src/systemd/sd-icmp6-nd.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdicmp6ndfoo
-#define foosdicmp6ndfoo
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Intel Corporation. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <net/ethernet.h>
-
-#include "sd-event.h"
-
-enum {
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
- SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
-};
-
-typedef struct sd_icmp6_nd sd_icmp6_nd;
-
-typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event,
- void *userdata);
-
-int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb,
- void *userdata);
-int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index);
-int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr);
-
-int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority);
-int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd);
-sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd);
-
-sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd);
-sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd);
-int sd_icmp6_nd_new(sd_icmp6_nd **ret);
-
-int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen,
- struct in6_addr *addr);
-
-int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu);
-int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr,
- uint8_t *prefixlen);
-int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr,
- uint8_t *prefixlen);
-
-int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
-int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
-
-#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-
-#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \
- be16toh((address).s6_addr16[0]), \
- be16toh((address).s6_addr16[1]), \
- be16toh((address).s6_addr16[2]), \
- be16toh((address).s6_addr16[3]), \
- be16toh((address).s6_addr16[4]), \
- be16toh((address).s6_addr16[5]), \
- be16toh((address).s6_addr16[6]), \
- be16toh((address).s6_addr16[7])
-
-#endif
diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h
index adcb2c7b92..6337d61452 100644
--- a/src/systemd/sd-ipv4acd.h
+++ b/src/systemd/sd-ipv4acd.h
@@ -23,11 +23,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
enum {
SD_IPV4ACD_EVENT_STOP = 0,
@@ -45,11 +47,13 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
-bool sd_ipv4acd_is_running(sd_ipv4acd *ll);
+int sd_ipv4acd_is_running(sd_ipv4acd *ll);
int sd_ipv4acd_start(sd_ipv4acd *ll);
int sd_ipv4acd_stop(sd_ipv4acd *ll);
sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
int sd_ipv4acd_new (sd_ipv4acd **ret);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index 677505f0c6..2949f1dfb2 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -22,11 +22,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
enum {
SD_IPV4LL_EVENT_STOP = 0,
@@ -43,12 +45,15 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
-bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
+int sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll);
int sd_ipv4ll_stop(sd_ipv4ll *ll);
sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll);
sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll);
int sd_ipv4ll_new (sd_ipv4ll **ret);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index 0680e526b0..31651ce132 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -1,5 +1,8 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+#ifndef foosdlldphfoo
+#define foosdlldphfoo
+
/***
This file is part of systemd.
@@ -20,15 +23,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
+#include <net/ethernet.h>
+#include <inttypes.h>
#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
enum {
SD_LLDP_EVENT_UPDATE_INFO = 0,
};
+enum {
+ SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE,
+ SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE,
+ SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE,
+};
+
typedef struct sd_lldp sd_lldp;
+typedef struct sd_lldp_packet sd_lldp_packet;
typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
@@ -43,3 +57,29 @@ int sd_lldp_detach_event(sd_lldp *lldp);
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata);
int sd_lldp_save(sd_lldp *lldp, const char *file);
+
+int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
+int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
+int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl);
+int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length);
+int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
+int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data);
+int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
+
+/* IEEE 802.1 organizationally specific TLVs */
+int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id);
+int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id);
+int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length);
+int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id);
+int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id);
+
+sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv);
+sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
+
+int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
+
+int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
new file mode 100644
index 0000000000..570e1741d6
--- /dev/null
+++ b/src/systemd/sd-ndisc.h
@@ -0,0 +1,77 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdndiscfoo
+#define foosdndiscfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Intel Corporation. All rights reserved.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <net/ethernet.h>
+
+#include "sd-event.h"
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
+enum {
+ SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
+ SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
+ SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
+ SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
+};
+
+typedef struct sd_ndisc sd_ndisc;
+
+typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event,
+ void *userdata);
+
+int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb,
+ void *userdata);
+int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
+int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
+
+int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
+int sd_ndisc_detach_event(sd_ndisc *nd);
+sd_event *sd_ndisc_get_event(sd_ndisc *nd);
+
+sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
+sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
+int sd_ndisc_new(sd_ndisc **ret);
+
+int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu);
+
+int sd_ndisc_stop(sd_ndisc *nd);
+int sd_ndisc_router_discovery_start(sd_ndisc *nd);
+
+#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+
+#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \
+ be16toh((address).s6_addr16[0]), \
+ be16toh((address).s6_addr16[1]), \
+ be16toh((address).s6_addr16[2]), \
+ be16toh((address).s6_addr16[3]), \
+ be16toh((address).s6_addr16[4]), \
+ be16toh((address).s6_addr16[5]), \
+ be16toh((address).s6_addr16[6]), \
+ be16toh((address).s6_addr16[7])
+
+_SD_END_DECLARATIONS;
+
+#endif
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index cb462bf48f..8e1b06ee9a 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -104,6 +104,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump);
int sd_netlink_message_is_error(sd_netlink_message *m);
int sd_netlink_message_get_errno(sd_netlink_message *m);
int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type);
+int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags);
int sd_netlink_message_is_broadcast(sd_netlink_message *m);
/* rtnl */
@@ -136,6 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
diff --git a/src/systemd/sd-path.h b/src/systemd/sd-path.h
index e238c0ce20..3280303633 100644
--- a/src/systemd/sd-path.h
+++ b/src/systemd/sd-path.h
@@ -24,6 +24,10 @@
#include <inttypes.h>
+#include "_sd-common.h"
+
+_SD_BEGIN_DECLARATIONS;
+
enum {
/* Temporary files */
SD_PATH_TEMPORARY = 0x0ULL,
@@ -84,4 +88,6 @@ enum {
int sd_path_home(uint64_t type, const char *suffix, char **path);
int sd_path_search(uint64_t type, const char *suffix, char ***paths);
+_SD_END_DECLARATIONS;
+
#endif
diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h
deleted file mode 100644
index 90878ffa27..0000000000
--- a/src/systemd/sd-pppoe.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosdpppoefoo
-#define foosdpppoefoo
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <net/ethernet.h>
-
-#include "sd-event.h"
-
-#include "sparse-endian.h"
-
-enum {
- SD_PPPOE_EVENT_RUNNING = 0,
- SD_PPPOE_EVENT_STOPPED = 1,
-};
-
-typedef struct sd_pppoe sd_pppoe;
-typedef void (*sd_pppoe_cb_t)(sd_pppoe *ppp, int event, void *userdata);
-
-int sd_pppoe_detach_event(sd_pppoe *ppp);
-int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority);
-int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel);
-int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata);
-int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex);
-int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname);
-int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name);
-int sd_pppoe_start(sd_pppoe *ppp);
-int sd_pppoe_stop(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp);
-sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp);
-int sd_pppoe_new (sd_pppoe **ret);
-
-#endif
diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h
index 80c5852e45..82c4b39efe 100644
--- a/src/systemd/sd-resolve.h
+++ b/src/systemd/sd-resolve.h
@@ -22,12 +22,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
-#include <sys/socket.h>
+#include <inttypes.h>
#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
-#include "_sd-common.h"
#include "sd-event.h"
+#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index aaa33354f4..008b1bde24 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -19,26 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <pwd.h>
+#include <getopt.h>
#include <grp.h>
-#include <shadow.h>
#include <gshadow.h>
-#include <getopt.h>
+#include <pwd.h>
+#include <shadow.h>
#include <utmp.h>
-#include "util.h"
-#include "hashmap.h"
-#include "specifier.h"
-#include "path-util.h"
-#include "build.h"
-#include "strv.h"
+#include "alloc-util.h"
#include "conf-files.h"
#include "copy.h"
-#include "utf8.h"
+#include "def.h"
+#include "fd-util.h"
#include "fileio-label.h"
-#include "uid-range.h"
-#include "selinux-util.h"
#include "formats-util.h"
+#include "hashmap.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "specifier.h"
+#include "string-util.h"
+#include "strv.h"
+#include "uid-range.h"
+#include "user-util.h"
+#include "utf8.h"
+#include "util.h"
typedef enum ItemType {
ADD_USER = 'u',
@@ -353,6 +358,19 @@ static int sync_rights(FILE *from, FILE *to) {
return 0;
}
+static int rename_and_apply_smack(const char *temp_path, const char *dest_path) {
+ int r = 0;
+ if (rename(temp_path, dest_path) < 0)
+ return -errno;
+
+#ifdef SMACK_RUN_LABEL
+ r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
+ if (r < 0)
+ return r;
+#endif
+ return r;
+}
+
static int write_files(void) {
_cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
@@ -699,36 +717,32 @@ static int write_files(void) {
/* And make the new files count */
if (group_changed) {
if (group) {
- if (rename(group_tmp, group_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(group_tmp, group_path);
+ if (r < 0)
goto finish;
- }
group_tmp = mfree(group_tmp);
}
if (gshadow) {
- if (rename(gshadow_tmp, gshadow_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(gshadow_tmp, gshadow_path);
+ if (r < 0)
goto finish;
- }
gshadow_tmp = mfree(gshadow_tmp);
}
}
if (passwd) {
- if (rename(passwd_tmp, passwd_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(passwd_tmp, passwd_path);
+ if (r < 0)
goto finish;
- }
passwd_tmp = mfree(passwd_tmp);
}
if (shadow) {
- if (rename(shadow_tmp, shadow_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(shadow_tmp, shadow_path);
+ if (r < 0)
goto finish;
- }
shadow_tmp = mfree(shadow_tmp);
}
@@ -929,7 +943,7 @@ static int add_user(Item *i) {
}
}
- /* Otherwise try to reuse the group ID */
+ /* Otherwise, try to reuse the group ID */
if (!i->uid_set && i->gid_set) {
r = uid_is_ok((uid_t) i->gid, i->name);
if (r < 0)
@@ -1753,7 +1767,7 @@ static int parse_argv(int argc, char *argv[]) {
{}
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -1767,17 +1781,12 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
- free(arg_root);
- arg_root = path_make_absolute_cwd(optarg);
- if (!arg_root)
- return log_oom();
-
- path_kill_slashes(arg_root);
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case '?':
@@ -1852,7 +1861,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- lock = take_password_lock(arg_root);
+ lock = take_etc_passwd_lock(arg_root);
if (lock < 0) {
log_error_errno(lock, "Failed to take lock: %m");
goto finish;
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 964750076a..042be97840 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -25,17 +25,24 @@
#include <stdio.h>
#include <unistd.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
+#include "hexdecoct.h"
+#include "install.h"
+#include "log.h"
#include "mkdir.h"
-#include "strv.h"
-#include "path-util.h"
#include "path-lookup.h"
-#include "log.h"
-#include "unit-name.h"
-#include "special.h"
-#include "hashmap.h"
+#include "path-util.h"
#include "set.h"
-#include "install.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "util.h"
typedef enum RunlevelType {
RUNLEVEL_UP,
@@ -80,9 +87,13 @@ typedef struct SysvStub {
char **conflicts;
bool has_lsb;
bool reload;
+ bool loaded;
} SysvStub;
static void free_sysvstub(SysvStub *s) {
+ if (!s)
+ return;
+
free(s->name);
free(s->path);
free(s->description);
@@ -107,19 +118,14 @@ static void free_sysvstub_hashmapp(Hashmap **h) {
}
static int add_symlink(const char *service, const char *where) {
- _cleanup_free_ char *from = NULL, *to = NULL;
+ const char *from, *to;
int r;
assert(service);
assert(where);
- from = strjoin(arg_dest, "/", service, NULL);
- if (!from)
- return log_oom();
-
- to = strjoin(arg_dest, "/", where, ".wants/", service, NULL);
- if (!to)
- return log_oom();
+ from = strjoina(arg_dest, "/", service);
+ to = strjoina(arg_dest, "/", where, ".wants/", service);
mkdir_parents_label(to, 0755);
@@ -127,6 +133,7 @@ static int add_symlink(const char *service, const char *where) {
if (r < 0) {
if (errno == EEXIST)
return 0;
+
return -errno;
}
@@ -134,20 +141,19 @@ static int add_symlink(const char *service, const char *where) {
}
static int add_alias(const char *service, const char *alias) {
- _cleanup_free_ char *link = NULL;
+ const char *link;
int r;
assert(service);
assert(alias);
- link = strjoin(arg_dest, "/", alias, NULL);
- if (!link)
- return log_oom();
+ link = strjoina(arg_dest, "/", alias);
r = symlink(service, link);
if (r < 0) {
if (errno == EEXIST)
return 0;
+
return -errno;
}
@@ -155,26 +161,32 @@ static int add_alias(const char *service, const char *alias) {
}
static int generate_unit_file(SysvStub *s) {
- char **p;
+ _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL;
_cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *unit = NULL,
- *before = NULL, *after = NULL,
- *wants = NULL, *conflicts = NULL;
+ const char *unit;
+ char **p;
int r;
+ assert(s);
+
+ if (!s->loaded)
+ return 0;
+
+ unit = strjoina(arg_dest, "/", s->name);
+
before = strv_join(s->before, " ");
after = strv_join(s->after, " ");
wants = strv_join(s->wants, " ");
conflicts = strv_join(s->conflicts, " ");
- unit = strjoin(arg_dest, "/", s->name, NULL);
- if (!before || !after || !wants || !conflicts || !unit)
+
+ if (!before || !after || !wants || !conflicts)
return log_oom();
/* We might already have a symlink with the same name from a Provides:,
* or from backup files like /etc/init.d/foo.bak. Real scripts always win,
* so remove an existing link */
if (is_symlink(unit) > 0) {
- log_warning("Overwriting existing symlink %s with real service", unit);
+ log_warning("Overwriting existing symlink %s with real service.", unit);
(void) unlink(unit);
}
@@ -186,9 +198,11 @@ static int generate_unit_file(SysvStub *s) {
"# Automatically generated by systemd-sysv-generator\n\n"
"[Unit]\n"
"Documentation=man:systemd-sysv-generator(8)\n"
- "SourcePath=%s\n"
- "Description=%s\n",
- s->path, s->description);
+ "SourcePath=%s\n",
+ s->path);
+
+ if (s->description)
+ fprintf(f, "Description=%s\n", s->description);
if (!isempty(before))
fprintf(f, "Before=%s\n", before);
@@ -221,13 +235,17 @@ static int generate_unit_file(SysvStub *s) {
if (s->reload)
fprintf(f, "ExecReload=%s reload\n", s->path);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit %s: %m", unit);
+
STRV_FOREACH(p, s->wanted_by) {
r = add_symlink(s->name, *p);
if (r < 0)
- log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p);
+ log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p);
}
- return 0;
+ return 1;
}
static bool usage_contains_reload(const char *line) {
@@ -257,7 +275,7 @@ static char *sysv_translate_name(const char *name) {
return res;
}
-static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
+static int sysv_translate_facility(const char *name, const char *filename, char **ret) {
/* We silently ignore the $ prefix here. According to the LSB
* spec it simply indicates whether something is a
@@ -276,31 +294,45 @@ static int sysv_translate_facility(const char *name, const char *filename, char
"time", SPECIAL_TIME_SYNC_TARGET,
};
- char *filename_no_sh, *e, *r;
+ char *filename_no_sh, *e, *m;
const char *n;
unsigned i;
+ int r;
assert(name);
- assert(_r);
+ assert(filename);
+ assert(ret);
n = *name == '$' ? name + 1 : name;
for (i = 0; i < ELEMENTSOF(table); i += 2) {
-
if (!streq(table[i], n))
continue;
if (!table[i+1])
return 0;
- r = strdup(table[i+1]);
- if (!r)
+ m = strdup(table[i+1]);
+ if (!m)
return log_oom();
- goto finish;
+ *ret = m;
+ return 1;
+ }
+
+ /* If we don't know this name, fallback heuristics to figure
+ * out whether something is a target or a service alias. */
+
+ /* Facilities starting with $ are most likely targets */
+ if (*name == '$') {
+ r = unit_name_build(n, NULL, ".target", ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to build name: %m");
+
+ return r;
}
- /* strip ".sh" suffix from file name for comparison */
+ /* Strip ".sh" suffix from file name for comparison */
filename_no_sh = strdupa(filename);
e = endswith(filename_no_sh, ".sh");
if (e) {
@@ -308,103 +340,103 @@ static int sysv_translate_facility(const char *name, const char *filename, char
filename = filename_no_sh;
}
- /* If we don't know this name, fallback heuristics to figure
- * out whether something is a target or a service alias. */
-
- if (*name == '$') {
- int k;
-
- /* Facilities starting with $ are most likely targets */
- k = unit_name_build(n, NULL, ".target", &r);
- if (k < 0)
- return k;
-
- } else if (streq_ptr(n, filename))
- /* Names equaling the file name of the services are redundant */
+ /* Names equaling the file name of the services are redundant */
+ if (streq_ptr(n, filename))
return 0;
- else
- /* Everything else we assume to be normal service names */
- r = sysv_translate_name(n);
- if (!r)
- return -ENOMEM;
-finish:
- *_r = r;
+ /* Everything else we assume to be normal service names */
+ m = sysv_translate_name(n);
+ if (!m)
+ return log_oom();
+ *ret = m;
return 1;
}
static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) {
- const char *word, *state_;
- size_t z;
int r;
- FOREACH_WORD_QUOTED(word, z, text, state_) {
- _cleanup_free_ char *n = NULL, *m = NULL;
- UnitType t;
+ assert(s);
+ assert(full_text);
+ assert(text);
- n = strndup(word, z);
- if (!n)
- return log_oom();
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *m = NULL;
- r = sysv_translate_facility(n, basename(s->path), &m);
+ r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to parse word from provides string: %m");
if (r == 0)
+ break;
+
+ r = sysv_translate_facility(word, basename(s->path), &m);
+ if (r <= 0) /* continue on error */
continue;
- t = unit_name_to_type(m);
- if (t == UNIT_SERVICE) {
+ switch (unit_name_to_type(m)) {
+
+ case UNIT_SERVICE:
log_debug("Adding Provides: alias '%s' for '%s'", m, s->name);
r = add_alias(s->name, m);
if (r < 0)
log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m);
- } else if (t == UNIT_TARGET) {
+ break;
+
+ case UNIT_TARGET:
+
/* NB: SysV targets which are provided by a
* service are pulled in by the services, as
* an indication that the generic service is
* now available. This is strictly one-way.
* The targets do NOT pull in SysV services! */
+
r = strv_extend(&s->before, m);
if (r < 0)
return log_oom();
+
r = strv_extend(&s->wants, m);
if (r < 0)
return log_oom();
+
if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) {
r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET);
if (r < 0)
return log_oom();
}
- } else if (t == _UNIT_TYPE_INVALID)
+
+ break;
+
+ case _UNIT_TYPE_INVALID:
log_warning("Unit name '%s' is invalid", m);
- else
+ break;
+
+ default:
log_warning("Unknown unit type for unit '%s'", m);
+ }
}
- if (!isempty(state_))
- log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line);
+
return 0;
}
static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) {
- const char *word, *state_;
- size_t z;
int r;
- FOREACH_WORD_QUOTED(word, z, text, state_) {
- _cleanup_free_ char *n = NULL, *m = NULL;
- bool is_before;
+ assert(s);
+ assert(full_text);
+ assert(text);
- n = strndup(word, z);
- if (!n)
- return log_oom();
+ for (;;) {
+ _cleanup_free_ char *word = NULL, *m = NULL;
+ bool is_before;
- r = sysv_translate_facility(n, basename(s->path), &m);
- if (r < 0) {
- log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n);
- continue;
- }
+ r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse word from provides string: %m");
if (r == 0)
+ break;
+
+ r = sysv_translate_facility(word, basename(s->path), &m);
+ if (r <= 0) /* continue on error */
continue;
is_before = startswith_no_case(full_text, "X-Start-Before:");
@@ -414,15 +446,14 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text
r = strv_extend(&s->after, m);
if (r < 0)
return log_oom();
+
r = strv_extend(&s->wants, m);
} else
r = strv_extend(is_before ? &s->before : &s->after, m);
-
if (r < 0)
return log_oom();
}
- if (!isempty(state_))
- log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text);
+
return 0;
}
@@ -440,24 +471,22 @@ static int load_sysv(SysvStub *s) {
_cleanup_free_ char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL;
char *description;
bool supports_reload = false;
+ char l[LINE_MAX];
assert(s);
f = fopen(s->path, "re");
- if (!f)
- return errno == ENOENT ? 0 : -errno;
-
- log_debug("Loading SysV script %s", s->path);
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
- while (!feof(f)) {
- char l[LINE_MAX], *t;
+ return log_error_errno(errno, "Failed to open %s: %m", s->path);
+ }
- if (!fgets(l, sizeof(l), f)) {
- if (feof(f))
- break;
+ log_debug("Loading SysV script %s", s->path);
- return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
- }
+ FOREACH_LINE(l, f, goto fail) {
+ char *t;
line++;
@@ -500,29 +529,25 @@ static int load_sysv(SysvStub *s) {
if (startswith_no_case(t, "description:")) {
- size_t k = strlen(t);
- char *d;
+ size_t k;
const char *j;
- if (t[k-1] == '\\') {
+ k = strlen(t);
+ if (k > 0 && t[k-1] == '\\') {
state = DESCRIPTION;
t[k-1] = 0;
}
j = strstrip(t+12);
- if (j && *j) {
- d = strdup(j);
- if (!d)
- return -ENOMEM;
- } else
- d = NULL;
+ if (isempty(j))
+ j = NULL;
- free(chkconfig_description);
- chkconfig_description = d;
+ r = free_and_strdup(&chkconfig_description, j);
+ if (r < 0)
+ return log_oom();
} else if (startswith_no_case(t, "pidfile:")) {
-
- char *fn;
+ const char *fn;
state = NORMAL;
@@ -532,12 +557,9 @@ static int load_sysv(SysvStub *s) {
continue;
}
- fn = strdup(fn);
- if (!fn)
- return -ENOMEM;
-
- free(s->pid_file);
- s->pid_file = fn;
+ r = free_and_strdup(&s->pid_file, fn);
+ if (r < 0)
+ return log_oom();
}
} else if (state == DESCRIPTION) {
@@ -545,25 +567,25 @@ static int load_sysv(SysvStub *s) {
/* Try to parse Red Hat style description
* continuation */
- size_t k = strlen(t);
+ size_t k;
char *j;
- if (t[k-1] == '\\')
+ k = strlen(t);
+ if (k > 0 && t[k-1] == '\\')
t[k-1] = 0;
else
state = NORMAL;
j = strstrip(t);
- if (j && *j) {
+ if (!isempty(j)) {
char *d = NULL;
if (chkconfig_description)
d = strjoin(chkconfig_description, " ", j, NULL);
else
d = strdup(j);
-
if (!d)
- return -ENOMEM;
+ return log_oom();
free(chkconfig_description);
chkconfig_description = d;
@@ -577,6 +599,7 @@ static int load_sysv(SysvStub *s) {
r = handle_provides(s, line, t, t + 9);
if (r < 0)
return r;
+
} else if (startswith_no_case(t, "Required-Start:") ||
startswith_no_case(t, "Should-Start:") ||
startswith_no_case(t, "X-Start-Before:") ||
@@ -588,55 +611,47 @@ static int load_sysv(SysvStub *s) {
if (r < 0)
return r;
-
} else if (startswith_no_case(t, "Description:")) {
- char *d, *j;
+ const char *j;
state = LSB_DESCRIPTION;
j = strstrip(t+12);
- if (j && *j) {
- d = strdup(j);
- if (!d)
- return -ENOMEM;
- } else
- d = NULL;
+ if (isempty(j))
+ j = NULL;
- free(long_description);
- long_description = d;
+ r = free_and_strdup(&long_description, j);
+ if (r < 0)
+ return log_oom();
} else if (startswith_no_case(t, "Short-Description:")) {
- char *d, *j;
+ const char *j;
state = LSB;
j = strstrip(t+18);
- if (j && *j) {
- d = strdup(j);
- if (!d)
- return -ENOMEM;
- } else
- d = NULL;
+ if (isempty(j))
+ j = NULL;
- free(short_description);
- short_description = d;
+ r = free_and_strdup(&short_description, j);
+ if (r < 0)
+ return log_oom();
} else if (state == LSB_DESCRIPTION) {
if (startswith(l, "#\t") || startswith(l, "# ")) {
- char *j;
+ const char *j;
j = strstrip(t);
- if (j && *j) {
+ if (!isempty(j)) {
char *d = NULL;
if (long_description)
d = strjoin(long_description, " ", t, NULL);
else
d = strdup(j);
-
if (!d)
- return -ENOMEM;
+ return log_oom();
free(long_description);
long_description = d;
@@ -667,12 +682,16 @@ static int load_sysv(SysvStub *s) {
d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description);
if (!d)
- return -ENOMEM;
+ return log_oom();
s->description = d;
}
+ s->loaded = true;
return 0;
+
+fail:
+ return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path);
}
static int fix_order(SysvStub *s, Hashmap *all_services) {
@@ -682,6 +701,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
assert(s);
+ if (!s->loaded)
+ return 0;
+
if (s->sysv_start_priority < 0)
return 0;
@@ -689,6 +711,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
if (s == other)
continue;
+ if (!other->loaded)
+ continue;
+
if (other->sysv_start_priority < 0)
continue;
@@ -701,13 +726,12 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
r = strv_extend(&s->after, other->name);
if (r < 0)
return log_oom();
- }
- else if (other->sysv_start_priority > s->sysv_start_priority) {
+
+ } else if (other->sysv_start_priority > s->sysv_start_priority) {
r = strv_extend(&s->before, other->name);
if (r < 0)
return log_oom();
- }
- else
+ } else
continue;
/* FIXME: Maybe we should compare the name here lexicographically? */
@@ -719,6 +743,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
char **path;
+ assert(lp);
+ assert(all_services);
+
STRV_FOREACH(path, lp->sysvinit_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -726,21 +753,18 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
d = opendir(*path);
if (!d) {
if (errno != ENOENT)
- log_warning_errno(errno, "opendir(%s) failed: %m", *path);
+ log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path);
continue;
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) {
_cleanup_free_ char *fpath = NULL, *name = NULL;
_cleanup_(free_sysvstubp) SysvStub *service = NULL;
struct stat st;
int r;
- if (hidden_file(de->d_name))
- continue;
-
if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
- log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
+ log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name);
continue;
}
@@ -757,15 +781,15 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
if (hashmap_contains(all_services, name))
continue;
- fpath = strjoin(*path, "/", de->d_name, NULL);
- if (!fpath)
- return log_oom();
-
if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) {
log_debug("Native unit for %s already exists, skipping", name);
continue;
}
+ fpath = strjoin(*path, "/", de->d_name, NULL);
+ if (!fpath)
+ return log_oom();
+
service = new0(SysvStub, 1);
if (!service)
return log_oom();
@@ -773,12 +797,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
service->sysv_start_priority = -1;
service->name = name;
service->path = fpath;
+ name = fpath = NULL;
r = hashmap_put(all_services, service->name, service);
if (r < 0)
return log_oom();
- name = fpath = NULL;
service = NULL;
}
}
@@ -787,43 +811,41 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
}
static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
- char **p;
- unsigned i;
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *path = NULL, *fpath = NULL;
- SysvStub *service;
- Iterator j;
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
_cleanup_set_free_ Set *shutdown_services = NULL;
- int r = 0;
+ SysvStub *service;
+ unsigned i;
+ Iterator j;
+ char **p;
+ int r;
+
+ assert(lp);
- STRV_FOREACH(p, lp->sysvrcnd_path)
+ STRV_FOREACH(p, lp->sysvrcnd_path) {
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
+
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_free_ char *path = NULL;
struct dirent *de;
- free(path);
path = strjoin(*p, "/", rcnd_table[i].path, NULL);
- if (!path)
- return -ENOMEM;
-
- safe_closedir(d);
+ if (!path) {
+ r = log_oom();
+ goto finish;
+ }
d = opendir(path);
if (!d) {
if (errno != ENOENT)
- log_warning_errno(errno, "opendir(%s) failed: %m", path);
+ log_warning_errno(errno, "Opening %s failed, ignoring: %m", path);
continue;
}
- while ((de = readdir(d))) {
- _cleanup_free_ char *name = NULL;
-
+ FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path)) {
+ _cleanup_free_ char *name = NULL, *fpath = NULL;
int a, b;
- if (hidden_file(de->d_name))
- continue;
-
if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
continue;
@@ -836,10 +858,9 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
if (a < 0 || b < 0)
continue;
- free(fpath);
fpath = strjoin(*p, "/", de->d_name, NULL);
if (!fpath) {
- r = -ENOMEM;
+ r = log_oom();
goto finish;
}
@@ -851,64 +872,77 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
service = hashmap_get(all_services, name);
if (!service){
- log_debug("Ignoring %s symlink in %s, not generating %s.",
- de->d_name, rcnd_table[i].path, name);
+ log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name);
continue;
}
if (de->d_name[0] == 'S') {
- if (rcnd_table[i].type == RUNLEVEL_UP) {
- service->sysv_start_priority =
- MAX(a*10 + b, service->sysv_start_priority);
- }
+ if (rcnd_table[i].type == RUNLEVEL_UP)
+ service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
r = set_ensure_allocated(&runlevel_services[i], NULL);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
r = set_put(runlevel_services[i], service);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
} else if (de->d_name[0] == 'K' &&
(rcnd_table[i].type == RUNLEVEL_DOWN)) {
r = set_ensure_allocated(&shutdown_services, NULL);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
r = set_put(shutdown_services, service);
- if (r < 0)
+ if (r < 0) {
+ log_oom();
goto finish;
+ }
}
}
}
+ }
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
SET_FOREACH(service, runlevel_services[i], j) {
r = strv_extend(&service->before, rcnd_table[i].target);
- if (r < 0)
- return log_oom();
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
r = strv_extend(&service->wanted_by, rcnd_table[i].target);
- if (r < 0)
- return log_oom();
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
}
SET_FOREACH(service, shutdown_services, j) {
r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET);
- if (r < 0)
- return log_oom();
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET);
- if (r < 0)
- return log_oom();
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
}
r = 0;
finish:
-
for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
set_free(runlevel_services[i]);
@@ -916,11 +950,11 @@ finish:
}
int main(int argc, char *argv[]) {
- int r, q;
- _cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths lp = {};
SysvStub *service;
Iterator j;
+ int r;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
@@ -938,43 +972,34 @@ int main(int argc, char *argv[]) {
r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
if (r < 0) {
- log_error("Failed to find lookup paths.");
- return EXIT_FAILURE;
+ log_error_errno(r, "Failed to find lookup paths: %m");
+ goto finish;
}
all_services = hashmap_new(&string_hash_ops);
if (!all_services) {
- log_oom();
- return EXIT_FAILURE;
+ r = log_oom();
+ goto finish;
}
r = enumerate_sysv(&lp, all_services);
- if (r < 0) {
- log_error("Failed to generate units for all init scripts.");
- return EXIT_FAILURE;
- }
+ if (r < 0)
+ goto finish;
r = set_dependencies_from_rcnd(&lp, all_services);
- if (r < 0) {
- log_error("Failed to read runlevels from rcnd links.");
- return EXIT_FAILURE;
- }
+ if (r < 0)
+ goto finish;
- HASHMAP_FOREACH(service, all_services, j) {
- q = load_sysv(service);
- if (q < 0)
- continue;
- }
+ HASHMAP_FOREACH(service, all_services, j)
+ (void) load_sysv(service);
HASHMAP_FOREACH(service, all_services, j) {
- q = fix_order(service, all_services);
- if (q < 0)
- continue;
-
- q = generate_unit_file(service);
- if (q < 0)
- continue;
+ (void) fix_order(service, all_services);
+ (void) generate_unit_file(service);
}
- return EXIT_SUCCESS;
+ r = 0;
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c
index d69104f540..aeaa0929b1 100644
--- a/src/test/test-af-list.c
+++ b/src/test/test-af-list.c
@@ -17,17 +17,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
#include <string.h>
+#include <sys/socket.h>
#include "macro.h"
+#include "string-util.h"
#include "util.h"
static const struct af_name* lookup_af(register const char *str, register unsigned int len);
+#include "af-from-name.h"
#include "af-list.h"
#include "af-to-name.h"
-#include "af-from-name.h"
int main(int argc, const char *argv[]) {
@@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) {
assert_se(af_from_name("huddlduddl") == AF_UNSPEC);
return 0;
-} \ No newline at end of file
+}
diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c
index d7c8eaa4a9..f3989ad201 100644
--- a/src/test/test-arphrd-list.c
+++ b/src/test/test-arphrd-list.c
@@ -21,13 +21,14 @@
#include <string.h>
#include "macro.h"
+#include "string-util.h"
#include "util.h"
static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len);
+#include "arphrd-from-name.h"
#include "arphrd-list.h"
#include "arphrd-to-name.h"
-#include "arphrd-from-name.h"
int main(int argc, const char *argv[]) {
@@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) {
assert_se(arphrd_from_name("huddlduddl") == 0);
return 0;
-} \ No newline at end of file
+}
diff --git a/src/test/test-async.c b/src/test/test-async.c
index abd36d693c..ada6d67c42 100644
--- a/src/test/test-async.c
+++ b/src/test/test-async.c
@@ -20,8 +20,9 @@
#include <unistd.h>
#include "async.h"
-#include "util.h"
+#include "fileio.h"
#include "macro.h"
+#include "util.h"
static bool test_async = false;
diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c
index e4771c9dd7..33356f8387 100644
--- a/src/test/test-btrfs.c
+++ b/src/test/test-btrfs.c
@@ -21,23 +21,26 @@
#include <fcntl.h>
-#include "log.h"
+#include "btrfs-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "log.h"
+#include "parse-util.h"
+#include "string-util.h"
#include "util.h"
-#include "btrfs-util.h"
int main(int argc, char *argv[]) {
+ BtrfsQuotaInfo quota;
int r, fd;
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
log_error_errno(errno, "Failed to open root directory: %m");
else {
- BtrfsSubvolInfo info;
- BtrfsQuotaInfo quota;
char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX];
+ BtrfsSubvolInfo info;
- r = btrfs_subvol_get_info_fd(fd, &info);
+ r = btrfs_subvol_get_info_fd(fd, 0, &info);
if (r < 0)
log_error_errno(r, "Failed to get subvolume info: %m");
else {
@@ -45,7 +48,7 @@ int main(int argc, char *argv[]) {
log_info("read-only (search): %s", yes_no(info.read_only));
}
- r = btrfs_subvol_get_quota_fd(fd, &quota);
+ r = btrfs_qgroup_get_quota_fd(fd, 0, &quota);
if (r < 0)
log_error_errno(r, "Failed to get quota info: %m");
else {
@@ -80,15 +83,15 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/xxxtest", false);
+ r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest2", false);
+ r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxtest3", false);
+ r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
@@ -96,7 +99,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
- r = btrfs_subvol_remove("/etc2", false);
+ r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
@@ -137,13 +140,61 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to snapshot subvolume: %m");
- r = btrfs_subvol_remove("/xxxrectest", true);
+ r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to recursively remove subvolume: %m");
- r = btrfs_subvol_remove("/xxxrectest2", true);
+ r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to recursively remove subvolume: %m");
+ r = btrfs_subvol_make("/xxxquotatest");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true);
+ if (r < 0)
+ log_error_errno(r, "Failed to set up auto qgroup: %m");
+
+ r = btrfs_subvol_make("/xxxquotatest/beneath");
+ if (r < 0)
+ log_error_errno(r, "Failed to make subvolume: %m");
+
+ r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false);
+ if (r < 0)
+ log_error_errno(r, "Failed to set up auto qgroup: %m");
+
+ r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024);
+ if (r < 0)
+ log_error_errno(r, "Failed to set up quota limit: %m");
+
+ r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024);
+ if (r < 0)
+ log_error_errno(r, "Failed to set up quota limit: %m");
+
+ r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
+ if (r < 0)
+ log_error_errno(r, "Failed to setup snapshot: %m");
+
+ r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, &quota);
+ if (r < 0)
+ log_error_errno(r, "Failed to query quota: %m");
+
+ assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
+
+ r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, &quota);
+ if (r < 0)
+ log_error_errno(r, "Failed to query quota: %m");
+
+ assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
+
+ r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
+ if (r < 0)
+ log_error_errno(r, "Failed remove subvolume: %m");
+
+ r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
+ if (r < 0)
+ log_error_errno(r, "Failed remove subvolume: %m");
+
return 0;
}
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 87e1da1258..70819b0371 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -21,7 +21,9 @@
#include <string.h>
+#include "alloc-util.h"
#include "calendarspec.h"
+#include "string-util.h"
#include "util.h"
static void test_one(const char *input, const char *output) {
@@ -50,6 +52,44 @@ static void test_one(const char *input, const char *output) {
assert_se(streq(q, p));
}
+static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) {
+ CalendarSpec *c;
+ usec_t u;
+ char *old_tz;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ int r;
+
+ old_tz = getenv("TZ");
+ if (old_tz)
+ old_tz = strdupa(old_tz);
+
+ if (new_tz)
+ assert_se(setenv("TZ", new_tz, 1) >= 0);
+ else
+ assert_se(unsetenv("TZ") >= 0);
+ tzset();
+
+ assert_se(calendar_spec_from_string(input, &c) >= 0);
+
+ printf("\"%s\"\n", input);
+
+ u = after;
+ r = calendar_spec_next_usec(c, after, &u);
+ printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
+ if (expect != (usec_t)-1)
+ assert_se(r >= 0 && u == expect);
+ else
+ assert(r == -ENOENT);
+
+ calendar_spec_free(c);
+
+ if (old_tz)
+ assert_se(setenv("TZ", old_tz, 1) >= 0);
+ else
+ assert_se(unsetenv("TZ") >= 0);
+ tzset();
+}
+
int main(int argc, char* argv[]) {
CalendarSpec *c;
@@ -82,6 +122,15 @@ int main(int argc, char* argv[]) {
test_one("semi-annually", "*-01,07-01 00:00:00");
test_one("annually", "*-01-01 00:00:00");
test_one("*:2/3", "*-*-* *:02/3:00");
+ test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+
+ test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
+ test_next("2016-03-27 03:17:00", "EET", 12345, -1);
+ test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
assert_se(calendar_spec_from_string("test", &c) < 0);
assert_se(calendar_spec_from_string("", &c) < 0);
diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c
index 43a2d35b80..4418bafda6 100644
--- a/src/test/test-cap-list.c
+++ b/src/test/test-cap-list.c
@@ -19,12 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "fileio.h"
-#include "cap-list.h"
-#include "capability.h"
#include <sys/prctl.h>
+#include "alloc-util.h"
+#include "cap-list.h"
+#include "capability-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "util.h"
+
/* verify the capability parser */
static void test_cap_list(void) {
int i;
diff --git a/src/test/test-capability.c b/src/test/test-capability.c
index f47452ce72..fc8d3ffe0d 100644
--- a/src/test/test-capability.c
+++ b/src/test/test-capability.c
@@ -17,20 +17,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/wait.h>
-#include <sys/capability.h>
-#include <sys/socket.h>
#include <netinet/in.h>
#include <pwd.h>
+#include <sys/capability.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
#include <unistd.h>
-#include "capability.h"
-#include "util.h"
+#include "capability-util.h"
+#include "fd-util.h"
#include "macro.h"
+#include "util.h"
static uid_t test_uid = -1;
static gid_t test_gid = -1;
-// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage
+
+/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE;
static void fork_test(void (*test_func)(void)) {
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
index 4ecf09a29e..a48b324e26 100644
--- a/src/test/test-cgroup-util.c
+++ b/src/test/test-cgroup-util.c
@@ -19,12 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-#include "util.h"
+#include "alloc-util.h"
#include "cgroup-util.h"
-#include "test-helper.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "string-util.h"
+#include "test-helper.h"
+#include "user-util.h"
+#include "util.h"
static void check_p_d_u(const char *path, int code, const char *result) {
_cleanup_free_ char *unit = NULL;
diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c
index 37b1c3554a..c20a29ba1f 100644
--- a/src/test/test-cgroup.c
+++ b/src/test/test-cgroup.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <string.h>
+#include <unistd.h>
#include "cgroup-util.h"
#include "path-util.h"
+#include "string-util.h"
#include "util.h"
int main(int argc, char*argv[]) {
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index b788c9532d..f224c6cdd8 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -17,18 +17,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-id128.h"
+
+#include "alloc-util.h"
+#include "apparmor-util.h"
+#include "architecture.h"
+#include "audit-util.h"
#include "condition.h"
-#include "macro.h"
-#include "util.h"
+#include "hostname-util.h"
+#include "ima-util.h"
#include "log.h"
-#include "architecture.h"
-#include "sd-id128.h"
+#include "macro.h"
#include "selinux-util.h"
-#include "audit.h"
-#include "ima-util.h"
-#include "apparmor-util.h"
#include "smack-util.h"
-#include "hostname-util.h"
+#include "util.h"
static void test_condition_test_path(void) {
Condition *condition;
diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c
index 01ece022c1..a69698d4ea 100644
--- a/src/test/test-conf-files.c
+++ b/src/test/test-conf-files.c
@@ -19,14 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdarg.h>
+#include <stdio.h>
+#include "alloc-util.h"
#include "conf-files.h"
+#include "fs-util.h"
#include "macro.h"
+#include "rm-rf.h"
+#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
#include "util.h"
-#include "rm-rf.h"
static void setup_test_dir(char *tmp_dir, const char *files, ...) {
va_list ap;
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 463906d304..b3a4c40339 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -18,10 +18,11 @@
***/
#include "conf-parser.h"
+#include "log.h"
#include "macro.h"
-#include "util.h"
+#include "string-util.h"
#include "strv.h"
-#include "log.h"
+#include "util.h"
static void test_config_parse_path_one(const char *rvalue, const char *expected) {
char *path = NULL;
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index a03a68bd43..ad57cb0202 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -19,14 +19,18 @@
#include <unistd.h>
+#include "alloc-util.h"
#include "copy.h"
-#include "path-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
+#include "macro.h"
#include "mkdir.h"
+#include "path-util.h"
+#include "rm-rf.h"
+#include "string-util.h"
#include "strv.h"
-#include "macro.h"
#include "util.h"
-#include "rm-rf.h"
static void test_copy_file(void) {
_cleanup_free_ char *buf = NULL;
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
index 7e0ac754d1..45fb554445 100644
--- a/src/test/test-daemon.c
+++ b/src/test/test-daemon.c
@@ -21,9 +21,22 @@
#include <unistd.h>
-#include "systemd/sd-daemon.h"
+#include "sd-daemon.h"
+
+#include "strv.h"
int main(int argc, char*argv[]) {
+ _cleanup_strv_free_ char **l = NULL;
+ int n, i;
+
+ n = sd_listen_fds_with_names(false, &l);
+ if (n < 0) {
+ log_error_errno(n, "Failed to get listening fds: %m");
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < n; i++)
+ log_info("fd=%i name=%s\n", SD_LISTEN_FDS_START + i, l[i]);
sd_notify(0,
"STATUS=Starting up");
@@ -49,5 +62,5 @@ int main(int argc, char*argv[]) {
"STOPPING=1");
sleep(5);
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/test/test-date.c b/src/test/test-date.c
index 00b569080c..c6d8bf82ea 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -21,14 +21,16 @@
#include <string.h>
+#include "alloc-util.h"
+#include "string-util.h"
#include "util.h"
-static void test_one(const char *p) {
+static void test_should_pass(const char *p) {
usec_t t, q;
char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
assert_se(parse_timestamp(p, &t) >= 0);
- format_timestamp(buf, sizeof(buf), t);
+ format_timestamp_us(buf, sizeof(buf), t);
log_info("%s", buf);
/* Chop off timezone */
@@ -42,23 +44,57 @@ static void test_one(const char *p) {
assert_se(parse_timestamp(buf, &q) >= 0);
}
+static void test_should_parse(const char *p) {
+ usec_t t;
+
+ assert_se(parse_timestamp(p, &t) >= 0);
+}
+
+static void test_should_fail(const char *p) {
+ usec_t t;
+
+ assert_se(parse_timestamp(p, &t) < 0);
+}
+
+static void test_one(const char *p) {
+ _cleanup_free_ char *with_utc;
+
+ log_info("Test: %s", p);
+ with_utc = strjoin(p, " UTC", NULL);
+ test_should_pass(p);
+ test_should_pass(with_utc);
+}
+
+static void test_one_noutc(const char *p) {
+ _cleanup_free_ char *with_utc;
+
+ log_info("Test: %s", p);
+ with_utc = strjoin(p, " UTC", NULL);
+ test_should_pass(p);
+ test_should_fail(with_utc);
+}
+
int main(int argc, char *argv[]) {
test_one("17:41");
test_one("18:42:44");
+ test_one("18:42:44.0");
+ test_one("18:42:44.999999999999");
test_one("12-10-02 12:13:14");
test_one("12-10-2 12:13:14");
test_one("12-10-03 12:13");
test_one("2012-12-30 18:42");
test_one("2012-10-02");
test_one("Tue 2012-10-02");
- test_one("now");
+ test_one_noutc("now");
test_one("yesterday");
test_one("today");
test_one("tomorrow");
- test_one("+2d");
- test_one("+2y 4d");
- test_one("5months ago");
- test_one("@1395716396");
+ test_one_noutc("+2d");
+ test_one_noutc("+2y 4d");
+ test_one_noutc("5months ago");
+ test_one_noutc("@1395716396");
+ test_should_parse("today UTC");
+ test_should_fail("today UTC UTC");
return 0;
}
diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c
index 59ba4be087..646b168cc0 100644
--- a/src/test/test-device-nodes.c
+++ b/src/test/test-device-nodes.c
@@ -21,7 +21,9 @@
#include <sys/types.h>
+#include "alloc-util.h"
#include "device-nodes.h"
+#include "string-util.h"
#include "util.h"
/* helpers for test_encode_devnode_name */
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 2193eb6f7d..d5778748a0 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "macro.h"
+#include "alloc-util.h"
#include "dns-domain.h"
+#include "macro.h"
+#include "string-util.h"
static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) {
char buffer[buffer_sz];
diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c
index 27df9089c3..c597d5aecd 100644
--- a/src/test/test-ellipsize.c
+++ b/src/test/test-ellipsize.c
@@ -21,9 +21,11 @@
#include <stdio.h>
-#include "util.h"
-#include "terminal-util.h"
+#include "alloc-util.h"
#include "def.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
static void test_one(const char *p) {
_cleanup_free_ char *t;
diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c
index 2e28c0c49b..c1315bbf9f 100644
--- a/src/test/test-env-replace.c
+++ b/src/test/test-env-replace.c
@@ -21,9 +21,10 @@
#include <string.h>
-#include "util.h"
-#include "strv.h"
#include "env-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
static void test_strv_env_delete(void) {
_cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL;
@@ -118,6 +119,8 @@ static void test_replace_env_arg(void) {
"$FOO$FOO",
"${FOO}${BAR}",
"${FOO",
+ "FOO$$${FOO}",
+ "$$FOO${FOO}",
NULL
};
_cleanup_strv_free_ char **r = NULL;
@@ -133,7 +136,9 @@ static void test_replace_env_arg(void) {
assert_se(streq(r[6], "BAR"));
assert_se(streq(r[7], "BAR BARwaldo"));
assert_se(streq(r[8], "${FOO"));
- assert_se(strv_length(r) == 9);
+ assert_se(streq(r[9], "FOO$BAR BAR"));
+ assert_se(streq(r[10], "$FOOBAR BAR"));
+ assert_se(strv_length(r) == 11);
}
static void test_env_clean(void) {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index fa6336f1fb..e2ec53ee51 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -17,14 +17,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <grp.h>
+#include <pwd.h>
#include <stdio.h>
+#include <sys/types.h>
-#include "unit.h"
-#include "manager.h"
-#include "util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "macro.h"
+#include "manager.h"
#include "mkdir.h"
+#include "path-util.h"
#include "rm-rf.h"
+#include "unit.h"
+#include "util.h"
typedef void (*test_function_t)(Manager *m);
@@ -123,11 +129,17 @@ static void test_exec_systemcallerrornumber(Manager *m) {
}
static void test_exec_user(Manager *m) {
- test(m, "exec-user.service", 0, CLD_EXITED);
+ if (getpwnam("nobody"))
+ test(m, "exec-user.service", 0, CLD_EXITED);
+ else
+ log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m");
}
static void test_exec_group(Manager *m) {
- test(m, "exec-group.service", 0, CLD_EXITED);
+ if (getgrnam("nobody"))
+ test(m, "exec-group.service", 0, CLD_EXITED);
+ else
+ log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m");
}
static void test_exec_environment(Manager *m) {
@@ -136,6 +148,26 @@ static void test_exec_environment(Manager *m) {
test(m, "exec-environment-empty.service", 0, CLD_EXITED);
}
+static void test_exec_environmentfile(Manager *m) {
+ static const char e[] =
+ "VAR1='word1 word2'\n"
+ "VAR2=word3 \n"
+ "# comment1\n"
+ "\n"
+ "; comment2\n"
+ " ; # comment3\n"
+ "line without an equal\n"
+ "VAR3='$word 5 6'\n";
+ int r;
+
+ r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
+ assert_se(r == 0);
+
+ test(m, "exec-environmentfile.service", 0, CLD_EXITED);
+
+ unlink("/tmp/test-exec_environmentfile.conf");
+}
+
static void test_exec_umask(Manager *m) {
test(m, "exec-umask-default.service", 0, CLD_EXITED);
test(m, "exec-umask-0177.service", 0, CLD_EXITED);
@@ -144,7 +176,51 @@ static void test_exec_umask(Manager *m) {
static void test_exec_runtimedirectory(Manager *m) {
test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
- test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ if (getgrnam("nobody"))
+ test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ else
+ log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m");
+}
+
+static void test_exec_capabilityboundingset(Manager *m) {
+ int r;
+
+ /* We use capsh to test if the capabilities are
+ * properly set, so be sure that it exists */
+ r = find_binary("capsh", NULL);
+ if (r < 0) {
+ log_error_errno(r, "Skipping test_exec_capabilityboundingset, could not find capsh binary: %m");
+ return;
+ }
+
+ test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
+ test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
+ test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
+ test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
+}
+
+static void test_exec_privatenetwork(Manager *m) {
+ int r;
+
+ r = find_binary("ip", NULL);
+ if (r < 0) {
+ log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m");
+ return;
+ }
+
+ test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED);
+}
+
+static void test_exec_oomscoreadjust(Manager *m) {
+ test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+ test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+}
+
+static void test_exec_ioschedulingclass(Manager *m) {
+ test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+ test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
}
int main(int argc, char *argv[]) {
@@ -154,13 +230,18 @@ int main(int argc, char *argv[]) {
test_exec_ignoresigpipe,
test_exec_privatetmp,
test_exec_privatedevices,
+ test_exec_privatenetwork,
test_exec_systemcallfilter,
test_exec_systemcallerrornumber,
test_exec_user,
test_exec_group,
test_exec_environment,
+ test_exec_environmentfile,
test_exec_umask,
test_exec_runtimedirectory,
+ test_exec_capabilityboundingset,
+ test_exec_oomscoreadjust,
+ test_exec_ioschedulingclass,
NULL,
};
test_function_t *test = NULL;
@@ -177,7 +258,7 @@ int main(int argc, char *argv[]) {
}
assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
- assert_se(set_unit_path(TEST_DIR) >= 0);
+ assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0);
r = manager_new(MANAGER_USER, true, &m);
if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) {
diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c
new file mode 100644
index 0000000000..09698c07c7
--- /dev/null
+++ b/src/test/test-extract-word.c
@@ -0,0 +1,546 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "extract-word.h"
+#include "log.h"
+#include "string-util.h"
+
+static void test_extract_first_word(void) {
+ const char *p, *original;
+ char *t;
+
+ p = original = "foobar waldo";
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "foobar"));
+ free(t);
+ assert_se(p == original + 7);
+
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"foobar\" \'waldo\'";
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "\"foobar\""));
+ free(t);
+ assert_se(p == original + 9);
+
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "\'waldo\'"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"foobar\" \'waldo\'";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+ assert_se(streq(t, "foobar"));
+ free(t);
+ assert_se(p == original + 9);
+
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"";
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+ assert_se(streq(t, "\""));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+ assert_se(p == original + 1);
+
+ p = original = "\'";
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+ assert_se(streq(t, "\'"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\'";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+ assert_se(p == original + 1);
+
+ p = original = "\'fooo";
+ assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
+ assert_se(streq(t, "\'fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\'fooo";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\'fooo";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"fooo";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "yay\'foo\'bar";
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "yay\'foo\'bar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "yay\'foo\'bar";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+ assert_se(streq(t, "yayfoobar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " foobar ";
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "foobar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
+ assert_se(streq(t, "foo\ba\x6ar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
+ assert_se(streq(t, "foobax6ar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
+ assert_se(streq(t, "föo"));
+ free(t);
+ assert_se(p == original + 13);
+
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0);
+ assert_se(streq(t, "pi\360\237\222\251le"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "fooo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "fooo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "foo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "foo::bar";
+ assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+ assert_se(streq(t, "foo"));
+ free(t);
+ assert_se(p == original + 5);
+
+ assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+ assert_se(streq(t, "bar"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word(&p, &t, ":", 0) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "foo\\:bar::waldo";
+ assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+ assert_se(streq(t, "foo:bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ assert_se(extract_first_word(&p, &t, ":", 0) == 1);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word(&p, &t, ":", 0) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "foo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "foo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "fooo bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
+ assert_se(streq(t, "fooo bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "fooo\\ bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "\\w+@\\K[\\d.]+";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
+ assert_se(p == original + 1);
+
+ p = original = "\\w+@\\K[\\d.]+";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "\\w+@\\K[\\d.]+"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\\w+\\b";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
+ assert_se(streq(t, "\\w+\b"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "-N ''";
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+ assert_se(streq(t, "-N"));
+ free(t);
+ assert_se(p == original + 3);
+
+ assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
+ assert_se(streq(t, ""));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = ":foo\\:bar::waldo:";
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+ assert_se(t);
+ assert_se(streq(t, ""));
+ free(t);
+ assert_se(p == original + 1);
+
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+ assert_se(streq(t, "foo:bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+ assert_se(t);
+ assert_se(streq(t, ""));
+ free(t);
+ assert_se(p == original + 11);
+
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(p == original + 17);
+
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
+ assert_se(streq(t, ""));
+ free(t);
+ assert_se(p == NULL);
+
+ assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
+ assert_se(!t);
+ assert_se(!p);
+}
+
+static void test_extract_first_word_and_warn(void) {
+ const char *p, *original;
+ char *t;
+
+ p = original = "foobar waldo";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foobar"));
+ free(t);
+ assert_se(p == original + 7);
+
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"foobar\" \'waldo\'";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foobar"));
+ free(t);
+ assert_se(p == original + 9);
+
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "waldo"));
+ free(t);
+ assert_se(isempty(p));
+
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
+ assert_se(!t);
+ assert_se(isempty(p));
+
+ p = original = "\"";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+ assert_se(p == original + 1);
+
+ p = original = "\'";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+ assert_se(p == original + 1);
+
+ p = original = "\'fooo";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\'fooo";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foo\ba\x6ar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " foo\\ba\\x6ar ";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foobax6ar"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "föo"));
+ free(t);
+ assert_se(p == original + 13);
+
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "pi\360\237\222\251le"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo\\"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
+ assert_se(p == original + 5);
+
+ p = original = "\"foo\\";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "foo"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "fooo\\ bar quux";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "fooo\\ bar"));
+ free(t);
+ assert_se(p == original + 10);
+
+ p = original = "\\w+@\\K[\\d.]+";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "\\w+@\\K[\\d.]+"));
+ free(t);
+ assert_se(isempty(p));
+
+ p = original = "\\w+\\b";
+ assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
+ assert_se(streq(t, "\\w+\b"));
+ free(t);
+ assert_se(isempty(p));
+}
+
+static void test_extract_many_words(void) {
+ const char *p, *original;
+ char *a, *b, *c;
+
+ p = original = "foobar waldi piep";
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, "foobar"));
+ assert_se(streq_ptr(b, "waldi"));
+ assert_se(streq_ptr(c, "piep"));
+ free(a);
+ free(b);
+ free(c);
+
+ p = original = "'foobar' wa\"ld\"i ";
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, "'foobar'"));
+ assert_se(streq_ptr(b, "wa\"ld\"i"));
+ assert_se(streq_ptr(c, NULL));
+ free(a);
+ free(b);
+
+ p = original = "'foobar' wa\"ld\"i ";
+ assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, "foobar"));
+ assert_se(streq_ptr(b, "waldi"));
+ assert_se(streq_ptr(c, NULL));
+ free(a);
+ free(b);
+
+ p = original = "";
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, NULL));
+ assert_se(streq_ptr(b, NULL));
+ assert_se(streq_ptr(c, NULL));
+
+ p = original = " ";
+ assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, NULL));
+ assert_se(streq_ptr(b, NULL));
+ assert_se(streq_ptr(c, NULL));
+
+ p = original = "foobar";
+ assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
+ assert_se(p == original);
+
+ p = original = "foobar waldi";
+ assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+ assert_se(p == original+7);
+ assert_se(streq_ptr(a, "foobar"));
+ free(a);
+
+ p = original = " foobar ";
+ assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
+ assert_se(isempty(p));
+ assert_se(streq_ptr(a, "foobar"));
+ free(a);
+}
+
+int main(int argc, char *argv[]) {
+ log_parse_environment();
+ log_open();
+
+ test_extract_first_word();
+ test_extract_first_word_and_warn();
+ test_extract_many_words();
+
+ return 0;
+}
diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c
index 242c5d9dc2..282aab1246 100644
--- a/src/test/test-fdset.c
+++ b/src/test/test-fdset.c
@@ -20,9 +20,11 @@
#include <fcntl.h>
#include <unistd.h>
+#include "fd-util.h"
#include "fdset.h"
-#include "util.h"
+#include "fileio.h"
#include "macro.h"
+#include "util.h"
static void test_fdset_new_fill(void) {
int fd = -1;
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index be3a87958f..e588681b86 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -23,13 +23,17 @@
#include <fcntl.h>
#include <unistd.h>
-#include "util.h"
-#include "process-util.h"
+#include "alloc-util.h"
+#include "ctype.h"
+#include "def.h"
+#include "env-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "env-util.h"
-#include "def.h"
-#include "ctype.h"
+#include "util.h"
static void test_parse_env_file(void) {
char t[] = "/tmp/test-fileio-in-XXXXXX",
@@ -241,18 +245,18 @@ static void test_status_field(void) {
unsigned long long total = 0, buffers = 0;
int r;
- assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0);
+ assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
puts(t);
assert_se(streq(t, "1"));
- r = get_status_field("/proc/meminfo", "MemTotal:", &p);
+ r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
if (r != -ENOENT) {
assert_se(r == 0);
puts(p);
assert_se(safe_atollu(p, &total) == 0);
}
- r = get_status_field("/proc/meminfo", "\nBuffers:", &s);
+ r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
if (r != -ENOENT) {
assert_se(r == 0);
puts(s);
@@ -263,7 +267,7 @@ static void test_status_field(void) {
assert_se(buffers < total);
/* Seccomp should be a good test for field full of zeros. */
- r = get_status_field("/proc/meminfo", "\nSeccomp:", &z);
+ r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
if (r != -ENOENT) {
assert_se(r == 0);
puts(z);
diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
index 50e5dee0a7..27816ac779 100644
--- a/src/test/test-fstab-util.c
+++ b/src/test/test-fstab-util.c
@@ -19,9 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "fstab-util.h"
-#include "util.h"
#include "log.h"
+#include "string-util.h"
+#include "util.h"
/*
int fstab_filter_options(const char *opts, const char *names,
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index 057b6c1dc1..6bf33306a9 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -17,9 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "hashmap.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
-#include "hashmap.h"
void test_hashmap_funcs(void);
@@ -692,8 +694,8 @@ static void test_hashmap_get2(void) {
hashmap_free_free_free(m);
}
-static unsigned long crippled_hashmap_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- return trivial_hash_func(p, hash_key) & 0xff;
+static void crippled_hashmap_func(const void *p, struct siphash *state) {
+ return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state);
}
static const struct hash_ops crippled_hashmap_ops = {
@@ -710,7 +712,7 @@ static void test_hashmap_many(void) {
unsigned n_entries;
} tests[] = {
{ .ops = NULL, .n_entries = 1 << 20 },
- { .ops = &crippled_hashmap_ops, .n_entries = 1 << 11 },
+ { .ops = &crippled_hashmap_ops, .n_entries = 1 << 14 },
};
diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c
index 6f5ef2615e..590175433c 100644
--- a/src/test/test-hostname-util.c
+++ b/src/test/test-hostname-util.c
@@ -21,9 +21,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "alloc-util.h"
#include "fileio.h"
#include "hostname-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_hostname_is_valid(void) {
assert_se(hostname_is_valid("foobar", false));
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index a6a0cd77a1..32cf3f80ca 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -21,11 +21,13 @@
#include <string.h>
-#include "systemd/sd-id128.h"
+#include "sd-daemon.h"
+#include "sd-id128.h"
-#include "util.h"
+#include "alloc-util.h"
#include "macro.h"
-#include "sd-daemon.h"
+#include "string-util.h"
+#include "util.h"
#define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10)
#define STR_WALDI "0102030405060708090a0b0c0d0e0f10"
diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c
index 4944bf6ad9..5841cb3fb1 100644
--- a/src/test/test-ipcrm.c
+++ b/src/test/test-ipcrm.c
@@ -19,8 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
#include "clean-ipc.h"
+#include "user-util.h"
+#include "util.h"
int main(int argc, char *argv[]) {
uid_t uid;
diff --git a/src/test/test-json.c b/src/test/test-json.c
index 1058c583c3..3995224eea 100644
--- a/src/test/test-json.c
+++ b/src/test/test-json.c
@@ -21,8 +21,10 @@
#include <math.h>
-#include "util.h"
+#include "alloc-util.h"
#include "json.h"
+#include "string-util.h"
+#include "util.h"
static void test_one(const char *data, ...) {
void *state = NULL;
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index 34c49b969a..350eaf734d 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -18,12 +18,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <unistd.h>
#include <getopt.h>
+#include <stdio.h>
#include <sys/epoll.h>
+#include <unistd.h>
#include "libudev.h"
+
+#include "string-util.h"
#include "udev-util.h"
#include "util.h"
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 7d7e08dc5d..5a12e959d4 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -21,9 +21,12 @@
#include <sys/socket.h>
+#include "alloc-util.h"
+#include "fd-util.h"
#include "namespace.h"
-#include "util.h"
#include "process-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_tmpdir(const char *id, const char *A, const char *B) {
_cleanup_free_ char *a, *b;
diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c
index 2879d7450f..a1e8774063 100644
--- a/src/test/test-netlink-manual.c
+++ b/src/test/test-netlink-manual.c
@@ -20,15 +20,16 @@
***/
#include <arpa/inet.h>
-#include <net/if.h>
+#include <libkmod.h>
#include <linux/ip.h>
+#include <net/if.h>
#include <linux/if_tunnel.h>
-#include <libkmod.h>
-#include "util.h"
-#include "macro.h"
#include "sd-netlink.h"
+#include "macro.h"
+#include "util.h"
+
static int load_module(const char *mod_name) {
struct kmod_ctx *ctx;
struct kmod_list *list = NULL, *l;
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
new file mode 100644
index 0000000000..d3ae0599ab
--- /dev/null
+++ b/src/test/test-parse-util.c
@@ -0,0 +1,452 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2013 Thomas H.P. Andersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <locale.h>
+#include <math.h>
+
+#include "log.h"
+#include "parse-util.h"
+
+static void test_parse_boolean(void) {
+ assert_se(parse_boolean("1") == 1);
+ assert_se(parse_boolean("y") == 1);
+ assert_se(parse_boolean("Y") == 1);
+ assert_se(parse_boolean("yes") == 1);
+ assert_se(parse_boolean("YES") == 1);
+ assert_se(parse_boolean("true") == 1);
+ assert_se(parse_boolean("TRUE") == 1);
+ assert_se(parse_boolean("on") == 1);
+ assert_se(parse_boolean("ON") == 1);
+
+ assert_se(parse_boolean("0") == 0);
+ assert_se(parse_boolean("n") == 0);
+ assert_se(parse_boolean("N") == 0);
+ assert_se(parse_boolean("no") == 0);
+ assert_se(parse_boolean("NO") == 0);
+ assert_se(parse_boolean("false") == 0);
+ assert_se(parse_boolean("FALSE") == 0);
+ assert_se(parse_boolean("off") == 0);
+ assert_se(parse_boolean("OFF") == 0);
+
+ assert_se(parse_boolean("garbage") < 0);
+ assert_se(parse_boolean("") < 0);
+ assert_se(parse_boolean("full") < 0);
+}
+
+static void test_parse_pid(void) {
+ int r;
+ pid_t pid;
+
+ r = parse_pid("100", &pid);
+ assert_se(r == 0);
+ assert_se(pid == 100);
+
+ r = parse_pid("0x7FFFFFFF", &pid);
+ assert_se(r == 0);
+ assert_se(pid == 2147483647);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("0", &pid);
+ assert_se(r == -ERANGE);
+ assert_se(pid == 65);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("-100", &pid);
+ assert_se(r == -ERANGE);
+ assert_se(pid == 65);
+
+ pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
+ r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
+ assert_se(r == -ERANGE);
+ assert_se(pid == 65);
+
+ r = parse_pid("junk", &pid);
+ assert_se(r == -EINVAL);
+}
+
+static void test_parse_mode(void) {
+ mode_t m;
+
+ assert_se(parse_mode("-1", &m) < 0);
+ assert_se(parse_mode("", &m) < 0);
+ assert_se(parse_mode("888", &m) < 0);
+ assert_se(parse_mode("77777", &m) < 0);
+
+ assert_se(parse_mode("544", &m) >= 0 && m == 0544);
+ assert_se(parse_mode("777", &m) >= 0 && m == 0777);
+ assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
+ assert_se(parse_mode("0", &m) >= 0 && m == 0);
+}
+
+static void test_parse_size(void) {
+ uint64_t bytes;
+
+ assert_se(parse_size("111", 1024, &bytes) == 0);
+ assert_se(bytes == 111);
+
+ assert_se(parse_size("111.4", 1024, &bytes) == 0);
+ assert_se(bytes == 111);
+
+ assert_se(parse_size(" 112 B", 1024, &bytes) == 0);
+ assert_se(bytes == 112);
+
+ assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0);
+ assert_se(bytes == 112);
+
+ assert_se(parse_size("3.5 K", 1024, &bytes) == 0);
+ assert_se(bytes == 3*1024 + 512);
+
+ assert_se(parse_size("3. K", 1024, &bytes) == 0);
+ assert_se(bytes == 3*1024);
+
+ assert_se(parse_size("3.0 K", 1024, &bytes) == 0);
+ assert_se(bytes == 3*1024);
+
+ assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0);
+ assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512);
+
+ assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("3.5G3B", 1024, &bytes) == 0);
+ assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3);
+
+ assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0);
+ assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4);
+
+ assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("4T3G3B", 1024, &bytes) == 0);
+ assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+ assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0);
+ assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
+
+ assert_se(parse_size("12P", 1024, &bytes) == 0);
+ assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
+
+ assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("3E 2P", 1024, &bytes) == 0);
+ assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
+
+ assert_se(parse_size("12X", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL);
+
+ assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE);
+ assert_se(parse_size("-1", 1024, &bytes) == -ERANGE);
+ assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE);
+
+ assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE);
+
+ assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
+}
+
+static void test_parse_range(void) {
+ unsigned lower, upper;
+
+ /* Successful cases */
+ assert_se(parse_range("111", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 111);
+
+ assert_se(parse_range("111-123", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 123);
+
+ assert_se(parse_range("123-111", &lower, &upper) == 0);
+ assert_se(lower == 123);
+ assert_se(upper == 111);
+
+ assert_se(parse_range("123-123", &lower, &upper) == 0);
+ assert_se(lower == 123);
+ assert_se(upper == 123);
+
+ assert_se(parse_range("0", &lower, &upper) == 0);
+ assert_se(lower == 0);
+ assert_se(upper == 0);
+
+ assert_se(parse_range("0-15", &lower, &upper) == 0);
+ assert_se(lower == 0);
+ assert_se(upper == 15);
+
+ assert_se(parse_range("15-0", &lower, &upper) == 0);
+ assert_se(lower == 15);
+ assert_se(upper == 0);
+
+ assert_se(parse_range("128-65535", &lower, &upper) == 0);
+ assert_se(lower == 128);
+ assert_se(upper == 65535);
+
+ assert_se(parse_range("1024-4294967295", &lower, &upper) == 0);
+ assert_se(lower == 1024);
+ assert_se(upper == 4294967295);
+
+ /* Leading whitespace is acceptable */
+ assert_se(parse_range(" 111", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 111);
+
+ assert_se(parse_range(" 111-123", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 123);
+
+ assert_se(parse_range("111- 123", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 123);
+
+ assert_se(parse_range("\t111-\t123", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 123);
+
+ assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0);
+ assert_se(lower == 111);
+ assert_se(upper == 123);
+
+ /* Error cases, make sure they fail as expected */
+ lower = upper = 9999;
+ assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("garbage", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* Empty string */
+ lower = upper = 9999;
+ assert_se(parse_range("", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */
+ assert_se(parse_range("111--123", &lower, &upper) == -ERANGE);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* Error on trailing dash */
+ assert_se(parse_range("111-", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111--", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111- ", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* Whitespace is not a separator */
+ assert_se(parse_range("111 123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* Trailing whitespace is invalid (from safe_atou) */
+ assert_se(parse_range("111 ", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+
+ /* Out of the "unsigned" range, this is 1<<64 */
+ assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE);
+ assert_se(lower == 9999);
+ assert_se(upper == 9999);
+}
+
+static void test_safe_atolli(void) {
+ int r;
+ long long l;
+
+ r = safe_atolli("12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 12345);
+
+ r = safe_atolli("junk", &l);
+ assert_se(r == -EINVAL);
+}
+
+static void test_safe_atou16(void) {
+ int r;
+ uint16_t l;
+
+ r = safe_atou16("12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 12345);
+
+ r = safe_atou16("123456", &l);
+ assert_se(r == -ERANGE);
+
+ r = safe_atou16("junk", &l);
+ assert_se(r == -EINVAL);
+}
+
+static void test_safe_atoi16(void) {
+ int r;
+ int16_t l;
+
+ r = safe_atoi16("-12345", &l);
+ assert_se(r == 0);
+ assert_se(l == -12345);
+
+ r = safe_atoi16("36536", &l);
+ assert_se(r == -ERANGE);
+
+ r = safe_atoi16("junk", &l);
+ assert_se(r == -EINVAL);
+}
+
+static void test_safe_atod(void) {
+ int r;
+ double d;
+ char *e;
+
+ r = safe_atod("junk", &d);
+ assert_se(r == -EINVAL);
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(fabs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ strtod("0,5", &e);
+ assert_se(*e == ',');
+
+ /* Check if this really is locale independent */
+ if (setlocale(LC_NUMERIC, "de_DE.utf8")) {
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(fabs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001);
+ }
+
+ /* And check again, reset */
+ assert_se(setlocale(LC_NUMERIC, "C"));
+
+ r = safe_atod("0.2244", &d);
+ assert_se(r == 0);
+ assert_se(fabs(d - 0.2244) < 0.000001);
+
+ r = safe_atod("0,5", &d);
+ assert_se(r == -EINVAL);
+
+ errno = 0;
+ strtod("0,5", &e);
+ assert_se(*e == ',');
+}
+
+int main(int argc, char *argv[]) {
+ log_parse_environment();
+ log_open();
+
+ test_parse_boolean();
+ test_parse_pid();
+ test_parse_mode();
+ test_parse_size();
+ test_parse_range();
+ test_safe_atolli();
+ test_safe_atou16();
+ test_safe_atoi16();
+ test_safe_atod();
+
+ return 0;
+}
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index aa4bac6cdd..65cb894ff7 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -19,29 +19,39 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdlib.h>
#include <sys/stat.h>
-#include "path-lookup.h"
#include "log.h"
-#include "strv.h"
+#include "path-lookup.h"
#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
static void test_paths(ManagerRunningAs running_as, bool personal) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
- _cleanup_lookup_paths_free_ LookupPaths lp = {};
- char *exists, *not;
+ _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
+ _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
+ char *exists, *not, *systemd_unit_path;
assert_se(mkdtemp(template));
exists = strjoina(template, "/exists");
assert_se(mkdir(exists, 0755) == 0);
not = strjoina(template, "/not");
- assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0);
+ assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
+ assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0);
+
+ assert_se(!strv_isempty(lp_without_env.unit_path));
+ assert_se(strv_contains(lp_without_env.unit_path, exists));
+ assert_se(strv_contains(lp_without_env.unit_path, not));
- assert_se(!strv_isempty(lp.unit_path));
- assert_se(strv_contains(lp.unit_path, exists));
- assert_se(strv_contains(lp.unit_path, not));
+ systemd_unit_path = strjoina(template, "/systemd-unit-path");
+ assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0);
+ assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0);
+ assert_se(strv_length(lp_with_env.unit_path) == 1);
+ assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path));
assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index fce4e81a09..3f0f0264ab 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -20,14 +20,18 @@
***/
#include <stdio.h>
-#include <unistd.h>
#include <sys/mount.h>
+#include <unistd.h>
-#include "path-util.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "macro.h"
-#include "strv.h"
+#include "mount-util.h"
+#include "path-util.h"
#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
#define test_path_compare(a, b, result) { \
assert_se(path_compare(a, b) == result); \
@@ -75,20 +79,6 @@ static void test_path(void) {
assert_se(streq(basename("/aa///file..."), "file..."));
assert_se(streq(basename("file.../"), ""));
-#define test_parent(x, y) { \
- _cleanup_free_ char *z = NULL; \
- int r = path_get_parent(x, &z); \
- printf("expected: %s\n", y ? y : "error"); \
- printf("actual: %s\n", r<0 ? "error" : z); \
- assert_se((y==NULL) ^ (r==0)); \
- assert_se(y==NULL || path_equal(z, y)); \
- }
-
- test_parent("./aa/bb/../file.da.", "./aa/bb/..");
- test_parent("/aa///.file", "/aa///");
- test_parent("/aa///file...", "/aa///");
- test_parent("file.../", NULL);
-
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY);
assert_se(fd >= 0);
assert_se(fd_is_mount_point(fd, "/", 0) > 0);
@@ -104,32 +94,28 @@ static void test_path(void) {
}
}
-static void test_find_binary(const char *self, bool local) {
+static void test_find_binary(const char *self) {
char *p;
- assert_se(find_binary("/bin/sh", local, &p) == 0);
+ assert_se(find_binary("/bin/sh", &p) == 0);
puts(p);
- assert_se(streq(p, "/bin/sh"));
+ assert_se(path_equal(p, "/bin/sh"));
free(p);
- assert_se(find_binary(self, local, &p) == 0);
+ assert_se(find_binary(self, &p) == 0);
puts(p);
assert_se(endswith(p, "/test-path-util"));
assert_se(path_is_absolute(p));
free(p);
- assert_se(find_binary("sh", local, &p) == 0);
+ assert_se(find_binary("sh", &p) == 0);
puts(p);
assert_se(endswith(p, "/sh"));
assert_se(path_is_absolute(p));
free(p);
- assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT);
-
- assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) ==
- (local ? -ENOENT : 0));
- if (!local)
- free(p);
+ assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT);
+ assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT);
}
static void test_prefixes(void) {
@@ -210,9 +196,10 @@ static void test_fsck_exists(void) {
unsetenv("PATH");
/* fsck.minix is provided by util-linux and will probably exist. */
- assert_se(fsck_exists("minix") == 0);
+ assert_se(fsck_exists("minix") == 1);
- assert_se(fsck_exists("AbCdE") == -ENOENT);
+ assert_se(fsck_exists("AbCdE") == 0);
+ assert_se(fsck_exists("/../bin/") == 0);
}
static void test_make_relative(void) {
@@ -450,8 +437,7 @@ static void test_path_is_mount_point(void) {
int main(int argc, char **argv) {
test_path();
- test_find_binary(argv[0], true);
- test_find_binary(argv[0], false);
+ test_find_binary(argv[0]);
test_prefixes();
test_path_join();
test_fsck_exists();
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 676c9f1793..8302bdd283 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -17,16 +17,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <stdbool.h>
+#include <stdio.h>
-#include "unit.h"
-#include "manager.h"
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "macro.h"
-#include "strv.h"
+#include "manager.h"
#include "mkdir.h"
#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit.h"
+#include "util.h"
typedef void (*test_function_t)(Manager *m);
@@ -254,7 +258,7 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- assert_se(set_unit_path(TEST_DIR) >= 0);
+ assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
for (test = tests; test && *test; test++) {
int r;
diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c
index dfedc9b8dc..07273ffe79 100644
--- a/src/test/test-prioq.c
+++ b/src/test/test-prioq.c
@@ -21,10 +21,11 @@
#include <stdlib.h>
-#include "util.h"
-#include "set.h"
+#include "alloc-util.h"
#include "prioq.h"
+#include "set.h"
#include "siphash24.h"
+#include "util.h"
#define SET_SIZE 1024*4
@@ -89,13 +90,10 @@ static int test_compare(const void *a, const void *b) {
return 0;
}
-static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void test_hash(const void *a, struct siphash *state) {
const struct test *x = a;
- uint64_t u;
-
- siphash24((uint8_t*) &u, &x->value, sizeof(x->value), hash_key);
- return (unsigned long) u;
+ siphash24_compress(&x->value, sizeof(x->value), state);
}
static const struct hash_ops test_hash_ops = {
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index eb0f443a43..48be5a3a87 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -18,17 +18,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
-#include "process-util.h"
+#include "alloc-util.h"
#include "log.h"
-#include "util.h"
#include "macro.h"
-#include "virt.h"
+#include "process-util.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
+#include "virt.h"
static void test_get_process_comm(void) {
struct stat st;
@@ -53,7 +55,7 @@ static void test_get_process_comm(void) {
assert_se(get_process_cmdline(1, 8, false, &d) >= 0);
log_info("pid1 cmdline truncated: '%s'", d);
- assert_se(get_parent_of_pid(1, &e) >= 0);
+ assert_se(get_process_ppid(1, &e) >= 0);
log_info("pid1 ppid: "PID_FMT, e);
assert_se(e == 0);
diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c
index b1d42d77fd..2de2091561 100644
--- a/src/test/test-replace-var.c
+++ b/src/test/test-replace-var.c
@@ -21,9 +21,10 @@
#include <string.h>
-#include "util.h"
#include "macro.h"
#include "replace-var.h"
+#include "string-util.h"
+#include "util.h"
static char *lookup(const char *variable, void *userdata) {
return strjoin("<<<", variable, ">>>", NULL);
diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c
index f5bae65bef..b3ccc7509d 100644
--- a/src/test/test-sigbus.c
+++ b/src/test/test-sigbus.c
@@ -21,8 +21,9 @@
#include <sys/mman.h>
-#include "util.h"
+#include "fd-util.h"
#include "sigbus.h"
+#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_close_ int fd = -1;
diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c
new file mode 100644
index 0000000000..2402da6a6f
--- /dev/null
+++ b/src/test/test-siphash24.c
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 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 "util.h"
+#include "siphash24.h"
+
+#define ITERATIONS 10000000ULL
+
+/* see https://131002.net/siphash/siphash.pdf, Appendix A */
+int main(int argc, char *argv[]) {
+ struct siphash state = {};
+ const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e };
+ const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ uint64_t out = 0;
+ unsigned i, j;
+
+ siphash24((uint8_t *)&out, in, sizeof(in), key);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+
+ /* verify the internal state as given in the above paper */
+ siphash24_init(&state, key);
+ assert_se(state.v0 == 0x7469686173716475);
+ assert_se(state.v1 == 0x6b617f6d656e6665);
+ assert_se(state.v2 == 0x6b7f62616d677361);
+ assert_se(state.v3 == 0x7b6b696e727e6c7b);
+ siphash24_compress(in, sizeof(in), &state);
+ assert_se(state.v0 == 0x4a017198de0a59e0);
+ assert_se(state.v1 == 0x0d52f6f62a4f59a4);
+ assert_se(state.v2 == 0x634cb3577b01fd3d);
+ assert_se(state.v3 == 0xa5224d6f55c7d9c8);
+ siphash24_finalize((uint8_t*)&out, &state);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+ assert_se(state.v0 == 0xf6bcd53893fecff1);
+ assert_se(state.v1 == 0x54b9964c7ea0d937);
+ assert_se(state.v2 == 0x1b38329c099bb55a);
+ assert_se(state.v3 == 0x1814bb89ad7be679);
+
+ /* verify that decomposing the input in three chunks gives the
+ same result */
+ for (i = 0; i < sizeof(in); i++) {
+ for (j = i; j < sizeof(in); j++) {
+ siphash24_init(&state, key);
+ siphash24_compress(in, i, &state);
+ siphash24_compress(&in[i], j - i, &state);
+ siphash24_compress(&in[j], sizeof(in) - j, &state);
+ siphash24_finalize((uint8_t*)&out, &state);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+ }
+ }
+}
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 2c18090ae5..b9699b2028 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -17,12 +17,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "socket-util.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "fd-util.h"
#include "in-addr-util.h"
-#include "util.h"
-#include "macro.h"
#include "log.h"
-#include "async.h"
+#include "macro.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "util.h"
static void test_socket_address_parse(void) {
SocketAddress a;
diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c
index 4ec648ae66..1d8eda0c15 100644
--- a/src/test/test-strbuf.c
+++ b/src/test/test-strbuf.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "strbuf.h"
+#include "string-util.h"
#include "strv.h"
#include "util.h"
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
new file mode 100644
index 0000000000..25444c794a
--- /dev/null
+++ b/src/test/test-string-util.c
@@ -0,0 +1,61 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "string-util.h"
+
+static void test_string_erase(void) {
+ char *x;
+
+ x = strdupa("");
+ assert_se(streq(string_erase(x), ""));
+
+ x = strdupa("1");
+ assert_se(streq(string_erase(x), "x"));
+
+ x = strdupa("12");
+ assert_se(streq(string_erase(x), "xx"));
+
+ x = strdupa("123");
+ assert_se(streq(string_erase(x), "xxx"));
+
+ x = strdupa("1234");
+ assert_se(streq(string_erase(x), "xxxx"));
+
+ x = strdupa("12345");
+ assert_se(streq(string_erase(x), "xxxxx"));
+
+ x = strdupa("123456");
+ assert_se(streq(string_erase(x), "xxxxxx"));
+
+ x = strdupa("1234567");
+ assert_se(streq(string_erase(x), "xxxxxxx"));
+
+ x = strdupa("12345678");
+ assert_se(streq(string_erase(x), "xxxxxxxx"));
+
+ x = strdupa("123456789");
+ assert_se(streq(string_erase(x), "xxxxxxxxx"));
+}
+
+int main(int argc, char *argv[]) {
+ test_string_erase();
+ return 0;
+}
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
index 6cec8768b1..10fc98ced5 100644
--- a/src/test/test-strip-tab-ansi.c
+++ b/src/test/test-strip-tab-ansi.c
@@ -21,8 +21,9 @@
#include <stdio.h>
-#include "util.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
int main(int argc, char *argv[]) {
char *p;
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index bff43950a9..c27f15283e 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -22,9 +22,11 @@
#include <string.h>
-#include "util.h"
+#include "alloc-util.h"
#include "specifier.h"
+#include "string-util.h"
#include "strv.h"
+#include "util.h"
static void test_specifier_printf(void) {
static const Specifier table[] = {
@@ -155,7 +157,7 @@ static void test_strv_join(void) {
static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
_cleanup_free_ char *p;
- _cleanup_strv_free_ char **s;
+ _cleanup_strv_free_ char **s = NULL;
char **t;
int r;
@@ -166,7 +168,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
assert_se(streq(p, quoted));
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(s));
assert_se(s);
STRV_FOREACH(t, s) {
assert_se(*t);
@@ -183,7 +185,7 @@ static void test_strv_unquote(const char *quoted, char **list) {
int r;
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(list));
assert_se(s);
j = strv_join(s, " | ");
assert_se(j);
@@ -225,7 +227,7 @@ static void test_strv_split_extract(void) {
int r;
r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(l));
assert_se(streq_ptr(l[0], ""));
assert_se(streq_ptr(l[1], "foo:bar"));
assert_se(streq_ptr(l[2], ""));
@@ -341,11 +343,11 @@ static void test_strv_extend_strv(void) {
_cleanup_strv_free_ char **a = NULL, **b = NULL;
a = strv_new("abc", "def", "ghi", NULL);
- b = strv_new("jkl", "mno", "pqr", NULL);
+ b = strv_new("jkl", "mno", "abc", "pqr", NULL);
assert_se(a);
assert_se(b);
- assert_se(strv_extend_strv(&a, b) >= 0);
+ assert_se(strv_extend_strv(&a, b, true) == 3);
assert_se(streq(a[0], "abc"));
assert_se(streq(a[1], "def"));
@@ -569,6 +571,77 @@ static void test_strv_shell_escape(void) {
assert_se(streq_ptr(v[3], NULL));
}
+static void test_strv_skip_one(char **a, size_t n, char **b) {
+ a = strv_skip(a, n);
+ assert_se(strv_equal(a, b));
+}
+
+static void test_strv_skip(void) {
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL));
+
+ test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux"));
+ test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL));
+
+ test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL));
+}
+
+static void test_strv_extend_n(void) {
+ _cleanup_strv_free_ char **v = NULL;
+
+ v = strv_new("foo", "bar", NULL);
+ assert_se(v);
+
+ assert_se(strv_extend_n(&v, "waldo", 3) >= 0);
+ assert_se(strv_extend_n(&v, "piep", 2) >= 0);
+
+ assert_se(streq(v[0], "foo"));
+ assert_se(streq(v[1], "bar"));
+ assert_se(streq(v[2], "waldo"));
+ assert_se(streq(v[3], "waldo"));
+ assert_se(streq(v[4], "waldo"));
+ assert_se(streq(v[5], "piep"));
+ assert_se(streq(v[6], "piep"));
+ assert_se(v[7] == NULL);
+
+ v = strv_free(v);
+
+ assert_se(strv_extend_n(&v, "foo", 1) >= 0);
+ assert_se(strv_extend_n(&v, "bar", 0) >= 0);
+
+ assert_se(streq(v[0], "foo"));
+ assert_se(v[1] == NULL);
+}
+
+static void test_strv_make_nulstr_one(char **l) {
+ _cleanup_free_ char *b = NULL, *c = NULL;
+ _cleanup_strv_free_ char **q = NULL;
+ size_t n, m;
+
+ assert_se(strv_make_nulstr(l, &b, &n) >= 0);
+ assert_se(q = strv_parse_nulstr(b, n));
+ assert_se(strv_equal(l, q));
+
+ assert_se(strv_make_nulstr(q, &c, &m) >= 0);
+ assert_se(m == n);
+ assert_se(memcmp(b, c, m) == 0);
+}
+
+static void test_strv_make_nulstr(void) {
+ test_strv_make_nulstr_one(NULL);
+ test_strv_make_nulstr_one(STRV_MAKE(NULL));
+ test_strv_make_nulstr_one(STRV_MAKE("foo"));
+ test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
+ test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
+}
+
int main(int argc, char *argv[]) {
test_specifier_printf();
test_strv_foreach();
@@ -627,6 +700,9 @@ int main(int argc, char *argv[]) {
test_strv_is_uniq();
test_strv_reverse();
test_strv_shell_escape();
+ test_strv_skip();
+ test_strv_extend_n();
+ test_strv_make_nulstr();
return 0;
}
diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c
index 858a4081da..e411d479ab 100644
--- a/src/test/test-strxcpyx.c
+++ b/src/test/test-strxcpyx.c
@@ -21,8 +21,9 @@
#include <string.h>
-#include "util.h"
+#include "string-util.h"
#include "strxcpyx.h"
+#include "util.h"
static void test_strpcpy(void) {
char target[25];
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index 0e5ab1645f..ed4abdbf12 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -17,7 +17,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "architecture.h"
#include "automount.h"
+#include "bus-xml-policy.h"
+#include "busname.h"
#include "cgroup.h"
#include "compress.h"
#include "condition.h"
@@ -25,7 +28,10 @@
#include "execute.h"
#include "install.h"
#include "job.h"
+#include "journald-server.h"
#include "kill.h"
+#include "link-config.h"
+#include "locale-util.h"
#include "log.h"
#include "logs-show.h"
#include "mount.h"
@@ -42,12 +48,7 @@
#include "unit-name.h"
#include "unit.h"
#include "util.h"
-#include "architecture.h"
-#include "link-config.h"
-#include "bus-xml-policy.h"
-#include "busname.h"
-#include "journald-server.h"
-#include "locale-util.h"
+#include "rlimit-util.h"
#include "test-tables.h"
diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c
index d81fdb9923..e940b5a204 100644
--- a/src/test/test-terminal-util.c
+++ b/src/test/test-terminal-util.c
@@ -21,10 +21,12 @@
#include <stdio.h>
#include <stdbool.h>
-#include "terminal-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
#include "macro.h"
+#include "terminal-util.h"
#include "util.h"
-#include "log.h"
static void test_default_term_for_tty(void) {
puts(default_term_for_tty("/dev/tty23"));
diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c
index 221dd67eb2..a8bd722e44 100644
--- a/src/test/test-tmpfiles.c
+++ b/src/test/test-tmpfiles.c
@@ -20,12 +20,16 @@
***/
#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "string-util.h"
+#include "util.h"
int main(int argc, char** argv) {
const char *p = argv[1] ?: "/tmp";
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 2b765a3e90..9cc64f7c68 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -18,19 +18,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
#include <errno.h>
-#include <unistd.h>
#include <sched.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
+#include <unistd.h>
+#include "fs-util.h"
#include "missing.h"
#include "selinux-util.h"
#include "signal-util.h"
-#include "udev.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
static int fake_filesystems(void) {
static const struct fakefs {
@@ -42,7 +44,7 @@ static int fake_filesystems(void) {
{ "test/dev", "/dev", "failed to mount test /dev" },
{ "test/run", "/run", "failed to mount test /run" },
{ "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" },
- { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" },
+ { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" },
};
unsigned int i;
int err;
@@ -64,7 +66,7 @@ static int fake_filesystems(void) {
err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
if (err < 0) {
err = -errno;
- fprintf(stderr, "%s %m", fakefss[i].error);
+ fprintf(stderr, "%s %m\n", fakefss[i].error);
return err;
}
}
diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c
index bc5baa2fcb..4dcf10e26d 100644
--- a/src/test/test-uid-range.c
+++ b/src/test/test-uid-range.c
@@ -21,8 +21,10 @@
#include <stddef.h>
-#include "util.h"
+#include "alloc-util.h"
#include "uid-range.h"
+#include "user-util.h"
+#include "util.h"
int main(int argc, char *argv[]) {
_cleanup_free_ UidRange *p = NULL;
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 8358789e6f..f9107e0d0d 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -20,23 +20,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
+#include <fcntl.h>
#include <stddef.h>
+#include <stdio.h>
#include <string.h>
+#include <sys/capability.h>
#include <unistd.h>
-#include <fcntl.h>
-#include "install.h"
-#include "install-printf.h"
-#include "specifier.h"
-#include "util.h"
-#include "macro.h"
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "hashmap.h"
+#include "hostname-util.h"
+#include "install-printf.h"
+#include "install.h"
#include "load-fragment.h"
+#include "macro.h"
+#include "specifier.h"
+#include "string-util.h"
#include "strv.h"
-#include "fileio.h"
#include "test-helper.h"
-#include "hostname-util.h"
+#include "util.h"
static int test_unit_file_get_set(void) {
int r;
@@ -626,6 +630,57 @@ static void test_install_printf(void) {
expect(i4, "%U", "0");
}
+static uint64_t make_cap(int cap) {
+ return ((uint64_t) 1ULL << (uint64_t) cap);
+}
+
+static void test_config_parse_bounding_set(void) {
+ /* int config_parse_bounding_set(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) */
+ int r;
+ uint64_t capability_bounding_set_drop = 0;
+
+ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, "CAP_NET_RAW",
+ &capability_bounding_set_drop, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW));
+
+ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, "CAP_NET_ADMIN",
+ &capability_bounding_set_drop, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
+
+ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, "",
+ &capability_bounding_set_drop, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL));
+
+ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, "~",
+ &capability_bounding_set_drop, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set_drop == (uint64_t) 0ULL);
+
+ capability_bounding_set_drop = 0;
+ r = config_parse_bounding_set(NULL, "fake", 1, "section", 1,
+ "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage",
+ &capability_bounding_set_drop, NULL);
+ assert_se(r >= 0);
+ assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN)));
+}
+
int main(int argc, char *argv[]) {
int r;
@@ -634,6 +689,7 @@ int main(int argc, char *argv[]) {
r = test_unit_file_get_set();
test_config_parse_exec();
+ test_config_parse_bounding_set();
test_load_env_file_1();
test_load_env_file_2();
test_load_env_file_3();
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index e5405fb7f3..9db7853dd4 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -21,21 +21,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <pwd.h>
+#include "alloc-util.h"
+#include "hostname-util.h"
+#include "macro.h"
#include "manager.h"
-#include "unit.h"
+#include "path-util.h"
+#include "specifier.h"
+#include "string-util.h"
+#include "test-helper.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "specifier.h"
+#include "unit.h"
#include "util.h"
-#include "macro.h"
-#include "path-util.h"
-#include "test-helper.h"
-#include "hostname-util.h"
static void test_unit_name_is_valid(void) {
assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
new file mode 100644
index 0000000000..09d37087e5
--- /dev/null
+++ b/src/test/test-user-util.c
@@ -0,0 +1,54 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "macro.h"
+#include "string-util.h"
+#include "user-util.h"
+#include "util.h"
+
+static void test_uid_to_name_one(uid_t uid, const char *name) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(t = uid_to_name(uid));
+ assert_se(streq_ptr(t, name));
+}
+
+static void test_gid_to_name_one(gid_t gid, const char *name) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(t = gid_to_name(gid));
+ assert_se(streq_ptr(t, name));
+}
+
+int main(int argc, char*argv[]) {
+
+ test_uid_to_name_one(0, "root");
+ test_uid_to_name_one(0xFFFF, "65535");
+ test_uid_to_name_one(0xFFFFFFFF, "4294967295");
+
+ test_gid_to_name_one(0, "root");
+ test_gid_to_name_one(TTY_GID, "tty");
+ test_gid_to_name_one(0xFFFF, "65535");
+ test_gid_to_name_one(0xFFFFFFFF, "4294967295");
+
+ return 0;
+}
diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c
index 346f8524c6..0af8349732 100644
--- a/src/test/test-utf8.c
+++ b/src/test/test-utf8.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "utf8.h"
#include "util.h"
+#include "string-util.h"
static void test_utf8_is_printable(void) {
assert_se(utf8_is_printable("ascii is valid\tunicode", 22));
diff --git a/src/test/test-util.c b/src/test/test-util.c
index f434c5ceba..f6ed55878c 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -20,25 +20,43 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <locale.h>
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
-#include <math.h>
+#include <string.h>
+#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <unistd.h>
-#include "util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "conf-parser.h"
+#include "cpu-set-util.h"
#include "def.h"
+#include "escape.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "conf-parser.h"
-#include "virt.h"
+#include "fs-util.h"
+#include "fstab-util.h"
+#include "glob-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
#include "process-util.h"
+#include "rm-rf.h"
#include "signal-util.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
+#include "web-util.h"
+#include "xattr-util.h"
static void test_streq_ptr(void) {
assert_se(streq_ptr(NULL, NULL));
@@ -218,63 +236,6 @@ static void test_close_many(void) {
unlink(name2);
}
-static void test_parse_boolean(void) {
- assert_se(parse_boolean("1") == 1);
- assert_se(parse_boolean("y") == 1);
- assert_se(parse_boolean("Y") == 1);
- assert_se(parse_boolean("yes") == 1);
- assert_se(parse_boolean("YES") == 1);
- assert_se(parse_boolean("true") == 1);
- assert_se(parse_boolean("TRUE") == 1);
- assert_se(parse_boolean("on") == 1);
- assert_se(parse_boolean("ON") == 1);
-
- assert_se(parse_boolean("0") == 0);
- assert_se(parse_boolean("n") == 0);
- assert_se(parse_boolean("N") == 0);
- assert_se(parse_boolean("no") == 0);
- assert_se(parse_boolean("NO") == 0);
- assert_se(parse_boolean("false") == 0);
- assert_se(parse_boolean("FALSE") == 0);
- assert_se(parse_boolean("off") == 0);
- assert_se(parse_boolean("OFF") == 0);
-
- assert_se(parse_boolean("garbage") < 0);
- assert_se(parse_boolean("") < 0);
- assert_se(parse_boolean("full") < 0);
-}
-
-static void test_parse_pid(void) {
- int r;
- pid_t pid;
-
- r = parse_pid("100", &pid);
- assert_se(r == 0);
- assert_se(pid == 100);
-
- r = parse_pid("0x7FFFFFFF", &pid);
- assert_se(r == 0);
- assert_se(pid == 2147483647);
-
- pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
- r = parse_pid("0", &pid);
- assert_se(r == -ERANGE);
- assert_se(pid == 65);
-
- pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
- r = parse_pid("-100", &pid);
- assert_se(r == -ERANGE);
- assert_se(pid == 65);
-
- pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */
- r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid);
- assert_se(r == -ERANGE);
- assert_se(pid == 65);
-
- r = parse_pid("junk", &pid);
- assert_se(r == -EINVAL);
-}
-
static void test_parse_uid(void) {
int r;
uid_t uid;
@@ -290,96 +251,6 @@ static void test_parse_uid(void) {
assert_se(r == -EINVAL);
}
-static void test_safe_atou16(void) {
- int r;
- uint16_t l;
-
- r = safe_atou16("12345", &l);
- assert_se(r == 0);
- assert_se(l == 12345);
-
- r = safe_atou16("123456", &l);
- assert_se(r == -ERANGE);
-
- r = safe_atou16("junk", &l);
- assert_se(r == -EINVAL);
-}
-
-static void test_safe_atoi16(void) {
- int r;
- int16_t l;
-
- r = safe_atoi16("-12345", &l);
- assert_se(r == 0);
- assert_se(l == -12345);
-
- r = safe_atoi16("36536", &l);
- assert_se(r == -ERANGE);
-
- r = safe_atoi16("junk", &l);
- assert_se(r == -EINVAL);
-}
-
-static void test_safe_atolli(void) {
- int r;
- long long l;
-
- r = safe_atolli("12345", &l);
- assert_se(r == 0);
- assert_se(l == 12345);
-
- r = safe_atolli("junk", &l);
- assert_se(r == -EINVAL);
-}
-
-static void test_safe_atod(void) {
- int r;
- double d;
- char *e;
-
- r = safe_atod("junk", &d);
- assert_se(r == -EINVAL);
-
- r = safe_atod("0.2244", &d);
- assert_se(r == 0);
- assert_se(fabs(d - 0.2244) < 0.000001);
-
- r = safe_atod("0,5", &d);
- assert_se(r == -EINVAL);
-
- errno = 0;
- strtod("0,5", &e);
- assert_se(*e == ',');
-
- /* Check if this really is locale independent */
- if (setlocale(LC_NUMERIC, "de_DE.utf8")) {
-
- r = safe_atod("0.2244", &d);
- assert_se(r == 0);
- assert_se(fabs(d - 0.2244) < 0.000001);
-
- r = safe_atod("0,5", &d);
- assert_se(r == -EINVAL);
-
- errno = 0;
- assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001);
- }
-
- /* And check again, reset */
- assert_se(setlocale(LC_NUMERIC, "C"));
-
- r = safe_atod("0.2244", &d);
- assert_se(r == 0);
- assert_se(fabs(d - 0.2244) < 0.000001);
-
- r = safe_atod("0,5", &d);
- assert_se(r == -EINVAL);
-
- errno = 0;
- strtod("0,5", &e);
- assert_se(*e == ',');
-}
-
static void test_strappend(void) {
_cleanup_free_ char *t1, *t2, *t3, *t4;
@@ -892,81 +763,13 @@ static void test_protect_errno(void) {
assert_se(errno == 12);
}
-static void test_parse_size(void) {
- uint64_t bytes;
-
- assert_se(parse_size("111", 1024, &bytes) == 0);
- assert_se(bytes == 111);
-
- assert_se(parse_size("111.4", 1024, &bytes) == 0);
- assert_se(bytes == 111);
-
- assert_se(parse_size(" 112 B", 1024, &bytes) == 0);
- assert_se(bytes == 112);
-
- assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0);
- assert_se(bytes == 112);
-
- assert_se(parse_size("3.5 K", 1024, &bytes) == 0);
- assert_se(bytes == 3*1024 + 512);
-
- assert_se(parse_size("3. K", 1024, &bytes) == 0);
- assert_se(bytes == 3*1024);
-
- assert_se(parse_size("3.0 K", 1024, &bytes) == 0);
- assert_se(bytes == 3*1024);
-
- assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0);
- assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512);
-
- assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("3.5G3B", 1024, &bytes) == 0);
- assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3);
-
- assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0);
- assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4);
-
- assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("4T3G3B", 1024, &bytes) == 0);
- assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
-
- assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0);
- assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
-
- assert_se(parse_size("12P", 1024, &bytes) == 0);
- assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
-
- assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("3E 2P", 1024, &bytes) == 0);
- assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
-
- assert_se(parse_size("12X", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL);
-
- assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE);
- assert_se(parse_size("-1", 1024, &bytes) == -ERANGE);
- assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE);
-
- assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE);
-
- assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
-}
-
static void test_parse_cpu_set(void) {
cpu_set_t *c = NULL;
int ncpus;
int cpu;
/* Simple range (from CPUAffinity example) */
- ncpus = parse_cpu_set("1 2", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus >= 1024);
assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
@@ -974,7 +777,7 @@ static void test_parse_cpu_set(void) {
c = mfree(c);
/* A more interesting range */
- ncpus = parse_cpu_set("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus >= 1024);
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
for (cpu = 0; cpu < 4; cpu++)
@@ -984,7 +787,7 @@ static void test_parse_cpu_set(void) {
c = mfree(c);
/* Quoted strings */
- ncpus = parse_cpu_set("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus >= 1024);
assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
for (cpu = 8; cpu < 12; cpu++)
@@ -992,28 +795,85 @@ static void test_parse_cpu_set(void) {
c = mfree(c);
/* Use commas as separators */
- ncpus = parse_cpu_set("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
+ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Commas with spaces (and trailing comma, space) */
+ ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 8; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
/* Ranges */
- ncpus = parse_cpu_set("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Ranges with trailing comma, space */
+ ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Negative range (returns empty cpu_set) */
+ ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
+ c = mfree(c);
+
+ /* Overlapping ranges */
+ ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
+ for (cpu = 0; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Mix ranges and individual CPUs */
+ ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
+ assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 4; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Garbage */
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus < 0);
assert_se(!c);
- /* Garbage */
- ncpus = parse_cpu_set("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
+ /* Range with garbage */
+ ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus < 0);
assert_se(!c);
/* Empty string */
c = NULL;
- ncpus = parse_cpu_set("", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus == 0); /* empty string returns 0 */
assert_se(!c);
/* Runnaway quoted string */
- ncpus = parse_cpu_set("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
assert_se(ncpus < 0);
assert_se(!c);
}
@@ -1551,507 +1411,6 @@ static void test_execute_directory(void) {
(void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
}
-static void test_extract_first_word(void) {
- const char *p, *original;
- char *t;
-
- p = original = "foobar waldo";
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "foobar"));
- free(t);
- assert_se(p == original + 7);
-
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"foobar\" \'waldo\'";
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "\"foobar\""));
- free(t);
- assert_se(p == original + 9);
-
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "\'waldo\'"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"foobar\" \'waldo\'";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
- assert_se(streq(t, "foobar"));
- free(t);
- assert_se(p == original + 9);
-
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word(&p, &t, NULL, 0) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"";
- assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
- assert_se(streq(t, "\""));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\"";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
- assert_se(p == original + 1);
-
- p = original = "\'";
- assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
- assert_se(streq(t, "\'"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\'";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
- assert_se(p == original + 1);
-
- p = original = "\'fooo";
- assert_se(extract_first_word(&p, &t, NULL, 0) == 1);
- assert_se(streq(t, "\'fooo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\'fooo";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\'fooo";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "fooo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "yay\'foo\'bar";
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "yay\'foo\'bar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "yay\'foo\'bar";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
- assert_se(streq(t, "yayfoobar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " foobar ";
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "foobar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " foo\\ba\\x6ar ";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
- assert_se(streq(t, "foo\ba\x6ar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " foo\\ba\\x6ar ";
- assert_se(extract_first_word(&p, &t, NULL, 0) > 0);
- assert_se(streq(t, "foobax6ar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0);
- assert_se(streq(t, "föo"));
- free(t);
- assert_se(p == original + 13);
-
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0);
- assert_se(streq(t, "pi\360\237\222\251le"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
- assert_se(streq(t, "fooo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "fooo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "fooo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "fooo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\"foo\\";
- assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\"foo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "foo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "foo::bar";
- assert_se(extract_first_word(&p, &t, ":", 0) == 1);
- assert_se(streq(t, "foo"));
- free(t);
- assert_se(p == original + 5);
-
- assert_se(extract_first_word(&p, &t, ":", 0) == 1);
- assert_se(streq(t, "bar"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word(&p, &t, ":", 0) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "foo\\:bar::waldo";
- assert_se(extract_first_word(&p, &t, ":", 0) == 1);
- assert_se(streq(t, "foo:bar"));
- free(t);
- assert_se(p == original + 10);
-
- assert_se(extract_first_word(&p, &t, ":", 0) == 1);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word(&p, &t, ":", 0) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"foo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\"foo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "foo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\"foo\\";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "foo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0);
- assert_se(streq(t, "fooo bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "fooo bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0);
- assert_se(streq(t, "fooo bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "fooo\\ bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "\\w+@\\K[\\d.]+";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL);
- assert_se(p == original + 1);
-
- p = original = "\\w+@\\K[\\d.]+";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "\\w+@\\K[\\d.]+"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\\w+\\b";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0);
- assert_se(streq(t, "\\w+\b"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "-N ''";
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
- assert_se(streq(t, "-N"));
- free(t);
- assert_se(p == original + 3);
-
- assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0);
- assert_se(streq(t, ""));
- free(t);
- assert_se(isempty(p));
-
- p = original = ":foo\\:bar::waldo:";
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
- assert_se(t);
- assert_se(streq(t, ""));
- free(t);
- assert_se(p == original + 1);
-
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
- assert_se(streq(t, "foo:bar"));
- free(t);
- assert_se(p == original + 10);
-
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
- assert_se(t);
- assert_se(streq(t, ""));
- free(t);
- assert_se(p == original + 11);
-
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(p == original + 17);
-
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1);
- assert_se(streq(t, ""));
- free(t);
- assert_se(p == NULL);
-
- assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0);
- assert_se(!t);
- assert_se(!p);
-}
-
-static void test_extract_first_word_and_warn(void) {
- const char *p, *original;
- char *t;
-
- p = original = "foobar waldo";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foobar"));
- free(t);
- assert_se(p == original + 7);
-
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"foobar\" \'waldo\'";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foobar"));
- free(t);
- assert_se(p == original + 9);
-
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "waldo"));
- free(t);
- assert_se(isempty(p));
-
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0);
- assert_se(!t);
- assert_se(isempty(p));
-
- p = original = "\"";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
- assert_se(p == original + 1);
-
- p = original = "\'";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
- assert_se(p == original + 1);
-
- p = original = "\'fooo";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\'fooo";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " foo\\ba\\x6ar ";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foo\ba\x6ar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " foo\\ba\\x6ar ";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foobax6ar"));
- free(t);
- assert_se(isempty(p));
-
- p = original = " f\\u00f6o \"pi\\U0001F4A9le\" ";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "föo"));
- free(t);
- assert_se(p == original + 13);
-
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "pi\360\237\222\251le"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo\\"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\"foo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\"foo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\"foo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL);
- assert_se(p == original + 5);
-
- p = original = "\"foo\\";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "foo"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "fooo\\ bar quux";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "fooo\\ bar"));
- free(t);
- assert_se(p == original + 10);
-
- p = original = "\\w+@\\K[\\d.]+";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "\\w+@\\K[\\d.]+"));
- free(t);
- assert_se(isempty(p));
-
- p = original = "\\w+\\b";
- assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0);
- assert_se(streq(t, "\\w+\b"));
- free(t);
- assert_se(isempty(p));
-}
-
-static void test_extract_many_words(void) {
- const char *p, *original;
- char *a, *b, *c;
-
- p = original = "foobar waldi piep";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, "foobar"));
- assert_se(streq_ptr(b, "waldi"));
- assert_se(streq_ptr(c, "piep"));
- free(a);
- free(b);
- free(c);
-
- p = original = "'foobar' wa\"ld\"i ";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, "'foobar'"));
- assert_se(streq_ptr(b, "wa\"ld\"i"));
- assert_se(streq_ptr(c, NULL));
- free(a);
- free(b);
-
- p = original = "'foobar' wa\"ld\"i ";
- assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, "foobar"));
- assert_se(streq_ptr(b, "waldi"));
- assert_se(streq_ptr(c, NULL));
- free(a);
- free(b);
-
- p = original = "";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, NULL));
- assert_se(streq_ptr(b, NULL));
- assert_se(streq_ptr(c, NULL));
-
- p = original = " ";
- assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, NULL));
- assert_se(streq_ptr(b, NULL));
- assert_se(streq_ptr(c, NULL));
-
- p = original = "foobar";
- assert_se(extract_many_words(&p, NULL, 0, NULL) == 0);
- assert_se(p == original);
-
- p = original = "foobar waldi";
- assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
- assert_se(p == original+7);
- assert_se(streq_ptr(a, "foobar"));
- free(a);
-
- p = original = " foobar ";
- assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1);
- assert_se(isempty(p));
- assert_se(streq_ptr(a, "foobar"));
- free(a);
-}
-
static int parse_item(const char *key, const char *value) {
assert_se(key);
@@ -2200,20 +1559,6 @@ static void test_shell_maybe_quote(void) {
test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
}
-static void test_parse_mode(void) {
- mode_t m;
-
- assert_se(parse_mode("-1", &m) < 0);
- assert_se(parse_mode("", &m) < 0);
- assert_se(parse_mode("888", &m) < 0);
- assert_se(parse_mode("77777", &m) < 0);
-
- assert_se(parse_mode("544", &m) >= 0 && m == 0544);
- assert_se(parse_mode("777", &m) >= 0 && m == 0777);
- assert_se(parse_mode("7777", &m) >= 0 && m == 07777);
- assert_se(parse_mode("0", &m) >= 0 && m == 0);
-}
-
static void test_tempfn(void) {
char *ret = NULL, *p;
@@ -2262,6 +1607,44 @@ static void test_strcmp_ptr(void) {
assert_se(strcmp_ptr("", "") == 0);
}
+static void test_fgetxattrat_fake(void) {
+ char t[] = "/var/tmp/xattrtestXXXXXX";
+ _cleanup_close_ int fd = -1;
+ const char *x;
+ char v[3] = {};
+ int r;
+
+ assert_se(mkdtemp(t));
+ x = strjoina(t, "/test");
+ assert_se(touch(x) >= 0);
+
+ r = setxattr(x, "user.foo", "bar", 3, 0);
+ if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */
+ goto cleanup;
+ assert_se(r >= 0);
+
+ fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
+ assert_se(fd >= 0);
+
+ assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0);
+ assert_se(memcmp(v, "bar", 3) == 0);
+
+ safe_close(fd);
+ fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
+ assert_se(fd >= 0);
+ assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA);
+
+cleanup:
+ assert_se(unlink(x) >= 0);
+ assert_se(rmdir(t) >= 0);
+}
+
+static void test_runlevel_to_target(void) {
+ assert_se(streq_ptr(runlevel_to_target(NULL), NULL));
+ assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL));
+ assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET));
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -2274,13 +1657,7 @@ int main(int argc, char *argv[]) {
test_div_round_up();
test_first_word();
test_close_many();
- test_parse_boolean();
- test_parse_pid();
test_parse_uid();
- test_safe_atou16();
- test_safe_atoi16();
- test_safe_atolli();
- test_safe_atod();
test_strappend();
test_strstrip();
test_delete_chars();
@@ -2307,7 +1684,6 @@ int main(int argc, char *argv[]) {
test_memdup_multiply();
test_u64log2();
test_protect_errno();
- test_parse_size();
test_parse_cpu_set();
test_config_parse_iec_uint64();
test_strextend();
@@ -2339,9 +1715,6 @@ int main(int argc, char *argv[]) {
test_search_and_fopen_nulstr();
test_glob_exists();
test_execute_directory();
- test_extract_first_word();
- test_extract_first_word_and_warn();
- test_extract_many_words();
test_parse_proc_cmdline();
test_raw_clone();
test_same_fd();
@@ -2349,9 +1722,10 @@ int main(int argc, char *argv[]) {
test_sparse_write();
test_shell_escape();
test_shell_maybe_quote();
- test_parse_mode();
test_tempfn();
test_strcmp_ptr();
+ test_fgetxattrat_fake();
+ test_runlevel_to_target();
return 0;
}
diff --git a/src/test/test-xml.c b/src/test/test-xml.c
index ea109fbde0..548d75a3c3 100644
--- a/src/test/test-xml.c
+++ b/src/test/test-xml.c
@@ -21,8 +21,10 @@
#include <stdarg.h>
-#include "xml.h"
+#include "alloc-util.h"
+#include "string-util.h"
#include "util.h"
+#include "xml.h"
static void test_one(const char *data, ...) {
void *state = NULL;
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 12a7ed6718..564d72773a 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -20,20 +20,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <getopt.h>
#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "util.h"
+#include "bus-util.h"
+#include "pager.h"
+#include "parse-util.h"
#include "spawn-polkit-agent.h"
-#include "build.h"
#include "strv.h"
-#include "pager.h"
#include "terminal-util.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -374,9 +375,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
@@ -502,7 +501,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
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 6de9e246f6..968ef8a788 100644
--- a/src/timedate/timedated.c
+++ b/src/timedate/timedated.c
@@ -23,21 +23,24 @@
#include <string.h>
#include <unistd.h>
-#include "sd-messages.h"
-#include "sd-event.h"
#include "sd-bus.h"
+#include "sd-event.h"
+#include "sd-messages.h"
-#include "util.h"
-#include "strv.h"
-#include "def.h"
-#include "clock-util.h"
-#include "path-util.h"
-#include "fileio-label.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "clock-util.h"
+#include "def.h"
#include "event-util.h"
+#include "fileio-label.h"
+#include "fs-util.h"
+#include "path-util.h"
#include "selinux-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
#define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
#define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index df4d89a620..001a0f4d41 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -19,14 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
+#include "alloc-util.h"
+#include "def.h"
+#include "extract-word.h"
+#include "string-util.h"
+#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
#include "timesyncd-server.h"
-#include "timesyncd-conf.h"
int manager_parse_server_string(Manager *m, ServerType type, const char *string) {
- const char *word, *state;
- size_t length;
ServerName *first;
int r;
@@ -35,17 +36,20 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers;
- FOREACH_WORD_QUOTED(word, length, string, state) {
- char buffer[length+1];
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
bool found = false;
ServerName *n;
- memcpy(buffer, word, length);
- buffer[length] = 0;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse timesyncd server syntax \"%s\": %m", string);
+ if (r == 0)
+ break;
/* Filter out duplicates */
LIST_FOREACH(names, n, first)
- if (streq_ptr(n->string, buffer)) {
+ if (streq_ptr(n->string, word)) {
found = true;
break;
}
@@ -53,7 +57,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string)
if (found)
continue;
- r = server_name_new(m, NULL, type, buffer);
+ r = server_name_new(m, NULL, type, word);
if (r < 0)
return r;
}
@@ -85,7 +89,7 @@ int config_parse_servers(
else {
r = manager_parse_server_string(m, ltype, rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue);
return 0;
}
}
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
index 40e0fd31fe..8dca538b3b 100644
--- a/src/timesync/timesyncd-manager.c
+++ b/src/timesync/timesyncd-manager.c
@@ -19,31 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
-#include <time.h>
#include <math.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <sys/socket.h>
#include <sys/timerfd.h>
#include <sys/timex.h>
-#include <sys/socket.h>
-#include <resolv.h>
#include <sys/types.h>
+#include <time.h>
-#include "missing.h"
-#include "util.h"
-#include "sparse-endian.h"
-#include "log.h"
-#include "socket-util.h"
+#include "sd-daemon.h"
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "list.h"
+#include "log.h"
+#include "missing.h"
+#include "network-util.h"
#include "ratelimit.h"
+#include "socket-util.h"
+#include "sparse-endian.h"
+#include "string-util.h"
#include "strv.h"
-#include "sd-daemon.h"
-#include "network-util.h"
+#include "time-util.h"
#include "timesyncd-conf.h"
#include "timesyncd-manager.h"
-#include "time-util.h"
+#include "util.h"
#ifndef ADJ_SETOFFSET
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */
@@ -365,7 +370,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) {
r = clock_adjtime(CLOCK_REALTIME, &tmx);
if (r < 0)
- return r;
+ return -errno;
touch("/var/lib/systemd/clock");
@@ -662,7 +667,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->sync = true;
r = manager_adjust_clock(m, offset, leap_sec);
if (r < 0)
- log_error_errno(errno, "Failed to call clock_adjtime(): %m");
+ log_error_errno(r, "Failed to call clock_adjtime(): %m");
}
log_debug("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s",
diff --git a/src/timesync/timesyncd-server.c b/src/timesync/timesyncd-server.c
index ec3fe1fc4e..f98e6b4cf0 100644
--- a/src/timesync/timesyncd-server.c
+++ b/src/timesync/timesyncd-server.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "timesyncd-server.h"
int server_address_new(
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 3cb7d435cd..7f70eaaea0 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -19,15 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "sd-event.h"
#include "sd-daemon.h"
-#include "capability.h"
+#include "sd-event.h"
+
+#include "capability-util.h"
#include "clock-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "network-util.h"
#include "signal-util.h"
-
-#include "timesyncd-manager.h"
#include "timesyncd-conf.h"
+#include "timesyncd-manager.h"
+#include "user-util.h"
static int load_clock_timestamp(uid_t uid, gid_t gid) {
_cleanup_close_ int fd = -1;
@@ -57,12 +60,12 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) {
/* Try to fix the access mode, so that we can still
touch the file after dropping priviliges */
- fchmod(fd, 0644);
- fchown(fd, uid, gid);
+ (void) fchmod(fd, 0644);
+ (void) fchown(fd, uid, gid);
} else
/* create stamp file with the compiled-in date */
- touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
+ (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644);
ct = now(CLOCK_REALTIME);
if (ct < min) {
@@ -150,7 +153,7 @@ int main(int argc, char *argv[]) {
/* if we got an authoritative time, store it in the file system */
if (m->sync)
- touch("/var/lib/systemd/clock");
+ (void) touch("/var/lib/systemd/clock");
sd_event_get_exit_code(m->event, &r);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 8f29256c6d..ffae91a3ca 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -20,43 +20,59 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <fcntl.h>
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <getopt.h>
+#include <glob.h>
#include <limits.h>
-#include <dirent.h>
+#include <linux/fs.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <time.h>
-#include <glob.h>
-#include <fnmatch.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/xattr.h>
-#include <linux/fs.h>
+#include <time.h>
+#include <unistd.h>
+#include "acl-util.h"
+#include "alloc-util.h"
+#include "btrfs-util.h"
+#include "capability-util.h"
+#include "chattr-util.h"
+#include "conf-files.h"
+#include "copy.h"
+#include "def.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
+#include "label.h"
#include "log.h"
-#include "util.h"
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
+#include "mount-util.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "strv.h"
-#include "label.h"
-#include "set.h"
-#include "conf-files.h"
-#include "capability.h"
-#include "specifier.h"
-#include "build.h"
-#include "copy.h"
#include "rm-rf.h"
#include "selinux-util.h"
-#include "btrfs-util.h"
-#include "acl-util.h"
-#include "formats-util.h"
+#include "set.h"
+#include "specifier.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "user-util.h"
+#include "util.h"
/* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
* them in the file system. This is intended to be used to create
@@ -70,6 +86,8 @@ typedef enum ItemType {
CREATE_DIRECTORY = 'd',
TRUNCATE_DIRECTORY = 'D',
CREATE_SUBVOLUME = 'v',
+ CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
+ CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
CREATE_FIFO = 'p',
CREATE_SYMLINK = 'L',
CREATE_CHAR_DEVICE = 'c',
@@ -181,6 +199,8 @@ static bool takes_ownership(ItemType t) {
CREATE_DIRECTORY,
TRUNCATE_DIRECTORY,
CREATE_SUBVOLUME,
+ CREATE_SUBVOLUME_INHERIT_QUOTA,
+ CREATE_SUBVOLUME_NEW_QUOTA,
CREATE_FIFO,
CREATE_SYMLINK,
CREATE_CHAR_DEVICE,
@@ -1199,16 +1219,16 @@ static int create_item(Item *i) {
case CREATE_DIRECTORY:
case TRUNCATE_DIRECTORY:
case CREATE_SUBVOLUME:
+ case CREATE_SUBVOLUME_INHERIT_QUOTA:
+ case CREATE_SUBVOLUME_NEW_QUOTA:
RUN_WITH_UMASK(0000)
mkdir_parents_label(i->path, 0755);
- if (i->type == CREATE_SUBVOLUME)
- RUN_WITH_UMASK((~i->mode) & 0777) {
+ if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
+ RUN_WITH_UMASK((~i->mode) & 0777)
r = btrfs_subvol_make(i->path);
- log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
- }
- else
+ } else
r = 0;
if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
@@ -1237,6 +1257,24 @@ static int create_item(Item *i) {
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
+ if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
+ r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
+ if (r == -ENOTTY) {
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
+ return 0;
+ }
+ if (r == -EROFS) {
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
+ if (r > 0)
+ log_debug("Adjusted quota for subvolume \"%s\".", i->path);
+ if (r == 0)
+ log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
+ }
+
r = path_set_perms(i, i->path);
if (r < 0)
return r;
@@ -1493,6 +1531,8 @@ static int remove_item(Item *i) {
case TRUNCATE_FILE:
case CREATE_DIRECTORY:
case CREATE_SUBVOLUME:
+ case CREATE_SUBVOLUME_INHERIT_QUOTA:
+ case CREATE_SUBVOLUME_NEW_QUOTA:
case CREATE_FIFO:
case CREATE_SYMLINK:
case CREATE_CHAR_DEVICE:
@@ -1562,8 +1602,7 @@ static int clean_item_instance(Item *i, const char* instance) {
if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0)
return log_error_errno(errno, "stat(%s/..) failed: %m", i->path);
- mountpoint = s.st_dev != ps.st_dev ||
- (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino);
+ mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino;
log_debug("Cleanup threshold for %s \"%s\" is %s",
mountpoint ? "mount point" : "directory",
@@ -1584,6 +1623,8 @@ static int clean_item(Item *i) {
switch (i->type) {
case CREATE_DIRECTORY:
case CREATE_SUBVOLUME:
+ case CREATE_SUBVOLUME_INHERIT_QUOTA:
+ case CREATE_SUBVOLUME_NEW_QUOTA:
case TRUNCATE_DIRECTORY:
case IGNORE_PATH:
case COPY_FILES:
@@ -1820,6 +1861,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
case CREATE_DIRECTORY:
case CREATE_SUBVOLUME:
+ case CREATE_SUBVOLUME_INHERIT_QUOTA:
+ case CREATE_SUBVOLUME_NEW_QUOTA:
case TRUNCATE_DIRECTORY:
case CREATE_FIFO:
case IGNORE_PATH:
@@ -1984,8 +2027,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
i.mode = m;
i.mode_set = true;
} else
- i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
- ? 0755 : 0644;
+ i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
if (!isempty(age) && !streq(age, "-")) {
const char *a = age;
@@ -2076,7 +2118,7 @@ static int parse_argv(int argc, char *argv[]) {
{}
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -2090,9 +2132,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_CREATE:
arg_create = true;
@@ -2121,12 +2161,9 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- free(arg_root);
- arg_root = path_make_absolute_cwd(optarg);
- if (!arg_root)
- return log_oom();
-
- path_kill_slashes(arg_root);
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case '?':
@@ -2189,7 +2226,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
continue;
ORDERED_HASHMAP_FOREACH(j, items, iter) {
- if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
+ if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
continue;
if (path_equal(j->path, i->path)) {
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 82cbf95f1e..8cfe10330d 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -19,32 +19,36 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <string.h>
+#include <sys/inotify.h>
+#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <stddef.h>
-#include <poll.h>
-#include <sys/inotify.h>
#include <unistd.h>
-#include <getopt.h>
-#include <sys/signalfd.h>
-#include <fcntl.h>
-#include "util.h"
+#include "alloc-util.h"
+#include "ask-password-api.h"
+#include "conf-parser.h"
+#include "def.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "mkdir.h"
#include "path-util.h"
-#include "conf-parser.h"
-#include "utmp-wtmp.h"
+#include "process-util.h"
+#include "signal-util.h"
#include "socket-util.h"
-#include "ask-password-api.h"
+#include "string-util.h"
#include "strv.h"
-#include "build.h"
-#include "def.h"
-#include "process-util.h"
#include "terminal-util.h"
-#include "signal-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
static enum {
ACTION_LIST,
@@ -59,9 +63,9 @@ static bool arg_console = false;
static int ask_password_plymouth(
const char *message,
usec_t until,
+ AskPasswordFlags flags,
const char *flag_file,
- bool accept_cached,
- char ***_passphrases) {
+ char ***ret) {
_cleanup_close_ int fd = -1, notify = -1;
union sockaddr_union sa = PLYMOUTH_SOCKET;
@@ -76,7 +80,7 @@ static int ask_password_plymouth(
POLL_INOTIFY
};
- assert(_passphrases);
+ assert(ret);
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -94,17 +98,15 @@ static int ask_password_plymouth(
r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
if (r < 0)
- return log_error_errno(errno, "Failed to connect to Plymouth: %m");
+ return -errno;
- if (accept_cached) {
+ if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
packet = strdup("c");
n = 1;
- } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1),
- message, &n) < 0)
+ } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
packet = NULL;
-
if (!packet)
- return log_oom();
+ return -ENOMEM;
r = loop_write(fd, packet, n + 1, true);
if (r < 0)
@@ -123,33 +125,48 @@ static int ask_password_plymouth(
y = now(CLOCK_MONOTONIC);
- if (y > until)
- return -ETIME;
+ if (y > until) {
+ r = -ETIME;
+ goto finish;
+ }
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
}
- if (flag_file && access(flag_file, F_OK) < 0)
- return -errno;
+ if (flag_file && access(flag_file, F_OK) < 0) {
+ r = -errno;
+ goto finish;
+ }
- j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+ j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (j < 0) {
if (errno == EINTR)
continue;
- return -errno;
- } else if (j == 0)
- return -ETIME;
+ r = -errno;
+ goto finish;
+ } else if (j == 0) {
+ r = -ETIME;
+ goto finish;
+ }
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+ if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
if (pollfd[POLL_SOCKET].revents == 0)
continue;
k = read(fd, buffer + p, sizeof(buffer) - p);
- if (k <= 0)
- return r = k < 0 ? -errno : -EIO;
+ if (k < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ r = -errno;
+ goto finish;
+ } else if (k == 0) {
+ r = -EIO;
+ goto finish;
+ }
p += k;
@@ -158,26 +175,29 @@ static int ask_password_plymouth(
if (buffer[0] == 5) {
- if (accept_cached) {
+ if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
/* Hmm, first try with cached
* passwords failed, so let's retry
* with a normal password request */
packet = mfree(packet);
- if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
- return -ENOMEM;
+ if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
r = loop_write(fd, packet, n+1, true);
if (r < 0)
- return r;
+ goto finish;
- accept_cached = false;
+ flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
p = 0;
continue;
}
/* No password, because UI not shown */
- return -ENOENT;
+ r = -ENOENT;
+ goto finish;
} else if (buffer[0] == 2 || buffer[0] == 9) {
uint32_t size;
@@ -189,32 +209,43 @@ static int ask_password_plymouth(
memcpy(&size, buffer+1, sizeof(size));
size = le32toh(size);
- if (size + 5 > sizeof(buffer))
- return -EIO;
+ if (size + 5 > sizeof(buffer)) {
+ r = -EIO;
+ goto finish;
+ }
if (p-5 < size)
continue;
l = strv_parse_nulstr(buffer + 5, size);
- if (!l)
- return -ENOMEM;
+ if (!l) {
+ r = -ENOMEM;
+ goto finish;
+ }
- *_passphrases = l;
+ *ret = l;
break;
- } else
+ } else {
/* Unknown packet */
- return -EIO;
+ r = -EIO;
+ goto finish;
+ }
}
- return 0;
+ r = 0;
+
+finish:
+ memory_erase(buffer, sizeof(buffer));
+ return r;
}
static int parse_password(const char *filename, char **wall) {
_cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL;
+ bool accept_cached = false, echo = false;
+ size_t packet_length = 0;
uint64_t not_after = 0;
unsigned pid = 0;
- bool accept_cached = false, echo = false;
const ConfigTableItem items[] = {
{ "Ask", "Socket", config_parse_string, 0, &socket_name },
@@ -257,7 +288,7 @@ static int parse_password(const char *filename, char **wall) {
if (asprintf(&_wall,
"%s%sPassword entry required for \'%s\' (PID %u).\r\n"
"Please enter password with the systemd-tty-ask-password-agent tool!",
- *wall ? *wall : "",
+ strempty(*wall),
*wall ? "\r\n\r\n" : "",
message,
pid) < 0)
@@ -268,7 +299,6 @@ static int parse_password(const char *filename, char **wall) {
} else {
union sockaddr_union sa = {};
- size_t packet_length = 0;
_cleanup_close_ int socket_fd = -1;
assert(arg_action == ACTION_QUERY ||
@@ -282,9 +312,9 @@ static int parse_password(const char *filename, char **wall) {
}
if (arg_plymouth) {
- _cleanup_strv_free_ char **passwords = NULL;
+ _cleanup_strv_free_erase_ char **passwords = NULL;
- r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords);
+ r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords);
if (r >= 0) {
char **p;
@@ -306,19 +336,23 @@ static int parse_password(const char *filename, char **wall) {
}
} else {
+ _cleanup_string_free_erase_ char *password = NULL;
int tty_fd = -1;
- _cleanup_free_ char *password = NULL;
if (arg_console) {
tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
if (tty_fd < 0)
- return tty_fd;
+ return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
+
+ r = reset_terminal_fd(tty_fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
- r = ask_password_tty(message, not_after, echo, filename, &password);
+ r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);
if (arg_console) {
- safe_close(tty_fd);
+ tty_fd = safe_close(tty_fd);
release_terminal();
}
@@ -334,67 +368,79 @@ static int parse_password(const char *filename, char **wall) {
}
}
- if (IN_SET(r, -ETIME, -ENOENT))
+ if (IN_SET(r, -ETIME, -ENOENT)) {
/* If the query went away, that's OK */
- return 0;
-
- if (r < 0)
- return log_error_errno(r, "Failed to query password: %m");
+ r = 0;
+ goto finish;
+ }
+ if (r < 0) {
+ log_error_errno(r, "Failed to query password: %m");
+ goto finish;
+ }
socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
- if (socket_fd < 0)
- return log_error_errno(errno, "socket(): %m");
+ if (socket_fd < 0) {
+ r = log_error_errno(errno, "socket(): %m");
+ goto finish;
+ }
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa,
- offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
- if (r < 0) {
- log_error_errno(errno, "Failed to send: %m");
- return r;
- }
+ r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+ memory_erase(packet, packet_length);
+ if (r < 0)
+ return log_error_errno(errno, "Failed to send: %m");
}
return 0;
+
+finish:
+ memory_erase(packet, packet_length);
+ return r;
}
static int wall_tty_block(void) {
_cleanup_free_ char *p = NULL;
- int fd, r;
dev_t devnr;
+ int fd, r;
r = get_ctty_devnr(0, &devnr);
+ if (r == -ENXIO) /* We have no controlling tty */
+ return -ENOTTY;
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get controlling TTY: %m");
if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
- return -ENOMEM;
+ return log_oom();
mkdir_parents_label(p, 0700);
mkfifo(p, 0600);
fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
- return -errno;
+ return log_debug_errno(errno, "Failed to open %s: %m", p);
return fd;
}
static bool wall_tty_match(const char *path, void *userdata) {
- int fd, r;
- struct stat st;
_cleanup_free_ char *p = NULL;
+ _cleanup_close_ int fd = -1;
+ struct stat st;
if (!path_is_absolute(path))
path = strjoina("/dev/", path);
- r = lstat(path, &st);
- if (r < 0)
+ if (lstat(path, &st) < 0) {
+ log_debug_errno(errno, "Failed to stat %s: %m", path);
return true;
+ }
- if (!S_ISCHR(st.st_mode))
+ if (!S_ISCHR(st.st_mode)) {
+ log_debug("%s is not a character device.", path);
return true;
+ }
/* We use named pipes to ensure that wall messages suggesting
* password entry are not printed over password prompts
@@ -404,16 +450,19 @@ static bool wall_tty_match(const char *path, void *userdata) {
* advantage that the block will automatically go away if the
* process dies. */
- if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
+ if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) {
+ log_oom();
return true;
+ }
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0)
- return true;
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed top open the wall pipe: %m");
+ return 1;
+ }
/* What, we managed to open the pipe? Then this tty is filtered. */
- safe_close(fd);
- return false;
+ return 0;
}
static int show_passwords(void) {
@@ -426,11 +475,10 @@ static int show_passwords(void) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "opendir(/run/systemd/ask-password): %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m");
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) {
_cleanup_free_ char *p = NULL, *wall = NULL;
int q;
@@ -455,7 +503,7 @@ static int show_passwords(void) {
r = q;
if (wall)
- utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
+ (void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
}
return r;
@@ -475,14 +523,14 @@ static int watch_passwords(void) {
tty_block_fd = wall_tty_block();
- mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_p_label("/run/systemd/ask-password", 0755);
notify = inotify_init1(IN_CLOEXEC);
if (notify < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to allocate directory watch: %m");
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
@@ -490,7 +538,7 @@ static int watch_passwords(void) {
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to allocate signal file descriptor: %m");
pollfd[FD_INOTIFY].fd = notify;
pollfd[FD_INOTIFY].events = POLLIN;
@@ -510,7 +558,7 @@ static int watch_passwords(void) {
}
if (pollfd[FD_INOTIFY].revents != 0)
- flush_fd(notify);
+ (void) flush_fd(notify);
if (pollfd[FD_SIGNAL].revents != 0)
break;
@@ -571,9 +619,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_LIST:
arg_action = ACTION_LIST;
@@ -628,8 +674,8 @@ int main(int argc, char *argv[]) {
goto finish;
if (arg_console) {
- setsid();
- release_terminal();
+ (void) setsid();
+ (void) release_terminal();
}
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
@@ -637,9 +683,6 @@ int main(int argc, char *argv[]) {
else
r = show_passwords();
- if (r < 0)
- log_error_errno(r, "Error: %m");
-
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/udev/.gitignore b/src/udev/.gitignore
index ba112ce218..f5d8be3dc1 100644
--- a/src/udev/.gitignore
+++ b/src/udev/.gitignore
@@ -1,5 +1,4 @@
/udev.pc
/keyboard-keys-from-name.gperf
/keyboard-keys-from-name.h
-/keyboard-keys-to-name.h
/keyboard-keys-list.txt
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index 1d1798dd10..1e414664ce 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -19,28 +19,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <ctype.h>
-#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <linux/bsg.h>
+#include <linux/hdreg.h>
#include <scsi/scsi.h>
-#include <scsi/sg.h>
#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <linux/hdreg.h>
-#include <linux/bsg.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "libudev.h"
+
+#include "fd-util.h"
#include "libudev-private.h"
-#include "udev-util.h"
#include "log.h"
+#include "udev-util.h"
#define COMMAND_TIMEOUT_MSEC (30 * 1000)
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
index 001bae7a24..72f284f710 100644
--- a/src/udev/cdrom_id/cdrom_id.c
+++ b/src/udev/cdrom_id/cdrom_id.c
@@ -17,24 +17,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <limits.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
-#include <time.h>
+#include <limits.h>
+#include <linux/cdrom.h>
#include <scsi/sg.h>
-#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <linux/cdrom.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
#include "libudev.h"
+
#include "libudev-private.h"
#include "random-util.h"
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
index b3a1f0bca1..b6c95cd452 100644
--- a/src/udev/collect/collect.c
+++ b/src/udev/collect/collect.c
@@ -19,13 +19,15 @@
*
*/
-#include <stdio.h>
-#include <stddef.h>
#include <errno.h>
#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include "alloc-util.h"
#include "libudev-private.h"
#include "macro.h"
+#include "string-util.h"
#define BUFSIZE 16
#define UDEV_ALARM_TIMEOUT 180
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
index a4b05d1bec..0647008d90 100644
--- a/src/udev/net/ethtool-util.c
+++ b/src/udev/net/ethtool-util.c
@@ -19,17 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/ioctl.h>
#include <net/if.h>
+#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
+#include "conf-parser.h"
#include "ethtool-util.h"
-
+#include "log.h"
+#include "string-table.h"
#include "strxcpyx.h"
#include "util.h"
-#include "log.h"
-#include "conf-parser.h"
static const char* const duplex_table[_DUP_MAX] = {
[DUP_FULL] = "full",
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 63e54db56e..776674e994 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -22,22 +22,28 @@
#include <netinet/ether.h>
#include <linux/netdevice.h>
+#include "sd-netlink.h"
-#include "missing.h"
-#include "link-config.h"
+#include "alloc-util.h"
+#include "conf-files.h"
+#include "conf-parser.h"
#include "ethtool-util.h"
-
+#include "fd-util.h"
#include "libudev-private.h"
-#include "sd-netlink.h"
-#include "util.h"
+#include "link-config.h"
#include "log.h"
-#include "strv.h"
-#include "path-util.h"
-#include "conf-parser.h"
-#include "conf-files.h"
+#include "missing.h"
#include "netlink-util.h"
#include "network-internal.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "proc-cmdline.h"
#include "random-util.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
struct link_config_ctx {
LIST_HEAD(link_config, links);
@@ -460,6 +466,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
mac = &generated_mac;
}
break;
+ case MACPOLICY_NONE:
default:
mac = config->mac;
}
@@ -492,7 +499,8 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret
static const char* const mac_policy_table[_MACPOLICY_MAX] = {
[MACPOLICY_PERSISTENT] = "persistent",
- [MACPOLICY_RANDOM] = "random"
+ [MACPOLICY_RANDOM] = "random",
+ [MACPOLICY_NONE] = "none"
};
DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 9875057e84..4fcbee8b92 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -21,10 +21,11 @@
#pragma once
-#include "ethtool-util.h"
+#include "libudev.h"
+
#include "condition.h"
+#include "ethtool-util.h"
#include "list.h"
-#include "libudev.h"
typedef struct link_config_ctx link_config_ctx;
typedef struct link_config link_config;
@@ -32,6 +33,7 @@ typedef struct link_config link_config;
typedef enum MACPolicy {
MACPOLICY_PERSISTENT,
MACPOLICY_RANDOM,
+ MACPOLICY_NONE,
_MACPOLICY_MAX,
_MACPOLICY_INVALID = -1
} MACPolicy;
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
index adb91869df..4655691642 100644
--- a/src/udev/scsi_id/scsi_id.c
+++ b/src/udev/scsi_id/scsi_id.c
@@ -16,22 +16,25 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <getopt.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "libudev.h"
+
+#include "fd-util.h"
#include "libudev-private.h"
#include "scsi_id.h"
+#include "string-util.h"
#include "udev-util.h"
static const struct option options[] = {
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
index de3b4f7581..c7ef783684 100644
--- a/src/udev/scsi_id/scsi_serial.c
+++ b/src/udev/scsi_id/scsi_serial.c
@@ -17,27 +17,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <time.h>
#include <inttypes.h>
+#include <linux/bsg.h>
+#include <linux/types.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
-#include <linux/types.h>
-#include <linux/bsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
#include "libudev.h"
+
#include "libudev-private.h"
+#include "random-util.h"
#include "scsi.h"
#include "scsi_id.h"
-#include "random-util.h"
+#include "string-util.h"
/*
* A priority based list of id, naa, and binary/ascii for the identifier
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index b8066ea6e9..d0e47ec6d8 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -18,18 +18,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <blkid/blkid.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/stat.h>
-#include <blkid/blkid.h>
#include "sd-id128.h"
-#include "gpt.h"
+
+#include "alloc-util.h"
#include "efivars.h"
+#include "fd-util.h"
+#include "gpt.h"
+#include "string-util.h"
#include "udev.h"
static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) {
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index 3352821567..cfaa463804 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -17,15 +17,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <sys/ioctl.h>
#ifdef HAVE_LINUX_BTRFS_H
#include <linux/btrfs.h>
#endif
+#include "fd-util.h"
#include "missing.h"
+#include "string-util.h"
#include "udev.h"
static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) {
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 72109d93d2..f4a065a97d 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -17,16 +17,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
#include <fnmatch.h>
#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
-#include "udev.h"
#include "sd-hwdb.h"
+#include "alloc-util.h"
#include "hwdb-util.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
static sd_hwdb *hwdb;
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index e3fa4bc162..fddafbd4dc 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -21,15 +21,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <errno.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
#include <string.h>
-#include <errno.h>
+#include <unistd.h>
#include <linux/limits.h>
#include <linux/input.h>
+#include "fd-util.h"
+#include "string-util.h"
#include "udev.h"
#include "util.h"
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index d63a8e2760..aa10beafb0 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -18,11 +18,15 @@
***/
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <linux/input.h>
+#include "fd-util.h"
+#include "parse-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
#include "udev.h"
static const struct key *keyboard_lookup_key(const char *str, unsigned len);
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index 81e78a8aa3..9665f678fd 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -18,12 +18,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
#include <errno.h>
#include <libkmod.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "string-util.h"
#include "udev.h"
static struct kmod_ctx *ctx = NULL;
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 589f1f7822..bf5c9c6b77 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -27,7 +27,7 @@
* http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
*
* Two character prefixes based on the type of interface:
- * en -- ethernet
+ * en -- Ethernet
* sl -- serial line IP (slip)
* wl -- wlan
* ww -- wwan
@@ -53,17 +53,17 @@
* exported.
* The usual USB configuration == 1 and interface == 0 values are suppressed.
*
- * PCI ethernet card with firmware index "1":
+ * PCI Ethernet card with firmware index "1":
* ID_NET_NAME_ONBOARD=eno1
* ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
*
- * PCI ethernet card in hotplug slot with firmware index number:
+ * PCI Ethernet card in hotplug slot with firmware index number:
* /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
* ID_NET_NAME_MAC=enx000000000466
* ID_NET_NAME_PATH=enp5s0
* ID_NET_NAME_SLOT=ens1
*
- * PCI ethernet multi-function card with 2 ports:
+ * PCI Ethernet multi-function card with 2 ports:
* /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
* ID_NET_NAME_MAC=enx78e7d1ea46da
* ID_NET_NAME_PATH=enp2s0f0
@@ -87,19 +87,21 @@
* ID_NET_NAME_PATH=enp0s29u1u2
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
#include <errno.h>
+#include <fcntl.h>
#include <net/if.h>
#include <net/if_arp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <linux/pci_regs.h>
-#include "udev.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "string-util.h"
+#include "udev.h"
enum netname_type{
NET_UNDEF,
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index d4589470fb..f72894b5c5 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "link-config.h"
-#include "udev.h"
#include "log.h"
+#include "udev.h"
static link_config_ctx *ctx = NULL;
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index 01e2c659ae..1e190140b2 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -19,17 +19,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "string-util.h"
#include "udev.h"
_printf_(2,3)
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 7bf4e7f24d..bbda9de08c 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -22,7 +22,9 @@
#include <stdlib.h>
#include <errno.h>
-#include "systemd/sd-login.h"
+#include "sd-login.h"
+
+#include "login-util.h"
#include "logind-acl.h"
#include "udev.h"
#include "util.h"
@@ -56,7 +58,7 @@ static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool
r = devnode_acl(path, true, false, 0, true, uid);
if (r < 0) {
- log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path);
+ log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path);
goto finish;
}
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index d309dc31cb..587649eff0 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -20,15 +20,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
+#include <unistd.h>
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "string-util.h"
#include "udev.h"
static void set_usb_iftype(char *to, int if_class_num, size_t len) {
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 4f625251d6..e6b36f124f 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -17,10 +17,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <getopt.h>
#include <stdio.h>
#include <string.h>
-#include <getopt.h>
+#include "string-util.h"
#include "udev.h"
static bool initialized;
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 56277f551f..1e05be51a5 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -18,8 +18,10 @@
#include <sys/socket.h>
#include <sys/un.h>
-#include "socket-util.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "socket-util.h"
#include "udev.h"
/* wire protocol magic must match */
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index 1e34cbc2f5..5d6542d3ad 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -15,26 +15,29 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
#include <ctype.h>
-#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
#include <net/if.h>
-#include <sys/prctl.h>
#include <poll.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/epoll.h>
-#include <sys/wait.h>
+#include <sys/prctl.h>
#include <sys/signalfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
-#include "netlink-util.h"
+#include "alloc-util.h"
#include "event-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "netlink-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "string-util.h"
#include "udev.h"
typedef struct Spawn {
@@ -438,9 +441,7 @@ static int spawn_exec(struct udev_event *event,
execve(argv[0], argv, envp);
/* exec failed */
- log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
-
- return -errno;
+ return log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
}
static void spawn_read(struct udev_event *event,
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
index e730fb45f1..c2edf2c5cd 100644
--- a/src/udev/udev-node.c
+++ b/src/udev/udev-node.c
@@ -15,20 +15,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
-#include "udev.h"
-#include "smack-util.h"
-#include "selinux-util.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "selinux-util.h"
+#include "smack-util.h"
+#include "string-util.h"
+#include "udev.h"
static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
struct stat stats;
@@ -261,8 +263,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply,
mode |= S_IFCHR;
if (lstat(devnode, &stats) != 0) {
- err = -errno;
- log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
+ err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
goto out;
}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 98c33171d4..c06ace09cf 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -15,27 +15,34 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stddef.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <fnmatch.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <time.h>
+#include <unistd.h>
-#include "udev.h"
-#include "path-util.h"
+#include "alloc-util.h"
#include "conf-files.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "glob-util.h"
+#include "path-util.h"
+#include "stat-util.h"
#include "strbuf.h"
+#include "string-util.h"
#include "strv.h"
-#include "util.h"
#include "sysctl-util.h"
+#include "udev.h"
+#include "user-util.h"
+#include "util.h"
#define PREALLOC_TOKEN 2048
@@ -51,7 +58,8 @@ static const char* const rules_dirs[] = {
"/etc/udev/rules.d",
"/run/udev/rules.d",
UDEVLIBEXECDIR "/rules.d",
- NULL};
+ NULL
+};
struct udev_rules {
struct udev *udev;
@@ -1937,7 +1945,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
break;
}
}
- if (!match && (cur->key.op != OP_NOMATCH))
+ if ((!match && (cur->key.op != OP_NOMATCH)) ||
+ (match && (cur->key.op == OP_NOMATCH)))
goto nomatch;
break;
}
@@ -2514,7 +2523,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
r = sysctl_write(filename, value);
if (r < 0)
- log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r));
+ log_error_errno(r, "error writing SYSCTL{%s}='%s': %m", filename, value);
break;
}
case TK_A_RUN_BUILTIN:
diff --git a/src/udev/udev.h b/src/udev/udev.h
index d17fc8c1ea..1f9c8120c0 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -18,16 +18,17 @@
#pragma once
-#include <sys/types.h>
#include <sys/param.h>
+#include <sys/types.h>
-#include "macro.h"
-#include "sd-netlink.h"
#include "libudev.h"
-#include "libudev-private.h"
-#include "util.h"
+#include "sd-netlink.h"
+
#include "label.h"
+#include "libudev-private.h"
+#include "macro.h"
#include "strv.h"
+#include "util.h"
struct udev_event {
struct udev *udev;
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
index 00609e31b5..031a099d77 100644
--- a/src/udev/udevadm-hwdb.c
+++ b/src/udev/udevadm-hwdb.c
@@ -17,18 +17,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <ctype.h>
#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "util.h"
-#include "strbuf.h"
+#include "alloc-util.h"
#include "conf-files.h"
-
-#include "udev.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "hwdb-internal.h"
#include "hwdb-util.h"
+#include "strbuf.h"
+#include "string-util.h"
+#include "udev.h"
+#include "util.h"
/*
* Generic udev properties, key/value database based on modalias strings.
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index b3d5565c48..7182668f23 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -15,19 +15,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
#include <ctype.h>
-#include <unistd.h>
#include <dirent.h>
#include <errno.h>
-#include <getopt.h>
#include <fcntl.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
-#include "udev.h"
+#include "fd-util.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
#include "udevadm-util.h"
static bool skip_attribute(const char *name) {
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index 5e93955186..30aa53feb2 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -25,9 +25,10 @@
#include <sys/time.h>
#include <sys/epoll.h>
-#include "udev.h"
-#include "udev-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "udev-util.h"
+#include "udev.h"
static bool udev_exit;
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
index 79f45610db..c25071b0fe 100644
--- a/src/udev/udevadm-settle.c
+++ b/src/udev/udevadm-settle.c
@@ -26,6 +26,7 @@
#include <getopt.h>
#include <poll.h>
+#include "parse-util.h"
#include "udev.h"
#include "util.h"
@@ -65,10 +66,9 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
r = safe_atou(optarg, &timeout);
if (r < 0) {
- fprintf(stderr, "Invalid timeout value '%s': %s\n",
- optarg, strerror(-r));
- exit(EXIT_FAILURE);
- };
+ log_error_errno(r, "Invalid timeout value '%s': %m", optarg);
+ return EXIT_FAILURE;
+ }
break;
}
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 35a7349439..0b180d03eb 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -15,12 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdio.h>
#include <errno.h>
#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "string-util.h"
#include "udev.h"
static void help(struct udev *udev) {
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index d04e618d0d..ff427cf292 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -16,17 +16,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
#include <errno.h>
-#include <signal.h>
#include <getopt.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/signalfd.h>
+#include <unistd.h>
-#include "udev.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
static void help(void) {
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
index 7af9665f8a..9d52345d92 100644
--- a/src/udev/udevadm-trigger.c
+++ b/src/udev/udevadm-trigger.c
@@ -15,16 +15,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
#include <stddef.h>
-#include <string.h>
#include <stdio.h>
+#include <string.h>
#include <unistd.h>
-#include <getopt.h>
-#include <errno.h>
-#include <fcntl.h>
-#include "udev.h"
+#include "string-util.h"
#include "udev-util.h"
+#include "udev.h"
#include "udevadm-util.h"
#include "util.h"
diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c
index 3f0e45e26c..3539c1d6ab 100644
--- a/src/udev/udevadm-util.c
+++ b/src/udev/udevadm-util.c
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "string-util.h"
#include "udevadm-util.h"
struct udev_device *find_device(struct udev *udev,
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index b86d8921f3..60f122ebda 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -16,12 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdio.h>
-#include <stddef.h>
#include <errno.h>
#include <getopt.h>
+#include <stddef.h>
+#include <stdio.h>
#include "selinux-util.h"
+#include "string-util.h"
#include "udev.h"
static int adm_version(struct udev *udev, int argc, char *argv[]) {
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 20497ae8be..5364b92a57 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -18,44 +18,54 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stddef.h>
-#include <signal.h>
-#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <string.h>
-#include <fcntl.h>
-#include <getopt.h>
+#include <sys/epoll.h>
#include <sys/file.h>
-#include <sys/time.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
#include <sys/prctl.h>
-#include <sys/socket.h>
#include <sys/signalfd.h>
-#include <sys/epoll.h>
-#include <sys/mount.h>
-#include <sys/wait.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include "sd-daemon.h"
#include "sd-event.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "event-util.h"
-#include "netlink-util.h"
+#include "alloc-util.h"
#include "cgroup-util.h"
-#include "process-util.h"
+#include "cpu-set-util.h"
#include "dev-setup.h"
+#include "event-util.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "selinux-util.h"
-#include "udev.h"
-#include "udev-util.h"
#include "formats-util.h"
+#include "fs-util.h"
#include "hashmap.h"
+#include "io-util.h"
+#include "netlink-util.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
+#include "process-util.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "udev-util.h"
+#include "udev.h"
+#include "user-util.h"
static bool arg_debug = false;
static int arg_daemonize = false;
@@ -1548,7 +1558,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
r = sd_event_default(&manager->event);
if (r < 0)
- return log_error_errno(errno, "could not allocate event loop: %m");
+ return log_error_errno(r, "could not allocate event loop: %m");
r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
if (r < 0)
diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
index 5c57db44c1..607d78a019 100644
--- a/src/udev/v4l_id/v4l_id.c
+++ b/src/udev/v4l_id/v4l_id.c
@@ -26,6 +26,7 @@
#include <sys/ioctl.h>
#include <linux/videodev2.h>
+#include "fd-util.h"
#include "util.h"
int main(int argc, char *argv[]) {
diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c
index 01bbde8455..4c44d50613 100644
--- a/src/update-done/update-done.c
+++ b/src/update-done/update-done.c
@@ -19,8 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
+#include "fd-util.h"
+#include "io-util.h"
#include "selinux-util.h"
+#include "util.h"
#define MESSAGE \
"This file was created by systemd-update-done. Its only \n" \
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index b2998dce43..d50063cbcd 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -29,15 +29,16 @@
#include "sd-bus.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "formats-util.h"
#include "log.h"
#include "macro.h"
-#include "util.h"
#include "special.h"
-#include "utmp-wtmp.h"
-#include "bus-util.h"
-#include "bus-error.h"
#include "unit-name.h"
-#include "formats-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
typedef struct Context {
sd_bus *bus;
@@ -62,7 +63,7 @@ static usec_t get_startup_time(Context *c) {
&error,
't', &t);
if (r < 0) {
- log_error("Failed to get timestamp: %s", bus_error_message(&error, -r));
+ log_error_errno(r, "Failed to get timestamp: %s", bus_error_message(&error, r));
return 0;
}
@@ -105,10 +106,8 @@ static int get_current_runlevel(Context *c) {
"ActiveState",
&error,
&state);
- if (r < 0) {
- log_warning("Failed to get state: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r));
if (streq(state, "active") || streq(state, "reloading"))
return table[i].runlevel;
@@ -130,8 +129,7 @@ static int on_reboot(Context *c) {
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -160,8 +158,7 @@ static int on_shutdown(Context *c) {
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -211,8 +208,7 @@ static int on_runlevel(Context *c) {
return log_oom();
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM)
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -256,7 +252,7 @@ int main(int argc, char *argv[]) {
if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
log_error_errno(errno, "Failed to connect to audit log: %m");
#endif
- r = bus_open_system_systemd(&c.bus);
+ r = bus_connect_system_systemd(&c.bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
@@ -284,6 +280,6 @@ finish:
audit_close(c.audit_fd);
#endif
- sd_bus_unref(c.bus);
+ sd_bus_flush_close_unref(c.bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c
index 7c736c44d2..252cbdb26c 100644
--- a/src/user-sessions/user-sessions.c
+++ b/src/user-sessions/user-sessions.c
@@ -19,12 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
+#include <unistd.h>
+#include "fileio.h"
#include "log.h"
+#include "string-util.h"
#include "util.h"
-#include "fileio.h"
int main(int argc, char*argv[]) {
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 6353579283..a5f4529cfd 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -19,25 +19,30 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
-#include <stdbool.h>
#include <limits.h>
-#include <sys/ioctl.h>
-#include <linux/tiocl.h>
#include <linux/kd.h>
+#include <linux/tiocl.h>
#include <linux/vt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
-#include "util.h"
-#include "log.h"
-#include "virt.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "io-util.h"
+#include "locale-util.h"
+#include "log.h"
#include "process-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+#include "util.h"
+#include "virt.h"
static bool is_vconsole(int fd) {
unsigned char data[1];
@@ -270,7 +275,7 @@ int main(int argc, char **argv) {
fd = open_terminal(vc, O_RDWR|O_CLOEXEC);
if (fd < 0) {
- log_error_errno(errno, "Failed to open %s: %m", vc);
+ log_error_errno(fd, "Failed to open %s: %m", vc);
return EXIT_FAILURE;
}